Compare commits

..

37 Commits
v2.8.3 ... v2.8

Author SHA1 Message Date
Ludovic Fernandez
3812e6f3cb Prepare release v2.8.8 2022-09-30 12:03:03 +02:00
John Pekcan
627175694d Fix autoDiscoverClusters option documentation for ECS provider 2022-09-30 10:57:48 +02:00
Boris HUISGEN
82cf6c9577 Fix watch option description for Docker provider 2022-09-30 10:50:09 +02:00
tspearconquest
63a1186d3e Update golang.org/x/net to latest version 2022-09-30 10:22:10 +02:00
Skyler Mäntysaari
f75f636e27 Improve documentation for publishedService and IP options 2022-09-29 10:14:08 +02:00
Ludovic Fernandez
615dc7fd35 Prepare release v2.8.7 2022-09-23 16:22:38 +02:00
Kevin Pollet
7758880f3f Prepare release v2.8.6 2022-09-23 15:24:15 +02:00
Ludovic Fernandez
d04903edb2 fix: query parameter matching with equal 2022-09-23 15:12:29 +02:00
Julien Salleyron
9cd54baca4 Optimize websocket headers handling
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
2022-09-22 10:00:09 +02:00
Ludovic Fernandez
7ac687a0a9 providers: simplify AddServer algorithms 2022-09-21 14:54:08 +02:00
t3hchipmunk
83ae1021f6 fix: UDP loadbalancer tags not being used with Consul Catalog 2022-09-21 14:30:09 +02:00
Romain
67e3bc6380 Add documentation for ECS constraints option 2022-09-20 12:22:08 +02:00
Ludovic Fernandez
89870ad539 docs: fix link to RouteNamespaces 2022-09-19 11:26:08 +02:00
NEwa-05
a4b447256b Add a note on case insensitive regex matching 2022-09-16 12:16:09 +02:00
Romain
1c9a7b8c61 Add documentation for json schema usage to validate config in the FAQ
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
2022-09-16 09:54:09 +02:00
Ludovic Fernandez
d06573de6c plugins: allow empty config 2022-09-15 11:00:09 +02:00
Romain
8ddc37d528 Prepare release v2.8.5 2022-09-13 17:13:58 +02:00
Kevin Pollet
0cb2652f51 Update Yaegi to v0.14.2 2022-09-13 15:44:08 +02:00
Fernandez Ludovic
fe8e7ab5b8 docs: update Docker Swarm link 2022-09-12 23:13:11 +02:00
Fernandez Ludovic
56a1ed4220 docs: update Docker Swarm Load Balancer link 2022-09-10 01:18:29 +02:00
Dylan Rodgers
37b6edb28c Added resources for businesses 2022-09-09 17:17:53 +02:00
Antoine
44a2b85dba Display default TLS options in the dashboard 2022-09-09 12:46:09 +02:00
MoonLightWatch
77c8d60092 fix: IPv6 addr in square brackets 2022-09-09 10:44:07 +02:00
Nicolas Mengin
b33c8cec0b Update deprecation notes about Pilot 2022-09-08 11:22:08 +02:00
Marco Lecheler
12dccc4fdd doc: add healthcheck timeout seconds to value 2022-09-05 17:22:08 +02:00
Romain
32e44816c9 Prepare release v2.8.4 2022-09-02 16:38:08 +02:00
Nicolas Mengin
23c74c9f2e Update deprecation notes about Pilot 2022-09-02 16:00:09 +02:00
Johannes Ballmann
9a82d96e68 Add missing networking apiGroup in Kubernetes RBACs examples and references 2022-09-02 12:18:08 +02:00
Ludovic Fernandez
d9589878fb fix: allow starting Traefik even if plugin services have an issue 2022-09-02 11:44:08 +02:00
Romain
d3e4d56a0d Fix Docker provider mem leak on operation retries
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
2022-08-31 18:04:08 +02:00
Ludovic Fernandez
adf82d72ae chore: update linter 2022-08-31 08:24:08 +02:00
Ludovic Fernandez
25027d6df8 fix: don't retry on panic 2022-08-29 11:36:08 +02:00
cui fliter
e56dfeb7d5 fix a typo 2022-08-29 09:24:07 +02:00
Ludovic Fernandez
5ca7fff7f6 doc: fix infobloc documentation 2022-08-25 10:34:09 +02:00
Ben Krieger
dfa1f3fc00 Fix k8s for example for rootCAs serversTransport 2022-08-24 16:16:08 +02:00
Tom Moulard
b26c45af2b chore: update paerser to v0.1.9 2022-08-19 15:58:08 +02:00
Tom Moulard
9c02612f65 Update codegen docker image to golang:1.19 2022-08-18 11:24:08 +02:00
89 changed files with 738 additions and 462 deletions

View File

@@ -7,7 +7,7 @@ on:
env:
GO_VERSION: 1.19
GOLANGCI_LINT_VERSION: v1.48.0
GOLANGCI_LINT_VERSION: v1.49.0
MISSSPELL_VERSION: v0.3.4
IN_DOCKER: ""

View File

@@ -119,7 +119,12 @@
"interfacer", # Deprecated
"maligned", # Deprecated
"golint", # Deprecated
"exhaustivestruct",# Deprecated
"nosnakecase", # Deprecated
"ifshort", # Deprecated
"structcheck", # Deprecated
"varcheck", # Deprecated
"deadcode", # Deprecated
"execinquery", # Not relevant (SQL)
"sqlclosecheck", # Not relevant (SQL)
"rowserrcheck", # Not relevant (SQL)
@@ -130,7 +135,6 @@
"nestif", # Too many false-positive.
"prealloc", # Too many false-positive.
"makezero", # Not relevant
"ifshort", # Not relevant
"dupl", # Too strict
"gosec", # Too strict
"gochecknoinits",
@@ -143,14 +147,11 @@
"tparallel", # Not relevant
"paralleltest", # Not relevant
"exhaustive", # Not relevant
"exhaustivestruct", # Not relevant
"exhaustruct", # duplicate of exhaustivestruct
"goerr113", # Too strict
"wrapcheck", # Too strict
"noctx", # Too strict
"bodyclose", # Too many false-positive and panics.
"unparam", # Too strict
"godox", # Too strict
"forcetypeassert", # Too strict
"tagliatelle", # Not compatible with current tags.
"varnamelen", # not relevant
@@ -160,7 +161,6 @@
"containedctx", # too many false-positive
"maintidx", # kind of duplicate of gocyclo
"nonamedreturns", # not relevant
"structcheck", # duplicate of unused
]
[issues]
@@ -182,6 +182,10 @@
[[issues.exclude-rules]]
path = "(.+)_test.go"
linters = ["goconst", "funlen", "godot", "nosnakecase"]
[[issues.exclude-rules]]
path = "(.+)_test.go"
text = " always receives "
linters = [ "unparam" ]
[[issues.exclude-rules]]
path = "integration/.+_test.go"
text = "Error return value of `cmd\\.Process\\.Kill` is not checked"
@@ -230,4 +234,13 @@
[[issues.exclude-rules]]
path = "pkg/types/tls_test.go"
text = "SA1019: tlsConfig.RootCAs.Subjects has been deprecated since Go 1.18"
[[issues.exclude-rules]]
path = "pkg/provider/kubernetes/(crd|gateway)/client.go"
linters = ["interfacebloat"]
[[issues.exclude-rules]]
path = "pkg/metrics/metrics.go"
linters = ["interfacebloat"]
[[issues.exclude-rules]]
path = "pkg/provider/acme/provider.go"
text = "\\(\\*Provider\\)\\.resolveCertificate - result 0 \\(\\*github.com/go-acme/lego/v4/certificate.Resource\\) is never used"

View File

@@ -40,6 +40,8 @@ builds:
goarch: arm64
- goos: freebsd
goarch: arm64
- goos: windows
goarch: arm
changelog:
skip: true

View File

@@ -25,7 +25,7 @@ global_job_config:
- export "PATH=${GOPATH}/bin:${PATH}"
- mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin"
- 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.48.0
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.49.0
- curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
- checkout
- cache restore traefik-$(checksum go.sum)

View File

@@ -1,3 +1,64 @@
## [v2.8.8](https://github.com/traefik/traefik/tree/v2.8.8) (2022-09-30)
[All Commits](https://github.com/traefik/traefik/compare/v2.8.7...v2.8.8)
**Bug fixes:**
- **[server]** Update golang.org/x/net to latest version ([#9398](https://github.com/traefik/traefik/pull/9398) by [tspearconquest](https://github.com/tspearconquest))
**Documentation:**
- **[docker]** Fix watch option description for Docker provider ([#9391](https://github.com/traefik/traefik/pull/9391) by [bhuisgen](https://github.com/bhuisgen))
- **[ecs]** Fix autoDiscoverClusters option documentation for ECS provider ([#9392](https://github.com/traefik/traefik/pull/9392) by [johnpekcan](https://github.com/johnpekcan))
- **[k8s]** Improve documentation for publishedService and IP options ([#9380](https://github.com/traefik/traefik/pull/9380) by [samip5](https://github.com/samip5))
## [v2.8.7](https://github.com/traefik/traefik/tree/v2.8.7) (2022-09-23)
[All Commits](https://github.com/traefik/traefik/compare/v2.8.5...v2.8.7)
**Bug fixes:**
- **[consulcatalog]** Fix UDP loadbalancer tags not being used with Consul Catalog ([#9357](https://github.com/traefik/traefik/pull/9357) by [t3hchipmunk](https://github.com/t3hchipmunk))
- **[docker,rancher,ecs,provider]** Simplify AddServer algorithm ([#9358](https://github.com/traefik/traefik/pull/9358) by [ldez](https://github.com/ldez))
- **[plugins]** Allow empty plugin configuration ([#9338](https://github.com/traefik/traefik/pull/9338) by [ldez](https://github.com/ldez))
- **[rules]** Fix query parameter matching with equal ([#9369](https://github.com/traefik/traefik/pull/9369) by [ldez](https://github.com/ldez))
- **[server]** Optimize websocket headers handling ([#9360](https://github.com/traefik/traefik/pull/9360) by [juliens](https://github.com/juliens))
**Documentation:**
- **[ecs]** Add documentation for ECS constraints option ([#9354](https://github.com/traefik/traefik/pull/9354) by [rtribotte](https://github.com/rtribotte))
- **[k8s/gatewayapi]** Fix link to RouteNamespaces ([#9349](https://github.com/traefik/traefik/pull/9349) by [ldez](https://github.com/ldez))
- Add documentation for json schema usage to validate config in the FAQ ([#9340](https://github.com/traefik/traefik/pull/9340) by [rtribotte](https://github.com/rtribotte))
- Add a note on case insensitive regex matching ([#9322](https://github.com/traefik/traefik/pull/9322) by [NEwa-05](https://github.com/NEwa-05))
## [v2.8.6](https://github.com/traefik/traefik/tree/v2.8.6) (2022-09-23)
[All Commits](https://github.com/traefik/traefik/compare/v2.8.5...v2.8.6)
Release canceled.
## [v2.8.5](https://github.com/traefik/traefik/tree/v2.8.5) (2022-09-13)
[All Commits](https://github.com/traefik/traefik/compare/v2.8.4...v2.8.5)
**Bug fixes:**
- **[plugins]** Update Yaegi to v0.14.2 ([#9327](https://github.com/traefik/traefik/pull/9327) by [kevinpollet](https://github.com/kevinpollet))
- **[server]** Fix IPv6 addr with square brackets ([#9313](https://github.com/traefik/traefik/pull/9313) by [moonlightwatch](https://github.com/moonlightwatch))
- **[webui,api]** Display default TLS options in the dashboard ([#9312](https://github.com/traefik/traefik/pull/9312) by [skwair](https://github.com/skwair))
**Documentation:**
- **[docker]** Add healthcheck timeout seconds to value ([#9306](https://github.com/traefik/traefik/pull/9306) by [fty4](https://github.com/fty4))
- Update deprecation notes about Pilot ([#9314](https://github.com/traefik/traefik/pull/9314) by [nmengin](https://github.com/nmengin))
- Added resources for businesses ([#9268](https://github.com/traefik/traefik/pull/9268) by [tomatokoolaid](https://github.com/tomatokoolaid))
## [v2.8.4](https://github.com/traefik/traefik/tree/v2.8.4) (2022-09-02)
[All Commits](https://github.com/traefik/traefik/compare/v2.8.3...v2.8.4)
**Bug fixes:**
- **[docker,docker/swarm]** Fix Docker provider mem leak on operation retries ([#9288](https://github.com/traefik/traefik/pull/9288) by [rtribotte](https://github.com/rtribotte))
- **[middleware]** Fix retry middleware on panic ([#9284](https://github.com/traefik/traefik/pull/9284) by [ldez](https://github.com/ldez))
- **[plugins]** Allow Traefik starting even if plugin service is unavailable ([#9287](https://github.com/traefik/traefik/pull/9287) by [ldez](https://github.com/ldez))
- chore: update paerser to v0.1.9 ([#9270](https://github.com/traefik/traefik/pull/9270) by [tomMoulard](https://github.com/tomMoulard))
**Documentation:**
- **[acme]** Fix infoblox acme provider documentation ([#9277](https://github.com/traefik/traefik/pull/9277) by [ldez](https://github.com/ldez))
- **[k8s/crd]** Fix serversTransport CRD documentation ([#9283](https://github.com/traefik/traefik/pull/9283) by [cuishuang](https://github.com/cuishuang))
- **[k8s/crd]** Fix k8s for example for rootCAs serversTransport ([#9274](https://github.com/traefik/traefik/pull/9274) by [ben-krieger](https://github.com/ben-krieger))
- **[k8s]** Add missing networking apiGroup in Kubernetes RBACs examples and references ([#9295](https://github.com/traefik/traefik/pull/9295) by [fibsifan](https://github.com/fibsifan))
- Update deprecation notes about Pilot ([#9300](https://github.com/traefik/traefik/pull/9300) by [nmengin](https://github.com/nmengin))
## [v2.8.3](https://github.com/traefik/traefik/tree/v2.8.3) (2022-08-12)
[All Commits](https://github.com/traefik/traefik/compare/v2.8.2...v2.8.3)
@@ -6199,5 +6260,3 @@ Same changelog as v2.0.3.
- Fix travis tag check [\#422](https://github.com/traefik/traefik/pull/422) ([emilevauge](https://github.com/emilevauge))
- log info about TOML configuration file using [\#420](https://github.com/traefik/traefik/pull/420) ([cocap10](https://github.com/cocap10))
- Doc about skipping some integration tests with '-check.f ConsulCatalogSuite' [\#418](https://github.com/traefik/traefik/pull/418) ([samber](https://github.com/samber))
\* *This Change Log was automatically generated by [gcg](https://github.com/ldez/gcg)*

View File

@@ -13,7 +13,7 @@ RUN mkdir -p /usr/local/bin \
| tar -xzC /usr/local/bin --transform 's#^.+/##x'
# Download golangci-lint binary to bin folder in $GOPATH
RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.48.0
RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOPATH/bin v1.49.0
# Download misspell binary to bin folder in $GOPATH
RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4

View File

@@ -64,7 +64,7 @@ func Do(staticConfiguration static.Configuration) (*http.Response, error) {
client := &http.Client{Timeout: 5 * time.Second}
protocol := "http"
// FIXME Handle TLS on ping etc...
// TODO Handle TLS on ping etc...
// if pingEntryPoint.TLS != nil {
// protocol = "https"
// tr := &http.Transport{

View File

@@ -72,22 +72,16 @@ func NewCentrifuge(rootPkg string) (*Centrifuge, error) {
// Run runs the code extraction and the code generation.
func (c Centrifuge) Run(dest string, pkgName string) error {
files, err := c.run(c.pkg.Scope(), c.rootPkg, pkgName)
if err != nil {
return err
}
files := c.run(c.pkg.Scope(), c.rootPkg, pkgName)
err = fileWriter{baseDir: dest}.Write(files)
err := fileWriter{baseDir: dest}.Write(files)
if err != nil {
return err
}
for _, p := range c.pkg.Imports() {
if contains(c.IncludedImports, p.Path()) {
fls, err := c.run(p.Scope(), p.Path(), p.Name())
if err != nil {
return err
}
fls := c.run(p.Scope(), p.Path(), p.Name())
err = fileWriter{baseDir: filepath.Join(dest, p.Name())}.Write(fls)
if err != nil {
@@ -99,7 +93,7 @@ func (c Centrifuge) Run(dest string, pkgName string) error {
return err
}
func (c Centrifuge) run(sc *types.Scope, rootPkg string, pkgName string) (map[string]*File, error) {
func (c Centrifuge) run(sc *types.Scope, rootPkg string, pkgName string) map[string]*File {
files := map[string]*File{}
for _, name := range sc.Names() {
@@ -158,7 +152,7 @@ func (c Centrifuge) run(sc *types.Scope, rootPkg string, pkgName string) (map[st
}
}
return files, nil
return files
}
func (c Centrifuge) writeStruct(name string, obj *types.Struct, rootPkg string, elt *File) string {

View File

@@ -223,12 +223,16 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
pluginBuilder, err := createPluginBuilder(staticConfiguration)
if err != nil {
return nil, err
log.WithoutContext().WithError(err).Error("Plugins are disabled because an error has occurred.")
}
// Providers plugins
for name, conf := range staticConfiguration.Providers.Plugin {
if pluginBuilder == nil {
break
}
p, err := pluginBuilder.BuildProvider(name, conf)
if err != nil {
return nil, fmt.Errorf("plugin: failed to build provider: %w", err)

View File

@@ -13,12 +13,12 @@ This page is maintained and updated periodically to reflect our roadmap and any
### Pilot Dashboard (Metrics)
Metrics will continue to function normally up to 2.8, when they will be disabled.
In 2.9, the Pilot platform and all Traefik integration code will be permanently removed.
In 3.0, the Pilot platform and all Traefik integration code will be permanently removed.
### Pilot Plugins
Starting on 2.7 the pilot token will not be a requirement anymore.
At 2.9, a new plugin catalog home should be available, decoupled from pilot.
Since 2.8, a [new plugin catalog](https://plugins.traefik.io) is available, decoupled from pilot.
### Consul Enterprise Namespace

View File

@@ -39,3 +39,5 @@ You no longer need to create and synchronize configuration files cluttered with
!!! question "How does Traefik discover the services?"
Traefik is able to use your cluster API to discover the services and read the attached information. In Traefik, these connectors are called [providers](../providers/overview.md) because they _provide_ the configuration to Traefik. To learn more about them, read the [provider overview](../providers/overview.md) section.
{!traefik-for-business-applications.md!}

View File

@@ -94,17 +94,4 @@ All the configuration options are documented in their related section.
You can browse the available features in the menu, the [providers](../providers/overview.md), or the [routing section](../routing/overview.md) to see them in action.
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -157,3 +157,27 @@ By default, the following headers are automatically added when proxying requests
For more details,
please check out the [forwarded header](../routing/entrypoints.md#forwarded-headers) documentation.
## What does the "field not found" error mean?
```shell
error: field not found, node: -badField-
```
The "field not found" error occurs, when an unknown property is encountered in the dynamic or static configuration.
One easy way to check whether a configuration file is well-formed, is to validate it with:
- [JSON Schema of the static configuration](https://json.schemastore.org/traefik-v2.json)
- [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json)
## Why are some resources (routers, middlewares, services...) not created/applied?
As a common tip, if a resource is dropped/not created by Traefik after the dynamic configuration was evaluated,
one should look for an error in the logs.
If found, the error obviously confirms that something went wrong while creating the resource,
and the message should help in figuring out the mistake(s) in the configuration, and how to fix it.
When using the file provider,
one easy way to check if the dynamic configuration is well-formed is to validate it with the [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json).

View File

@@ -179,17 +179,4 @@ And run it:
All the details are available in the [Contributing Guide](../contributing/building-testing.md)
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -53,6 +53,7 @@ rules:
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:

View File

@@ -116,17 +116,4 @@ IP: 172.27.0.4
Now that you have a basic understanding of how Traefik can automatically create the routes to your services and load balance them, it is time to dive into [the documentation](/) and let Traefik work for you!
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -342,7 +342,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [IBM Cloud (SoftLayer)](https://www.ibm.com/cloud/) | `ibmcloud` | `SOFTLAYER_USERNAME`, `SOFTLAYER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ibmcloud) |
| [IIJ DNS Platform Service](https://www.iij.ad.jp) | `iijdpf` | `IIJ_DPF_API_TOKEN` , `IIJ_DPF_DPM_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iijdpf) |
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iij) |
| [Infoblox](https://www.infoblox.com/) | `infoblox` | `INFOBLOX_USER`, `INFOBLOX_PASSWORD`, `INFOBLOX_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/infoblox) |
| [Infoblox](https://www.infoblox.com/) | `infoblox` | `INFOBLOX_USERNAME`, `INFOBLOX_PASSWORD`, `INFOBLOX_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/infoblox) |
| [Infomaniak](https://www.infomaniak.com) | `infomaniak` | `INFOMANIAK_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/infomaniak) |
| [Internet.bs](https://internetbs.net) | `internetbs` | `INTERNET_BS_API_KEY`, `INTERNET_BS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/internetbs) |
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) |
@@ -661,23 +661,10 @@ certificatesResolvers:
If Let's Encrypt is not reachable, the following certificates will apply:
1. Previously generated ACME certificates (before downtime)
1. Expired ACME certificates
1. Provided certificates
2. Expired ACME certificates
3. Provided certificates
!!! important
For new (sub)domains which need Let's Encrypt authentication, the default Traefik certificate will be used until Traefik is restarted.
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -19,3 +19,5 @@ The next sections of this documentation explain how to configure the TLS connect
That is to say, how to obtain [TLS certificates](./tls.md#certificates-definition):
either through a definition in the dynamic configuration, or through [Let's Encrypt](./acme.md) (ACME).
And how to configure [TLS options](./tls.md#tls-options), and [certificates stores](./tls.md#certificates-stores).
{!traefik-for-business-applications.md!}

View File

@@ -490,3 +490,5 @@ spec:
- secretCA
clientAuthType: RequireAndVerifyClientCert
```
{!traefik-for-business-applications.md!}

View File

@@ -0,0 +1,4 @@
{
"extends": "../../.markdownlint.json",
"MD041": false
}

View File

@@ -0,0 +1,16 @@
---
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Docker Swarm Ingress Controller](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).

View File

@@ -469,3 +469,5 @@ The `permissionsPolicy` allows sites to control browser features.
Set `isDevelopment` to `true` when developing to mitigate the unwanted effects of the `AllowedHosts`, SSL, and STS options.
Usually testing takes place using HTTP, not HTTPS, and on `localhost`, not your production domain.
If you would like your development environment to mimic production with complete Host blocking, SSL redirects, and STS headers, leave this as `false`.
{!traefik-for-business-applications.md!}

View File

@@ -157,3 +157,5 @@ http:
## Community Middlewares
Please take a look at the community-contributed plugins in the [plugin catalog](https://pilot.traefik.io/plugins).
{!traefik-for-business-applications.md!}

View File

@@ -129,3 +129,5 @@ http:
A list of HTTP middlewares can be found [here](http/overview.md).
A list of TCP middlewares can be found [here](tcp/overview.md).
{!traefik-for-business-applications.md!}

View File

@@ -50,6 +50,7 @@ rules:
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
verbs:
@@ -58,6 +59,7 @@ rules:
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
@@ -147,6 +149,7 @@ rules:
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
verbs:
@@ -155,6 +158,7 @@ rules:
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
@@ -441,7 +445,7 @@ To enable HTTP/3 on an EntryPoint, please check out the [HTTP/3 configuration](.
### Kubernetes Gateway API Provider
In `v2.6`, the [Kubernetes Gateway API provider](../providers/kubernetes-gateway.md) now only supports the version [v1alpha2](https://gateway-api.sigs.k8s.io/v1alpha2/guides/getting-started/) of the specification and
[route namespaces](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.RouteNamespaces) selectors, which requires Traefik to fetch and watch the cluster namespaces.
[route namespaces](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.RouteNamespaces) selectors, which requires Traefik to fetch and watch the cluster namespaces.
Therefore, the [RBAC](../reference/dynamic-configuration/kubernetes-gateway.md#rbac) and [CRD](../reference/dynamic-configuration/kubernetes-gateway.md#definitions) definitions must be updated.
## v2.6.0 to v2.6.1

View File

@@ -128,3 +128,5 @@ api:
You can now access the dashboard on the port `8080` of the Traefik instance,
at the following URL: `http://<Traefik IP>:8080/dashboard/` (trailing slash is mandatory).
{!traefik-for-business-applications.md!}

View File

@@ -531,7 +531,7 @@ providers:
_Optional, Default=true_
Watch Docker Swarm events.
Watch Docker events.
```yaml tab="File (YAML)"
providers:
@@ -715,17 +715,4 @@ providers:
--providers.docker.tls.insecureSkipVerify=true
```
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -65,7 +65,7 @@ _Optional, Default=false_
Search for services in cluster list.
- If set to `true` service discovery is disabled on configured clusters, but enabled for all other clusters.
- If set to `true` service discovery is enabled for all clusters.
- If set to `false` service discovery is enabled on configured clusters only.
```yaml tab="File (YAML)"
@@ -91,6 +91,7 @@ providers:
_Optional, Default=["default"]_
Search for services in cluster list.
This option is ignored if `autoDiscoverClusters` is set to `true`.
```yaml tab="File (YAML)"
providers:
@@ -137,6 +138,70 @@ providers:
# ...
```
### `constraints`
_Optional, Default=""_
The `constraints` option can be set to an expression that Traefik matches against the container labels (task),
to determine whether to create any route for that container.
If none of the container labels match the expression, no route for that container is created.
If the expression is empty, all detected containers are included.
The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions,
as well as the usual boolean logic, as shown in examples below.
??? example "Constraints Expression Examples"
```toml
# Includes only containers having a label with key `a.label.name` and value `foo`
constraints = "Label(`a.label.name`, `foo`)"
```
```toml
# Excludes containers having any label with key `a.label.name` and value `foo`
constraints = "!Label(`a.label.name`, `value`)"
```
```toml
# With logical AND.
constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)"
```
```toml
# With logical OR.
constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)"
```
```toml
# With logical AND and OR, with precedence set by parentheses.
constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))"
```
```toml
# Includes only containers having a label with key `a.label.name` and a value matching the `a.+` regular expression.
constraints = "LabelRegex(`a.label.name`, `a.+`)"
```
For additional information, refer to [Restrict the Scope of Service Discovery](./overview.md#restrict-the-scope-of-service-discovery).
```yaml tab="File (YAML)"
providers:
ecs:
constraints: "Label(`a.label.name`,`foo`)"
# ...
```
```toml tab="File (TOML)"
[providers.ecs]
constraints = "Label(`a.label.name`,`foo`)"
# ...
```
```bash tab="CLI"
--providers.ecs.constraints=Label(`a.label.name`,`foo`)
# ...
```
### `defaultRule`
_Optional, Default=```Host(`{{ normalize .Name }}`)```_

View File

@@ -291,3 +291,5 @@ To illustrate, it is possible to easily define multiple routers, services, and T
# ...
{{ end }}
```
{!traefik-for-business-applications.md!}

View File

@@ -344,3 +344,5 @@ providers:
## Full Example
For additional information, refer to the [full example](../user-guides/crd-acme/index.md) with Let's Encrypt.
{!traefik-for-business-applications.md!}

View File

@@ -374,7 +374,7 @@ providers:
_Optional, Default: ""_
IP used for Kubernetes Ingress endpoints.
This IP will get copied to Ingress `status.loadbalancer.ip`, and currently only supports one IP value (IPv4 or IPv6).
```yaml tab="File (YAML)"
providers:
@@ -398,7 +398,9 @@ providers:
_Optional, Default: ""_
Published Kubernetes Service to copy status from.
The Kubernetes service to copy status from.
When using third parties tools like External-DNS, this option can be used to copy the service `loadbalancer.status` (containing the service's endpoints IPs) to the ingresses.
Format: `namespace/servicename`.
```yaml tab="File (YAML)"
@@ -502,17 +504,4 @@ providers:
To learn more about the various aspects of the Ingress specification that Traefik supports,
many examples of Ingresses definitions are located in the test [examples](https://github.com/traefik/traefik/tree/v2.8/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -213,6 +213,7 @@ you can do so in two different ways:
List of providers that support these features:
- [Docker](./docker.md#exposedbydefault)
- [ECS](./ecs.md#exposedbydefault)
- [Consul Catalog](./consul-catalog.md#exposedbydefault)
- [Nomad](./nomad.md#exposedbydefault)
- [Rancher](./rancher.md#exposedbydefault)
@@ -223,6 +224,7 @@ List of providers that support these features:
List of providers that support constraints:
- [Docker](./docker.md#constraints)
- [ECS](./ecs.md#constraints)
- [Consul Catalog](./consul-catalog.md#constraints)
- [Nomad](./nomad.md#constraints)
- [Rancher](./rancher.md#constraints)
@@ -230,3 +232,5 @@ List of providers that support constraints:
- [Kubernetes CRD](./kubernetes-crd.md#labelselector)
- [Kubernetes Ingress](./kubernetes-ingress.md#labelselector)
- [Kubernetes Gateway](./kubernetes-gateway.md#labelselector)
{!traefik-for-business-applications.md!}

View File

@@ -26,6 +26,7 @@ rules:
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:

View File

@@ -562,7 +562,7 @@ TLS key
Use the ip address from the bound port, rather than from the inner network. (Default: ```false```)
`--providers.docker.watch`:
Watch Docker Swarm events. (Default: ```true```)
Watch Docker events. (Default: ```true```)
`--providers.ecs`:
Enable AWS ECS backend with default settings. (Default: ```false```)

View File

@@ -562,7 +562,7 @@ TLS key
Use the ip address from the bound port, rather than from the inner network. (Default: ```false```)
`TRAEFIK_PROVIDERS_DOCKER_WATCH`:
Watch Docker Swarm events. (Default: ```true```)
Watch Docker events. (Default: ```true```)
`TRAEFIK_PROVIDERS_ECS`:
Enable AWS ECS backend with default settings. (Default: ```false```)

View File

@@ -968,17 +968,4 @@ entrypoints.foo.address=:8000/udp
entrypoints.foo.udp.timeout=10s
```
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -406,3 +406,5 @@ serversTransport:
## Static configuration
--serversTransport.forwardingTimeouts.idleConnTimeout=1s
```
{!traefik-for-business-applications.md!}

View File

@@ -360,7 +360,7 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
See [health check](../services/index.md#health-check) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10"
- "traefik.http.services.myservice.loadbalancer.healthcheck.timeout=10s"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.followredirects`"

View File

@@ -1782,3 +1782,5 @@ If the ServersTransport CRD is defined in another provider the cross-provider fo
## Further
Also see the [full example](../../user-guides/crd-acme/index.md) with Let's Encrypt.
{!traefik-for-business-applications.md!}

View File

@@ -47,6 +47,7 @@ which in turn will create the resulting routers, services, handlers, etc.
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
@@ -438,6 +439,7 @@ This way, any Ingress attached to this Entrypoint will have TLS termination by d
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
@@ -645,6 +647,7 @@ For more options, please refer to the available [annotations](#on-ingress).
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
@@ -944,3 +947,5 @@ This will allow users to create a "default router" that will match all unmatched
to avoid this global ingress from satisfying requests that could match other ingresses.
To do this, use the `traefik.ingress.kubernetes.io/router.priority` annotation (as seen in [Annotations on Ingress](#on-ingress)) on your ingresses accordingly.
{!traefik-for-business-applications.md!}

View File

@@ -233,18 +233,18 @@ If the rule is verified, the router becomes active, calls middlewares, and then
The table below lists all the available matchers:
| Rule | Description |
|------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| ```Headers(`key`, `value`)``` | Check if there is a key `key`defined in the headers, with the value `value` |
| ```HeadersRegexp(`key`, `regexp`)``` | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` |
| ```Host(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. |
| ```HostHeader(`example.com`, ...)``` | Same as `Host`, only exists for historical reasons. |
| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)``` | Match the request domain. See "Regexp Syntax" below. |
| ```Method(`GET`, ...)``` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`) |
| ```Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...)``` | Match exact request path. See "Regexp Syntax" below. |
| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`)``` | Match request prefix path. See "Regexp Syntax" below. |
| ```Query(`foo=bar`, `bar=baz`)``` | Match Query String parameters. It accepts a sequence of key=value pairs. |
| ```ClientIP(`10.0.0.0/16`, `::1`)``` | Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats. |
| Rule | Description |
|--------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| ```Headers(`key`, `value`)``` | Check if there is a key `key`defined in the headers, with the value `value` |
| ```HeadersRegexp(`key`, `regexp`)``` | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` |
| ```Host(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. |
| ```HostHeader(`example.com`, ...)``` | Same as `Host`, only exists for historical reasons. |
| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)``` | Match the request domain. See "Regexp Syntax" below. |
| ```Method(`GET`, ...)``` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`) |
| ```Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...)``` | Match exact request path. See "Regexp Syntax" below. |
| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`)``` | Match request prefix path. See "Regexp Syntax" below. |
| ```Query(`foo=bar`, `bar=baz`)``` | Match Query String parameters. It accepts a sequence of key=value pairs. |
| ```ClientIP(`10.0.0.0/16`, `::1`)``` | Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats. |
!!! important "Non-ASCII Domain Names"
@@ -259,6 +259,7 @@ The table below lists all the available matchers:
The regexp name (`name` in the above example) is an arbitrary value, that exists only for historical reasons.
Any `regexp` supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used.
For example, here is a case insensitive path matcher syntax: ```Path(`/{path:(?i:Products)}`)```.
!!! info "Combining Matchers Using Operators and Parenthesis"
@@ -1322,17 +1323,4 @@ Services are the target for the router.
!!! important "UDP routers can only target UDP services (and not HTTP or TCP services)."
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -677,7 +677,7 @@ metadata:
name: myca
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
```
#### `maxIdleConnsPerHost`
@@ -1646,17 +1646,4 @@ udp:
address = "private-ip-server-2:8080/"
```
!!! question "Using Traefik for Business Applications?"
If you are using Traefik for commercial applications,
consider the [Enterprise Edition](https://traefik.io/traefik-enterprise/).
You can use it as your:
- [Kubernetes Ingress Controller](https://traefik.io/solutions/kubernetes-ingress/)
- [Load Balancer](https://traefik.io/solutions/docker-swarm-ingress/)
- [API Gateway](https://traefik.io/solutions/api-gateway/)
Traefik Enterprise enables centralized access management,
distributed Let's Encrypt,
and other advanced capabilities.
Learn more in [this 15-minute technical walkthrough](https://info.traefik.io/watch-traefikee-demo).
{!traefik-for-business-applications.md!}

View File

@@ -93,3 +93,5 @@ whoami:
# Allow request only from the predefined entry point named "web"
- "traefik.http.routers.whoami.entrypoints=web"
```
{!traefik-for-business-applications.md!}

View File

@@ -55,9 +55,9 @@ markdown_extensions:
- pymdownx.tasklist
- pymdownx.snippets:
check_paths: true
# - markdown_include.include:
# base_path: content/includes/
# encoding: utf-8
- markdown_include.include:
base_path: content/includes/
encoding: utf-8
- toc:
permalink: true

8
go.mod
View File

@@ -55,8 +55,8 @@ require (
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.8.0
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
github.com/traefik/paerser v0.1.8
github.com/traefik/yaegi v0.14.1
github.com/traefik/paerser v0.1.9
github.com/traefik/yaegi v0.14.2
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/uber/jaeger-lib v2.2.0+incompatible
github.com/unrolled/render v1.0.2
@@ -67,7 +67,7 @@ require (
go.elastic.co/apm v1.13.1
go.elastic.co/apm/module/apmot v1.13.1
golang.org/x/mod v0.4.2
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
golang.org/x/net v0.0.0-20220927171203-f486391704dc
golang.org/x/text v0.3.7
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2
@@ -313,7 +313,7 @@ require (
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e // indirect
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.44.0 // indirect

15
go.sum
View File

@@ -1903,10 +1903,10 @@ github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305 h1:y/1cL5AL2oRcfzz8CAHHhR6kDDfIOT0WEyH5k40sccM=
github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305/go.mod h1:gXOLibKqQTRAVuVZ9gX7G9Ykky8ll8yb4slxsEMoY0c=
github.com/traefik/paerser v0.1.8 h1:DmX/v9KwWAFvRr5A/XQzLLfd1BSWgh710q+dZJmjZ+c=
github.com/traefik/paerser v0.1.8/go.mod h1:Dk3Bfz6Zyj13/S8pJyRdx/FNvXlsVRVbtp0UK4ZSiA0=
github.com/traefik/yaegi v0.14.1 h1:t0ssyzeZCWTFGd/JnVuDxH/slMQfYg+2CDD4dLW/rU0=
github.com/traefik/yaegi v0.14.1/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0=
github.com/traefik/paerser v0.1.9 h1:x5hZafOt/yogLvr6upoSOYIAn2nh2GsnLb236MOzd4I=
github.com/traefik/paerser v0.1.9/go.mod h1:Dk3Bfz6Zyj13/S8pJyRdx/FNvXlsVRVbtp0UK4ZSiA0=
github.com/traefik/yaegi v0.14.2 h1:9t9xepIfar6BrYdwJHGc+XRKo6qFoJCl6Z46N3hUtUw=
github.com/traefik/yaegi v0.14.2/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0=
github.com/transip/gotransip/v6 v6.6.1 h1:nsCU1ErZS5G0FeOpgGXc4FsWvBff9GPswSMggsC4564=
github.com/transip/gotransip/v6 v6.6.1/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
@@ -2239,8 +2239,9 @@ golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -2401,8 +2402,8 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e h1:CsOuNlbOuf0mzxJIefr6Q4uAUetRUwZE4qt7VfzP+xo=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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=

View File

@@ -603,7 +603,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels(c *check.C) {
c.Assert(err, checker.IsNil)
req.Host = "my.super.host"
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO validate : run on 80
// Expected a 404 as we did not configure anything
err = try.Request(req, 1500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
@@ -681,7 +681,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
c.Assert(err, checker.IsNil)
req.Host = "whoami"
// FIXME Need to wait for up to 10 seconds (for consul discovery or traefik to boot up ?)
// TODO Need to wait for up to 10 seconds (for consul discovery or traefik to boot up ?)
err = try.Request(req, 10*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("Hostname: whoami2"))
c.Assert(err, checker.IsNil)

View File

@@ -78,7 +78,7 @@ func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
c.Assert(err, checker.IsNil)
req.Host = fmt.Sprintf("simple-%s.docker.localhost", s.composeProject.Name)
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
@@ -147,7 +147,7 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
c.Assert(err, checker.IsNil)
req.Host = "my-super.host"
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
_, err = try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
@@ -155,7 +155,7 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
c.Assert(err, checker.IsNil)
req.Host = "my.super.host"
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
@@ -194,7 +194,7 @@ func (s *DockerSuite) TestDockerContainersWithOneMissingLabels(c *check.C) {
c.Assert(err, checker.IsNil)
req.Host = "my.super.host"
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO validate : run on 80
// Expected a 404 as we did not configure anything
err = try.Request(req, 1500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
@@ -227,7 +227,7 @@ func (s *DockerSuite) TestRestartDockerContainers(c *check.C) {
c.Assert(err, checker.IsNil)
req.Host = "my.super.host"
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)

View File

@@ -5,9 +5,11 @@
Package helloworld is a generated protocol buffer package.
It is generated from these files:
helloworld.proto
It has these top-level messages:
HelloRequest
HelloReply
StreamExampleRequest

View File

@@ -209,14 +209,14 @@ func (s *BaseSuite) traefikCmd(args ...string) (*exec.Cmd, func(*check.C)) {
cmd, out := s.cmdTraefik(args...)
return cmd, func(c *check.C) {
if c.Failed() || *showLog {
s.displayLogK3S(c)
s.displayLogK3S()
s.displayLogCompose(c)
s.displayTraefikLog(c, out)
}
}
}
func (s *BaseSuite) displayLogK3S(c *check.C) {
func (s *BaseSuite) displayLogK3S() {
filePath := "./fixtures/k8s/config.skip/k3s.log"
if _, err := os.Stat(filePath); err == nil {
content, errR := os.ReadFile(filePath)

View File

@@ -135,7 +135,7 @@ type storeWriter struct {
data map[string]string
}
func (f storeWriter) Put(key string, value []byte, options []string) error {
func (f storeWriter) Put(key string, value []byte, _ []string) error {
f.data[key] = string(value)
return nil
}

View File

@@ -11,7 +11,7 @@ import (
)
func init() {
// FIXME Goroutines2 -> Goroutines
// TODO Goroutines2 -> Goroutines
expvar.Publish("Goroutines2", expvar.Func(goroutines))
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/gorilla/mux"
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/tls"
)
type routerRepresentation struct {
@@ -20,6 +21,10 @@ type routerRepresentation struct {
}
func newRouterRepresentation(name string, rt *runtime.RouterInfo) routerRepresentation {
if rt.TLS != nil && rt.TLS.Options == "" {
rt.TLS.Options = tls.DefaultTLSConfigName
}
return routerRepresentation{
RouterInfo: rt,
Name: name,

View File

@@ -223,6 +223,52 @@ func TestHandler_HTTP(t *testing.T) {
jsonFile: "testdata/router-bar.json",
},
},
{
desc: "one router by id, implicitly using default TLS options",
path: "/api/http/routers/baz@myprovider",
conf: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"baz@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.baz`)",
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
TLS: &dynamic.RouterTLSConfig{},
},
Status: "enabled",
},
},
},
expected: expected{
statusCode: http.StatusOK,
jsonFile: "testdata/router-baz-default-tls-options.json",
},
},
{
desc: "one router by id, using specific TLS options",
path: "/api/http/routers/baz@myprovider",
conf: runtime.Configuration{
Routers: map[string]*runtime.RouterInfo{
"baz@myprovider": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service@myprovider",
Rule: "Host(`foo.baz`)",
Middlewares: []string{"auth", "addPrefixTest@anotherprovider"},
TLS: &dynamic.RouterTLSConfig{
Options: "myTLS",
},
},
Status: "enabled",
},
},
},
expected: expected{
statusCode: http.StatusOK,
jsonFile: "testdata/router-baz-custom-tls-options.json",
},
},
{
desc: "one router by id, that does not exist",
path: "/api/http/routers/foo@myprovider",
@@ -811,6 +857,7 @@ func TestHandler_HTTP(t *testing.T) {
// To lazily initialize the Statuses.
rtConf.PopulateUsedBy()
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, false)
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, true)
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
server := httptest.NewServer(handler.createRouter())

View File

@@ -0,0 +1,20 @@
{
"entryPoints": [
"web"
],
"middlewares": [
"auth",
"addPrefixTest@anotherprovider"
],
"name": "baz@myprovider",
"provider": "myprovider",
"rule": "Host(`foo.baz`)",
"service": "foo-service@myprovider",
"tls": {
"options": "myTLS"
},
"status": "enabled",
"using": [
"web"
]
}

View File

@@ -0,0 +1,20 @@
{
"entryPoints": [
"web"
],
"middlewares": [
"auth",
"addPrefixTest@anotherprovider"
],
"name": "baz@myprovider",
"provider": "myprovider",
"rule": "Host(`foo.baz`)",
"service": "foo-service@myprovider",
"tls": {
"options": "default"
},
"status": "enabled",
"using": [
"web"
]
}

View File

@@ -215,9 +215,9 @@ type ServerHealthCheck struct {
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty" export:"true"`
// FIXME change string to ptypes.Duration
// TODO change string to ptypes.Duration
Interval string `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty" export:"true"`
// FIXME change string to ptypes.Duration
// TODO change string to ptypes.Duration
Timeout string `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty" export:"true"`
Hostname string `json:"hostname,omitempty" toml:"hostname,omitempty" yaml:"hostname,omitempty"`
FollowRedirects *bool `json:"followRedirects" toml:"followRedirects" yaml:"followRedirects" export:"true"`

View File

@@ -20,27 +20,32 @@ type Registry interface {
IsSvcEnabled() bool
// server metrics
ConfigReloadsCounter() metrics.Counter
ConfigReloadsFailureCounter() metrics.Counter
LastConfigReloadSuccessGauge() metrics.Gauge
LastConfigReloadFailureGauge() metrics.Gauge
// TLS
TLSCertsNotAfterTimestampGauge() metrics.Gauge
// entry point metrics
EntryPointReqsCounter() metrics.Counter
EntryPointReqsTLSCounter() metrics.Counter
EntryPointReqDurationHistogram() ScalableHistogram
EntryPointOpenConnsGauge() metrics.Gauge
// router metrics
RouterReqsCounter() metrics.Counter
RouterReqsTLSCounter() metrics.Counter
RouterReqDurationHistogram() ScalableHistogram
RouterOpenConnsGauge() metrics.Gauge
// service metrics
ServiceReqsCounter() metrics.Counter
ServiceReqsTLSCounter() metrics.Counter
ServiceReqDurationHistogram() ScalableHistogram

View File

@@ -166,6 +166,8 @@ func containsHeader(req *http.Request, name, value string) bool {
// values that are not part of the set of HTTP verbs are replaced with EXTENSION_METHOD.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
// https://datatracker.ietf.org/doc/html/rfc2616/#section-5.1.1.
//
//nolint:usestdlibvars
func getMethod(r *http.Request) string {
if !utf8.ValidString(r.Method) {
log.WithoutContext().Warnf("Invalid HTTP method encoding: %s", r.Method)

View File

@@ -166,7 +166,7 @@ func (rl *rateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
delay := res.Delay()
if delay > rl.maxDelay {
res.Cancel()
rl.serveDelayError(ctx, w, r, delay)
rl.serveDelayError(ctx, w, delay)
return
}
@@ -174,7 +174,7 @@ func (rl *rateLimiter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rl.next.ServeHTTP(w, r)
}
func (rl *rateLimiter) serveDelayError(ctx context.Context, w http.ResponseWriter, r *http.Request, delay time.Duration) {
func (rl *rateLimiter) serveDelayError(ctx context.Context, w http.ResponseWriter, delay time.Duration) {
w.Header().Set("Retry-After", fmt.Sprintf("%.0f", math.Ceil(delay.Seconds())))
w.Header().Set("X-Retry-In", delay.String())
w.WriteHeader(http.StatusTooManyRequests)

View File

@@ -49,11 +49,16 @@ func (r *RequestDecorator) ServeHTTP(rw http.ResponseWriter, req *http.Request,
func parseHost(addr string) string {
if !strings.Contains(addr, ":") {
// IPv4 without port or empty address
return addr
}
// IPv4 with port or IPv6
host, _, err := net.SplitHostPort(addr)
if err != nil {
if addr[0] == '[' && addr[len(addr)-1] == ']' {
return addr[1 : len(addr)-1]
}
return addr
}
return host

View File

@@ -104,7 +104,7 @@ func TestRequestFlattening(t *testing.T) {
}
}
func TestRequestHostParseHost(t *testing.T) {
func Test_parseHost(t *testing.T) {
testCases := []struct {
desc string
host string
@@ -130,6 +130,46 @@ func TestRequestHostParseHost(t *testing.T) {
host: "127.0.0.1:",
expected: "127.0.0.1",
},
{
desc: "host with : and without port",
host: "fe80::215:5dff:fe20:cd6a",
expected: "fe80::215:5dff:fe20:cd6a",
},
{
desc: "IPv6 host with : and with port",
host: "[fe80::215:5dff:fe20:cd6a]:123",
expected: "fe80::215:5dff:fe20:cd6a",
},
{
desc: "IPv6 host with : and without port",
host: "[fe80::215:5dff:fe20:cd6a]:",
expected: "fe80::215:5dff:fe20:cd6a",
},
{
desc: "IPv6 host without : and without port",
host: "[fe80::215:5dff:fe20:cd6a]",
expected: "fe80::215:5dff:fe20:cd6a",
},
{
desc: "invalid IPv6: missing [",
host: "fe80::215:5dff:fe20:cd6a]",
expected: "fe80::215:5dff:fe20:cd6a]",
},
{
desc: "invalid IPv6: missing ]",
host: "[fe80::215:5dff:fe20:cd6a",
expected: "[fe80::215:5dff:fe20:cd6a",
},
{
desc: "empty address",
host: "",
expected: "",
},
{
desc: "only :",
host: ":",
expected: "",
},
}
for _, test := range testCases {

View File

@@ -16,7 +16,6 @@ import (
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares"
"github.com/traefik/traefik/v2/pkg/safe"
"github.com/traefik/traefik/v2/pkg/tracing"
)
@@ -118,7 +117,7 @@ func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
r.listener.Retried(req, attempts)
}
err := backoff.RetryNotify(safe.OperationWithRecover(operation), backOff, notify)
err := backoff.RetryNotify(operation, backOff, notify)
if err != nil {
log.FromContext(middlewares.GetLoggerCtx(req.Context(), r.name, typeName)).
Debugf("Final retry attempt failed: %v", err.Error())

View File

@@ -237,7 +237,7 @@ func headersRegexp(route *mux.Route, headers ...string) error {
func query(route *mux.Route, query ...string) error {
var queries []string
for _, elem := range query {
queries = append(queries, strings.Split(elem, "=")...)
queries = append(queries, strings.SplitN(elem, "=", 2)...)
}
route.Queries(queries...)

View File

@@ -252,6 +252,14 @@ func Test_addRoute(t *testing.T) {
"http://localhost/foo?bar=baz": http.StatusNotFound,
},
},
{
desc: "Query with multiple equals",
rule: "Query(`foo=b=ar`)",
expected: map[string]int{
"http://localhost/foo?foo=b=ar": http.StatusOK,
"http://localhost/foo?foo=bar": http.StatusNotFound,
},
},
{
desc: "Rule with simple path",
rule: `Path("/a")`,

View File

@@ -164,7 +164,12 @@ func (c *Client) Download(ctx context.Context, pName, pVersion string) (string,
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode == http.StatusOK {
switch resp.StatusCode {
case http.StatusNotModified:
// noop
return hash, nil
case http.StatusOK:
err = os.MkdirAll(filepath.Dir(filename), 0o755)
if err != nil {
return "", fmt.Errorf("failed to create directory: %w", err)
@@ -189,15 +194,11 @@ func (c *Client) Download(ctx context.Context, pName, pVersion string) (string,
}
return hash, nil
}
if resp.StatusCode == http.StatusNotModified {
// noop
return hash, nil
default:
data, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("error: %d: %s", resp.StatusCode, string(data))
}
data, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("error: %d: %s", resp.StatusCode, string(data))
}
// Check checks the plugin archive integrity.

View File

@@ -84,6 +84,9 @@ func (p middlewareBuilder) createConfig(config map[string]interface{}) (reflect.
}
vConfig := results[0]
if len(config) == 0 {
return vConfig, nil
}
cfg := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.StringToSliceHookFunc(","),

View File

@@ -26,7 +26,7 @@ func TestGetUncheckedCertificates(t *testing.T) {
domainSafe := &safe.Safe{}
domainSafe.Set(domainMap)
// FIXME Add a test for DefaultCertificate
// TODO Add a test for DefaultCertificate
testCases := []struct {
desc string
dynamicCerts *safe.Safe

View File

@@ -37,7 +37,7 @@ func (p *Provider) buildConfiguration(ctx context.Context, items []itemData, cer
if len(confFromLabel.TCP.Routers) > 0 || len(confFromLabel.TCP.Services) > 0 {
tcpOrUDP = true
err := p.buildTCPServiceConfiguration(ctxSvc, item, confFromLabel.TCP)
err := p.buildTCPServiceConfiguration(item, confFromLabel.TCP)
if err != nil {
logger.Error(err)
continue
@@ -49,7 +49,7 @@ func (p *Provider) buildConfiguration(ctx context.Context, items []itemData, cer
if len(confFromLabel.UDP.Routers) > 0 || len(confFromLabel.UDP.Services) > 0 {
tcpOrUDP = true
err := p.buildUDPServiceConfiguration(ctxSvc, item, confFromLabel.UDP)
err := p.buildUDPServiceConfiguration(item, confFromLabel.UDP)
if err != nil {
logger.Error(err)
continue
@@ -75,7 +75,7 @@ func (p *Provider) buildConfiguration(ctx context.Context, items []itemData, cer
}
}
err = p.buildServiceConfiguration(ctxSvc, item, confFromLabel.HTTP)
err = p.buildServiceConfiguration(item, confFromLabel.HTTP)
if err != nil {
logger.Error(err)
continue
@@ -128,7 +128,7 @@ func (p *Provider) keepContainer(ctx context.Context, item itemData) bool {
return true
}
func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, item itemData, configuration *dynamic.TCPConfiguration) error {
func (p *Provider) buildTCPServiceConfiguration(item itemData, configuration *dynamic.TCPConfiguration) error {
if len(configuration.Services) == 0 {
configuration.Services = make(map[string]*dynamic.TCPService)
@@ -141,17 +141,16 @@ func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, item itemDa
}
for name, service := range configuration.Services {
ctxSvc := log.With(ctx, log.Str(log.ServiceName, name))
err := p.addServerTCP(ctxSvc, item, service.LoadBalancer)
err := p.addServerTCP(item, service.LoadBalancer)
if err != nil {
return err
return fmt.Errorf("%s: %w", name, err)
}
}
return nil
}
func (p *Provider) buildUDPServiceConfiguration(ctx context.Context, item itemData, configuration *dynamic.UDPConfiguration) error {
func (p *Provider) buildUDPServiceConfiguration(item itemData, configuration *dynamic.UDPConfiguration) error {
if len(configuration.Services) == 0 {
configuration.Services = make(map[string]*dynamic.UDPService)
@@ -163,17 +162,16 @@ func (p *Provider) buildUDPServiceConfiguration(ctx context.Context, item itemDa
}
for name, service := range configuration.Services {
ctxSvc := log.With(ctx, log.Str(log.ServiceName, name))
err := p.addServerUDP(ctxSvc, item, service.LoadBalancer)
err := p.addServerUDP(item, service.LoadBalancer)
if err != nil {
return err
return fmt.Errorf("%s: %w", name, err)
}
}
return nil
}
func (p *Provider) buildServiceConfiguration(ctx context.Context, item itemData, configuration *dynamic.HTTPConfiguration) error {
func (p *Provider) buildServiceConfiguration(item itemData, configuration *dynamic.HTTPConfiguration) error {
if len(configuration.Services) == 0 {
configuration.Services = make(map[string]*dynamic.Service)
@@ -186,48 +184,45 @@ func (p *Provider) buildServiceConfiguration(ctx context.Context, item itemData,
}
for name, service := range configuration.Services {
ctxSvc := log.With(ctx, log.Str(log.ServiceName, name))
err := p.addServer(ctxSvc, item, service.LoadBalancer)
err := p.addServer(item, service.LoadBalancer)
if err != nil {
return err
return fmt.Errorf("%s: %w", name, err)
}
}
return nil
}
func (p *Provider) addServerTCP(ctx context.Context, item itemData, loadBalancer *dynamic.TCPServersLoadBalancer) error {
func (p *Provider) addServerTCP(item itemData, loadBalancer *dynamic.TCPServersLoadBalancer) error {
if loadBalancer == nil {
return errors.New("load-balancer is not defined")
}
var port string
if len(loadBalancer.Servers) > 0 {
port = loadBalancer.Servers[0].Port
}
if len(loadBalancer.Servers) == 0 {
loadBalancer.Servers = []dynamic.TCPServer{{}}
}
if item.Port != "" && port == "" {
if item.Address == "" {
return errors.New("address is missing")
}
port := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if port == "" {
port = item.Port
}
loadBalancer.Servers[0].Port = ""
if port == "" {
return errors.New("port is missing")
}
if item.Address == "" {
return errors.New("address is missing")
}
loadBalancer.Servers[0].Address = net.JoinHostPort(item.Address, port)
return nil
}
func (p *Provider) addServerUDP(ctx context.Context, item itemData, loadBalancer *dynamic.UDPServersLoadBalancer) error {
func (p *Provider) addServerUDP(item itemData, loadBalancer *dynamic.UDPServersLoadBalancer) error {
if loadBalancer == nil {
return errors.New("load-balancer is not defined")
}
@@ -236,34 +231,31 @@ func (p *Provider) addServerUDP(ctx context.Context, item itemData, loadBalancer
loadBalancer.Servers = []dynamic.UDPServer{{}}
}
var port string
if item.Port != "" {
if item.Address == "" {
return errors.New("address is missing")
}
port := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if port == "" {
port = item.Port
loadBalancer.Servers[0].Port = ""
}
if port == "" {
return errors.New("port is missing")
}
if item.Address == "" {
return errors.New("address is missing")
}
loadBalancer.Servers[0].Address = net.JoinHostPort(item.Address, port)
return nil
}
func (p *Provider) addServer(ctx context.Context, item itemData, loadBalancer *dynamic.ServersLoadBalancer) error {
func (p *Provider) addServer(item itemData, loadBalancer *dynamic.ServersLoadBalancer) error {
if loadBalancer == nil {
return errors.New("load-balancer is not defined")
}
var port string
if len(loadBalancer.Servers) > 0 {
port = loadBalancer.Servers[0].Port
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
@@ -271,17 +263,19 @@ func (p *Provider) addServer(ctx context.Context, item itemData, loadBalancer *d
loadBalancer.Servers = []dynamic.Server{server}
}
if item.Port != "" && port == "" {
port = item.Port
if item.Address == "" {
return errors.New("address is missing")
}
port := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if port == "" {
return errors.New("port is missing")
port = item.Port
}
if item.Address == "" {
return errors.New("address is missing")
if port == "" {
return errors.New("port is missing")
}
scheme := loadBalancer.Servers[0].Scheme

View File

@@ -2220,7 +2220,7 @@ func Test_buildConfiguration(t *testing.T) {
Labels: map[string]string{
"traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)",
"traefik.tcp.routers.foo.tls.options": "foo",
"traefik.tcp.services.foo.loadbalancer.server.port": "80",
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
},
Address: "127.0.0.1",
Port: "80",
@@ -2244,7 +2244,7 @@ func Test_buildConfiguration(t *testing.T) {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "127.0.0.1:80",
Address: "127.0.0.1:8080",
},
},
TerminationDelay: Int(100),
@@ -2611,6 +2611,57 @@ func Test_buildConfiguration(t *testing.T) {
},
},
},
{
desc: "UDP service with labels only",
ConnectAware: true,
items: []itemData{
{
ID: "1",
Node: "Node1",
Datacenter: "dc1",
Name: "Test",
Namespace: "ns",
Labels: map[string]string{
"traefik.udp.routers.test-udp-label.service": "test-udp-label-service",
"traefik.udp.routers.test-udp-label.entryPoints": "udp",
"traefik.udp.services.test-udp-label-service.loadBalancer.server.port": "21116",
},
Address: "127.0.0.1",
Port: "80",
Status: api.HealthPassing,
},
},
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"test-udp-label": {
EntryPoints: []string{"udp"},
Service: "test-udp-label-service",
},
},
Services: map[string]*dynamic.UDPService{
"test-udp-label-service": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{
Servers: []dynamic.UDPServer{
{Address: "127.0.0.1:21116"},
},
},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
},
}
for _, test := range testCases {

View File

@@ -187,28 +187,24 @@ func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadB
return errors.New("load-balancer is not defined")
}
var serverPort string
if len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if len(loadBalancer.Servers) == 0 {
loadBalancer.Servers = []dynamic.TCPServer{{}}
}
serverPort := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
ip, port, err := p.getIPPort(ctx, container, serverPort)
if err != nil {
return err
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.TCPServer{}
loadBalancer.Servers = []dynamic.TCPServer{server}
}
if port == "" {
return errors.New("port is missing")
}
loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port)
return nil
}
@@ -217,28 +213,24 @@ func (p *Provider) addServerUDP(ctx context.Context, container dockerData, loadB
return errors.New("load-balancer is not defined")
}
var serverPort string
if len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if len(loadBalancer.Servers) == 0 {
loadBalancer.Servers = []dynamic.UDPServer{{}}
}
serverPort := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
ip, port, err := p.getIPPort(ctx, container, serverPort)
if err != nil {
return err
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.UDPServer{}
loadBalancer.Servers = []dynamic.UDPServer{server}
}
if port == "" {
return errors.New("port is missing")
}
loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port)
return nil
}
@@ -247,17 +239,6 @@ func (p *Provider) addServer(ctx context.Context, container dockerData, loadBala
return errors.New("load-balancer is not defined")
}
var serverPort string
if len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
}
ip, port, err := p.getIPPort(ctx, container, serverPort)
if err != nil {
return err
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
@@ -265,6 +246,14 @@ func (p *Provider) addServer(ctx context.Context, container dockerData, loadBala
loadBalancer.Servers = []dynamic.Server{server}
}
serverPort := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
ip, port, err := p.getIPPort(ctx, container, serverPort)
if err != nil {
return err
}
if port == "" {
return errors.New("port is missing")
}

View File

@@ -49,7 +49,7 @@ var _ provider.Provider = (*Provider)(nil)
// Provider holds configurations of the provider.
type Provider struct {
Constraints string `description:"Constraints is an expression that Traefik matches against the container's labels to determine whether to create any route for that container." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
Watch bool `description:"Watch Docker Swarm events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
Watch bool `description:"Watch Docker events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
Endpoint string `description:"Docker server endpoint. Can be a tcp or a unix socket endpoint." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
TLS *types.ClientTLS `description:"Enable Docker TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
@@ -205,6 +205,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
logger.Errorf("Failed to create a client for docker, error: %s", err)
return err
}
defer dockerClient.Close()
serverVersion, err := dockerClient.ServerVersion(ctx)
if err != nil {
@@ -249,7 +250,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
case <-ticker.C:
services, err := p.listServices(ctx, dockerClient)
if err != nil {
logger.Errorf("Failed to list services for docker, error %s", err)
logger.Errorf("Failed to list services for docker swarm mode, error %s", err)
errChan <- err
return
}

View File

@@ -185,7 +185,7 @@ func (p *Provider) filterInstance(ctx context.Context, instance ecsInstance) boo
matches, err := constraints.MatchLabels(instance.Labels, p.Constraints)
if err != nil {
logger.Errorf("Error matching constraints expression: %v", err)
logger.Errorf("Error matching constraint expression: %v", err)
return false
}
if !matches {
@@ -201,28 +201,24 @@ func (p *Provider) addServerTCP(instance ecsInstance, loadBalancer *dynamic.TCPS
return errors.New("load-balancer is not defined")
}
var serverPort string
if len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if len(loadBalancer.Servers) == 0 {
loadBalancer.Servers = []dynamic.TCPServer{{}}
}
serverPort := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
ip, port, err := p.getIPPort(instance, serverPort)
if err != nil {
return err
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.TCPServer{}
loadBalancer.Servers = []dynamic.TCPServer{server}
}
if port == "" {
return errors.New("port is missing")
}
loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port)
return nil
}
@@ -231,28 +227,24 @@ func (p *Provider) addServerUDP(instance ecsInstance, loadBalancer *dynamic.UDPS
return errors.New("load-balancer is not defined")
}
var serverPort string
if len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if len(loadBalancer.Servers) == 0 {
loadBalancer.Servers = []dynamic.UDPServer{{}}
}
serverPort := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
ip, port, err := p.getIPPort(instance, serverPort)
if err != nil {
return err
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.UDPServer{}
loadBalancer.Servers = []dynamic.UDPServer{server}
}
if port == "" {
return errors.New("port is missing")
}
loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port)
return nil
}
@@ -261,17 +253,6 @@ func (p *Provider) addServer(instance ecsInstance, loadBalancer *dynamic.Servers
return errors.New("load-balancer is not defined")
}
var serverPort string
if len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
}
ip, port, err := p.getIPPort(instance, serverPort)
if err != nil {
return err
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
@@ -279,6 +260,14 @@ func (p *Provider) addServer(instance ecsInstance, loadBalancer *dynamic.Servers
loadBalancer.Servers = []dynamic.Server{server}
}
serverPort := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
ip, port, err := p.getIPPort(instance, serverPort)
if err != nil {
return err
}
if port == "" {
return errors.New("port is missing")
}

View File

@@ -46,7 +46,7 @@ metadata:
data:
ca.crt: VEVTVFJPT1RDQVM0
tls.ca: VEVTVFJPT1RDQVM1 # <-- This should be the prefered one.
tls.ca: VEVTVFJPT1RDQVM1 # <-- This should be the preferred one.
---
apiVersion: v1

View File

@@ -45,14 +45,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:
//
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
//
// kclientset, _ := kubernetes.NewForConfig(c)
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
// kclientset, _ := kubernetes.NewForConfig(c)
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
//
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.

View File

@@ -45,14 +45,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:
//
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
//
// kclientset, _ := kubernetes.NewForConfig(c)
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
// kclientset, _ := kubernetes.NewForConfig(c)
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
//
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.

View File

@@ -97,7 +97,7 @@ func (s *Mock) List(ctx context.Context, prefix string, options *store.ReadOptio
}
var kv []*store.KVPair
for _, kvPair := range s.KVPairs {
if strings.HasPrefix(kvPair.Key, prefix) { // FIXME && !strings.ContainsAny(strings.TrimPrefix(kvPair.Key, prefix), "/") {
if strings.HasPrefix(kvPair.Key, prefix) {
kv = append(kv, kvPair)
}
}

View File

@@ -172,29 +172,27 @@ func (p *Provider) addServerTCP(i item, lb *dynamic.TCPServersLoadBalancer) erro
return errors.New("load-balancer is missing")
}
var port string
if len(lb.Servers) > 0 {
port = lb.Servers[0].Port
}
if len(lb.Servers) == 0 {
lb.Servers = []dynamic.TCPServer{{}}
}
if i.Port != 0 && port == "" {
port = strconv.Itoa(i.Port)
}
lb.Servers[0].Port = ""
if port == "" {
return errors.New("port is missing")
}
if i.Address == "" {
return errors.New("address is missing")
}
port := lb.Servers[0].Port
lb.Servers[0].Port = ""
if port == "" && i.Port > 0 {
port = strconv.Itoa(i.Port)
}
if port == "" {
return errors.New("port is missing")
}
lb.Servers[0].Address = net.JoinHostPort(i.Address, port)
return nil
}
@@ -203,29 +201,27 @@ func (p *Provider) addServerUDP(i item, lb *dynamic.UDPServersLoadBalancer) erro
return errors.New("load-balancer is missing")
}
var port string
if len(lb.Servers) > 0 {
port = lb.Servers[0].Port
}
if len(lb.Servers) == 0 {
lb.Servers = []dynamic.UDPServer{{}}
}
if i.Port != 0 && port == "" {
port = strconv.Itoa(i.Port)
}
lb.Servers[0].Port = ""
if port == "" {
return errors.New("port is missing")
}
if i.Address == "" {
return errors.New("address is missing")
}
port := lb.Servers[0].Port
lb.Servers[0].Port = ""
if port == "" && i.Port > 0 {
port = strconv.Itoa(i.Port)
}
if port == "" {
return errors.New("port is missing")
}
lb.Servers[0].Address = net.JoinHostPort(i.Address, port)
return nil
}
@@ -234,11 +230,6 @@ func (p *Provider) addServer(i item, lb *dynamic.ServersLoadBalancer) error {
return errors.New("load-balancer is missing")
}
var port string
if len(lb.Servers) > 0 {
port = lb.Servers[0].Port
}
if len(lb.Servers) == 0 {
server := dynamic.Server{}
server.SetDefaults()
@@ -246,19 +237,21 @@ func (p *Provider) addServer(i item, lb *dynamic.ServersLoadBalancer) error {
lb.Servers = []dynamic.Server{server}
}
if i.Port != 0 && port == "" {
if i.Address == "" {
return errors.New("address is missing")
}
port := lb.Servers[0].Port
lb.Servers[0].Port = ""
if port == "" && i.Port > 0 {
port = strconv.Itoa(i.Port)
}
lb.Servers[0].Port = ""
if port == "" {
return errors.New("port is missing")
}
if i.Address == "" {
return errors.New("address is missing")
}
scheme := lb.Servers[0].Scheme
lb.Servers[0].Scheme = ""
lb.Servers[0].URL = fmt.Sprintf("%s://%s", scheme, net.JoinHostPort(i.Address, port))

View File

@@ -160,7 +160,7 @@ func (p *Provider) keepService(ctx context.Context, service rancherData) bool {
matches, err := constraints.MatchLabels(service.Labels, p.Constraints)
if err != nil {
logger.Errorf("Error matching constraints expression: %v", err)
logger.Errorf("Error matching constraint expression: %v", err)
return false
}
if !matches {
@@ -185,23 +185,19 @@ func (p *Provider) keepService(ctx context.Context, service rancherData) bool {
func (p *Provider) addServerTCP(ctx context.Context, service rancherData, loadBalancer *dynamic.TCPServersLoadBalancer) error {
log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name)
serverPort := ""
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
if loadBalancer == nil {
return errors.New("load-balancer is not defined")
}
port := getServicePort(service)
if len(loadBalancer.Servers) == 0 {
server := dynamic.TCPServer{}
loadBalancer.Servers = []dynamic.TCPServer{server}
loadBalancer.Servers = []dynamic.TCPServer{{}}
}
if serverPort != "" {
port = serverPort
loadBalancer.Servers[0].Port = ""
port := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if port == "" {
port = getServicePort(service)
}
if port == "" {
@@ -216,29 +212,26 @@ func (p *Provider) addServerTCP(ctx context.Context, service rancherData, loadBa
}
loadBalancer.Servers = servers
return nil
}
func (p *Provider) addServerUDP(ctx context.Context, service rancherData, loadBalancer *dynamic.UDPServersLoadBalancer) error {
log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name)
serverPort := ""
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
serverPort = loadBalancer.Servers[0].Port
if loadBalancer == nil {
return errors.New("load-balancer is not defined")
}
port := getServicePort(service)
if len(loadBalancer.Servers) == 0 {
server := dynamic.UDPServer{}
loadBalancer.Servers = []dynamic.UDPServer{server}
loadBalancer.Servers = []dynamic.UDPServer{{}}
}
if serverPort != "" {
port = serverPort
loadBalancer.Servers[0].Port = ""
port := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if port == "" {
port = getServicePort(service)
}
if port == "" {
@@ -253,14 +246,16 @@ func (p *Provider) addServerUDP(ctx context.Context, service rancherData, loadBa
}
loadBalancer.Servers = servers
return nil
}
func (p *Provider) addServers(ctx context.Context, service rancherData, loadBalancer *dynamic.ServersLoadBalancer) error {
log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name)
serverPort := getLBServerPort(loadBalancer)
port := getServicePort(service)
if loadBalancer == nil {
return errors.New("load-balancer is not defined")
}
if len(loadBalancer.Servers) == 0 {
server := dynamic.Server{}
@@ -269,9 +264,11 @@ func (p *Provider) addServers(ctx context.Context, service rancherData, loadBala
loadBalancer.Servers = []dynamic.Server{server}
}
if serverPort != "" {
port = serverPort
loadBalancer.Servers[0].Port = ""
port := loadBalancer.Servers[0].Port
loadBalancer.Servers[0].Port = ""
if port == "" {
port = getServicePort(service)
}
if port == "" {
@@ -286,14 +283,8 @@ func (p *Provider) addServers(ctx context.Context, service rancherData, loadBala
}
loadBalancer.Servers = servers
return nil
}
func getLBServerPort(loadBalancer *dynamic.ServersLoadBalancer) string {
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
return loadBalancer.Servers[0].Port
}
return ""
return nil
}
func getServicePort(data rancherData) string {

View File

@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"net/http"
"reflect"
"strings"
"github.com/containous/alice"
@@ -314,7 +315,7 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
return nil, badConf
}
middleware = func(next http.Handler) (http.Handler, error) {
// FIXME missing metrics / accessLog
// TODO missing metrics / accessLog
return retry.New(ctx, next, *config.Retry, retry.Listeners{}, middlewareName)
}
}
@@ -340,7 +341,7 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
}
// Plugin
if config.Plugin != nil {
if config.Plugin != nil && !reflect.ValueOf(b.pluginBuilder).IsNil() { // Using "reflect" because "b.pluginBuilder" is an interface.
if middleware != nil {
return nil, badConf
}

View File

@@ -2,7 +2,6 @@ package middleware
import (
"errors"
"fmt"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/plugins"
@@ -30,9 +29,5 @@ func findPluginConfig(rawConfig map[string]dynamic.PluginConf) (string, map[stri
return "", nil, errors.New("missing plugin type")
}
if len(rawPluginConfig) == 0 {
return "", nil, fmt.Errorf("missing plugin configuration: %s", pluginType)
}
return pluginType, rawPluginConfig, nil
}

View File

@@ -106,7 +106,7 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
// we still need to reply with a 404.
}
// FIXME -- Check if ProxyProtocol changes the first bytes of the request
// TODO -- Check if ProxyProtocol changes the first bytes of the request
br := bufio.NewReader(conn)
serverName, tls, peeked, err := clientHelloServerName(br)
if err != nil {
@@ -218,7 +218,7 @@ func (r *Router) AddHTTPTLSConfig(sniHost string, config *tls.Config) {
// GetConn creates a connection proxy with a peeked string.
func (r *Router) GetConn(conn tcp.WriteCloser, peeked string) tcp.WriteCloser {
// FIXME should it really be on Router ?
// TODO should it really be on Router ?
conn = &Conn{
Peeked: []byte(peeked),
WriteCloser: conn,

View File

@@ -52,11 +52,7 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) m
log.FromContext(ctx).Warn("Config has more than one udp router for a given entrypoint.")
}
handlers, err := m.buildEntryPointHandlers(ctx, routers)
if err != nil {
log.FromContext(ctx).Error(err)
continue
}
handlers := m.buildEntryPointHandlers(ctx, routers)
if len(handlers) > 0 {
// As UDP support only one router per entrypoint, we only take the first one.
@@ -66,7 +62,7 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) m
return entryPointHandlers
}
func (m *Manager) buildEntryPointHandlers(ctx context.Context, configs map[string]*runtime.UDPRouterInfo) ([]udp.Handler, error) {
func (m *Manager) buildEntryPointHandlers(ctx context.Context, configs map[string]*runtime.UDPRouterInfo) []udp.Handler {
var rtNames []string
for routerName := range configs {
rtNames = append(rtNames, routerName)
@@ -101,5 +97,5 @@ func (m *Manager) buildEntryPointHandlers(ctx context.Context, configs map[strin
handlers = append(handlers, handler)
}
return handlers, nil
return handlers
}

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package server

View File

@@ -15,6 +15,7 @@ import (
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
"golang.org/x/net/http/httpguts"
)
// StatusClientClosedRequest non-standard HTTP status code for client disconnection.
@@ -67,16 +68,18 @@ func buildProxy(passHostHeader *bool, responseForwarding *dynamic.ResponseForwar
// some servers need Sec-WebSocket-Key, Sec-WebSocket-Extensions, Sec-WebSocket-Accept,
// Sec-WebSocket-Protocol and Sec-WebSocket-Version to be case-sensitive.
// https://tools.ietf.org/html/rfc6455#page-20
outReq.Header["Sec-WebSocket-Key"] = outReq.Header["Sec-Websocket-Key"]
outReq.Header["Sec-WebSocket-Extensions"] = outReq.Header["Sec-Websocket-Extensions"]
outReq.Header["Sec-WebSocket-Accept"] = outReq.Header["Sec-Websocket-Accept"]
outReq.Header["Sec-WebSocket-Protocol"] = outReq.Header["Sec-Websocket-Protocol"]
outReq.Header["Sec-WebSocket-Version"] = outReq.Header["Sec-Websocket-Version"]
delete(outReq.Header, "Sec-Websocket-Key")
delete(outReq.Header, "Sec-Websocket-Extensions")
delete(outReq.Header, "Sec-Websocket-Accept")
delete(outReq.Header, "Sec-Websocket-Protocol")
delete(outReq.Header, "Sec-Websocket-Version")
if isWebSocketUpgrade(outReq) {
outReq.Header["Sec-WebSocket-Key"] = outReq.Header["Sec-Websocket-Key"]
outReq.Header["Sec-WebSocket-Extensions"] = outReq.Header["Sec-Websocket-Extensions"]
outReq.Header["Sec-WebSocket-Accept"] = outReq.Header["Sec-Websocket-Accept"]
outReq.Header["Sec-WebSocket-Protocol"] = outReq.Header["Sec-Websocket-Protocol"]
outReq.Header["Sec-WebSocket-Version"] = outReq.Header["Sec-Websocket-Version"]
delete(outReq.Header, "Sec-Websocket-Key")
delete(outReq.Header, "Sec-Websocket-Extensions")
delete(outReq.Header, "Sec-Websocket-Accept")
delete(outReq.Header, "Sec-Websocket-Protocol")
delete(outReq.Header, "Sec-Websocket-Version")
}
},
Transport: roundTripper,
FlushInterval: time.Duration(flushInterval),
@@ -112,6 +115,14 @@ func buildProxy(passHostHeader *bool, responseForwarding *dynamic.ResponseForwar
return proxy, nil
}
func isWebSocketUpgrade(req *http.Request) bool {
if !httpguts.HeaderValuesContainsToken(req.Header["Connection"], "Upgrade") {
return false
}
return strings.EqualFold(req.Header.Get("Upgrade"), "websocket")
}
func statusText(statusCode int) string {
if statusCode == StatusClientClosedRequest {
return StatusClientClosedRequestText

View File

@@ -425,7 +425,7 @@ func (m *Manager) upsertServers(ctx context.Context, lb healthcheck.BalancerHand
return fmt.Errorf("error adding server %s to load balancer: %w", srv.URL, err)
}
// FIXME Handle Metrics
// TODO Handle Metrics
}
return nil
}

View File

@@ -14,7 +14,7 @@ import (
)
func TestGetBestCertificate(t *testing.T) {
// FIXME Add tests for defaultCert
// TODO Add tests for defaultCert
testCases := []struct {
desc string
domainToCheck string

View File

@@ -1,5 +1,4 @@
# TODO rewrite this to be able to use go1.19.
FROM golang:1.17
FROM golang:1.19
ARG USER=$USER
ARG UID=$UID
@@ -9,14 +8,15 @@ USER ${UID}:${GID}
ARG KUBE_VERSION
RUN go get k8s.io/code-generator@$KUBE_VERSION; exit 0
RUN go get k8s.io/apimachinery@$KUBE_VERSION; exit 0
RUN go get k8s.io/code-generator/cmd/deepcopy-gen@$KUBE_VERSION; exit 0
RUN go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.2; exit 0
RUN go install k8s.io/code-generator/cmd/defaulter-gen@$KUBE_VERSION
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/informer-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.6.2
RUN mkdir -p $GOPATH/src/k8s.io/{code-generator,apimachinery}
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/apimachinery@$KUBE_VERSION $GOPATH/src/k8s.io/apimachinery
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 chmod +x $GOPATH/src/k8s.io/code-generator/generate-groups.sh
WORKDIR $GOPATH/src/k8s.io/code-generator

View File

@@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file"
FileName = "traefik_changelog.md"
# example new bugfix v2.8.3
# example new bugfix v2.8.8
CurrentRef = "v2.8"
PreviousRef = "v2.8.2"
PreviousRef = "v2.8.7"
BaseBranch = "v2.8"
FutureCurrentRefName = "v2.8.3"
FutureCurrentRefName = "v2.8.8"
ThresholdPreviousRef = 10
ThresholdCurrentRef = 10