Compare commits

...

32 Commits

Author SHA1 Message Date
Romain
32655b5b16 Prepare release v2.4.8 2021-03-23 16:34:04 +01:00
Romain
a513a05b7a Raise errors for non-ASCII domain names in a router's rules 2021-03-22 21:16:04 +01:00
Tom Moulard
1e716a93ff Adding an option to (de)activate Pilot integration into the Traefik dashboard
Co-authored-by: Jean-Baptiste Doumenjou <925513+jbdoumenjou@users.noreply.github.com>
2021-03-22 19:18:04 +01:00
Fabian
06fc2c505f Doc: improve basic auth middleware httpasswd example 2021-03-22 15:26:03 +01:00
Deepyaman Datta
6fcea91d1f Add missing traefik. prefix across sample config 2021-03-19 09:12:04 +01:00
Tom Moulard
93d099a2f0 Fix travis docker image pulling for docs 2021-03-16 12:08:04 +01:00
Corey McGalliard
e5983d96f7 updating docs to remove a no longer needed note 2021-03-15 10:46:03 +01:00
Jean-Baptiste Doumenjou
08e6ae07af Update to gateway-api v0.2.0
Co-authored-by: Romain <rtribotte@users.noreply.github.com>
2021-03-15 09:44:03 +01:00
Matthias Schneider
49b46a9a3f server: updating go-proxyproto with security bugfix from upstream 2021-03-15 09:16:03 +01:00
Ludovic Fernandez
36c316f39c Update go-acme/lego to v4.3.1 2021-03-12 14:38:07 +01:00
Ludovic Fernandez
7e76abc067 Update go-acme/lego to v4.3.0 2021-03-11 09:52:04 +01:00
Jean-Baptiste Doumenjou
b1e11f3e88 Prepare release v2.4.7 2021-03-08 18:04:03 +01:00
Ludovic Fernandez
09d5f59701 fix: double close chan on TLS challenge
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
2021-03-08 11:18:04 +01:00
Julien Salleyron
3c8675bb8b Fix flaky tests.
Co-authored-by: Ludovic Fernandez <ldez@users.noreply.github.com>
2021-03-08 09:58:04 +01:00
Ludovic Fernandez
71ca237478 Add new GitHub issue chooser. 2021-03-08 09:40:04 +01:00
dom3k
0e4b6d36fd Use Docker dependency directly without replace directive 2021-03-07 22:26:03 +01:00
Marc Vertes
e898080460 feature: tune transport buffer size to increase performance 2021-03-05 14:30:04 +01:00
Romain
bdba7d3adf Update to go1.16 2021-03-04 20:08:03 +01:00
Ludovic Fernandez
2e7833df49 chore: update linter. 2021-03-04 09:02:03 +01:00
Romain
ec0d03658d Fix ServersTransport documentation
Co-authored-by: mpl <mathieu.lonjaret@gmail.com>
2021-03-03 16:48:04 +01:00
Jean-Baptiste Doumenjou
d2d7cf14e5 Bump paerser to v0.1.2 2021-03-03 12:46:03 +01:00
Jean-Baptiste Doumenjou
40cd6ada4f Prepare release v2.4.6 2021-03-01 19:14:03 +01:00
wouter bolsterlee
c843c182e4 Address all shellcheck warnings 2021-02-26 14:34:04 +01:00
Tom Moulard
c35a8bdb15 Fixing doc for default value of checknewversion 2021-02-26 10:20:03 +01:00
Julien Salleyron
dd0701dd16 fix: wait for file and internal before applying configurations
Co-authored-by: Ludovic Fernandez <ldez@users.noreply.github.com>
2021-02-25 17:20:04 +01:00
Ludovic Fernandez
32500773b8 Update Yaegi to v0.9.13 2021-02-24 17:06:03 +01:00
Mal Curtis
e7d3f4316f Fix typo in routing/services/index.md 2021-02-22 20:28:05 +01:00
Vasilis Gerakaris
4b38d7368f Fix reflink typo in file provider documentation 2021-02-19 18:48:03 +01:00
Kevin Pollet
dce6a86900 Fix Kubernetes Gateway API documentation links 2021-02-19 17:16:03 +01:00
Romain
dc9c558c06 Prepare release v2.4.5 2021-02-18 18:04:03 +01:00
Romain
b8a466c571 Prepare release v2.4.4 2021-02-18 15:28:03 +01:00
Manuel Zapf
bae28c5f57 Only allow iframes to be loaded from our domain 2021-02-18 14:54:03 +01:00
128 changed files with 2194 additions and 1966 deletions

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Traefik Community Support
url: https://community.traefik.io/
about: If you have a question, or are looking for advice, please post on our Discuss forum! The community loves to chime in to help. Happy Coding!
- name: Traefik Helm Chart Issues
url: https://github.com/traefik/traefik-helm-chart
about: Are you submitting an issue or feature enhancement for the Traefik helm chart? Please post in the traefik-helm-chart GitHub Issues.

View File

@@ -30,38 +30,64 @@
lines = 230 # default 60
statements = 120 # default 40
[linters-settings.forbidigo]
forbid = [
'^print(ln)?$',
'^spew\.Print(f|ln)?$',
'^spew\.Dump$',
]
[linters-settings.depguard]
list-type = "blacklist"
include-go-root = false
packages = ["github.com/pkg/errors"]
[linters-settings.godox]
keywords = ["FIXME"]
[linters-settings.importas]
corev1 = "k8s.io/api/core/v1"
networkingv1beta1 = "k8s.io/api/networking/v1beta1"
extensionsv1beta1 = "k8s.io/api/extensions/v1beta1"
metav1 = "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeerror = "k8s.io/apimachinery/pkg/api/errors"
[linters]
enable-all = true
disable = [
"scopelint", # Deprecated
"interfacer", # Deprecated
"maligned", # Deprecated
"sqlclosecheck", # Not relevant (SQL)
"rowserrcheck", # Not relevant (SQL)
"lll", # Not relevant
"gocyclo", # FIXME must be fixed
"gosec",
"dupl",
"maligned",
"lll",
"unparam",
"prealloc",
"scopelint",
"cyclop", # Duplicate of gocyclo
"gocognit", # Too strict
"nestif", # Too many false-positive.
"prealloc", # Too many false-positive.
"makezero", # Not relevant
"ifshort", # Not relevant
"dupl", # Too strict
"gosec", # Too strict
"gochecknoinits",
"gochecknoglobals",
"godox",
"gocognit",
"bodyclose", # Too many false-positive and panics.
"wsl", # Too strict
"nlreturn", # Not relevant
"gomnd", # Too strict
"stylecheck", # skip because report issues related to some generated files.
"testpackage", # Too strict
"goerr113", # Too strict
"nestif", # Too many false-positive.
"noctx", # Too strict
"exhaustive", # Too strict
"nlreturn", # Not relevant
"wrapcheck", # Too strict
"tparallel", # Not relevant
"paralleltest", # Not relevant
"exhaustive", # Not relevant
"exhaustivestruct", # Not relevant
"makezero", # not relevant
"forbidigo", # not relevant
"ifshort", # not relevant
"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
]
[issues]
@@ -69,9 +95,9 @@
max-per-linter = 0
max-same-issues = 0
exclude = [
"SA1019: http.CloseNotifier is deprecated: the CloseNotifier interface predates Go's context package. New code should use Request.Context instead.", # FIXME must be fixed
"Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked",
"should have a package comment, unless it's in another file for this package",
"SA1019: http.CloseNotifier has been deprecated", # FIXME must be fixed
]
[[issues.exclude-rules]]
path = "(.+)_test.go"
@@ -88,18 +114,12 @@
[[issues.exclude-rules]]
path = "pkg/h2c/h2c.go"
text = "Error return value of `rw.Write` is not checked"
[[issues.exclude-rules]]
path = "pkg/middlewares/recovery/recovery.go"
text = "`logger` can be `github.com/stretchr/testify/assert.TestingT`"
[[issues.exclude-rules]]
path = "pkg/provider/docker/builder_test.go"
text = "(U1000: func )?`(.+)` is unused"
[[issues.exclude-rules]]
path = "pkg/provider/kubernetes/builder_(endpoint|service)_test.go"
text = "(U1000: func )?`(.+)` is unused"
[[issues.exclude-rules]]
path = "pkg/config/parser/.+_test.go"
text = "U1000: field `(foo|fuu)` is unused"
[[issues.exclude-rules]]
path = "pkg/server/service/bufferpool.go"
text = "SA6002: argument should be pointer-like to avoid allocations"
@@ -109,9 +129,6 @@
[[issues.exclude-rules]]
path = "pkg/server/middleware/middlewares.go"
text = "Function 'buildConstructor' has too many statements"
[[issues.exclude-rules]] # FIXME must be fixed
path = "cmd/context.go"
text = "S1000: should use a simple channel send/receive instead of `select` with a single case"
[[issues.exclude-rules]]
path = "pkg/tracing/haystack/logger.go"
linters = ["goprintffuncname"]

View File

@@ -16,7 +16,7 @@ env:
script:
- echo "Skipping tests... (Tests are executed on SemaphoreCI)"
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then make docs; fi
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then travis_retry make docs-pull-images && make docs; fi
before_deploy:
- >

View File

@@ -1,3 +1,54 @@
## [v2.4.8](https://github.com/traefik/traefik/tree/v2.4.8) (2021-03-22)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.7...v2.4.8)
**Bug fixes:**
- **[acme]** Update go-acme/lego to v4.3.1 ([#7980](https://github.com/traefik/traefik/pull/7980) by [ldez](https://github.com/ldez))
- **[acme]** Update go-acme/lego to v4.3.0 ([#7975](https://github.com/traefik/traefik/pull/7975) by [ldez](https://github.com/ldez))
- **[k8s,k8s/gatewayapi]** Update to gateway-api v0.2.0 ([#7943](https://github.com/traefik/traefik/pull/7943) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[pilot,webui]** Adding an option to (de)activate Pilot integration into the Traefik dashboard ([#7994](https://github.com/traefik/traefik/pull/7994) by [tomMoulard](https://github.com/tomMoulard))
- **[rules]** Raise errors for non-ASCII domain names in a router&#39;s rules ([#7986](https://github.com/traefik/traefik/pull/7986) by [rtribotte](https://github.com/rtribotte))
- **[server]** Update pires/go-proxyproto to v0.5.0 ([#7948](https://github.com/traefik/traefik/pull/7948) by [mschneider82](https://github.com/mschneider82))
**Documentation:**
- **[middleware]** Improve basic auth middleware httpasswd example ([#7992](https://github.com/traefik/traefik/pull/7992) by [d3473r](https://github.com/d3473r))
- **[middleware]** Add missing `traefik.` prefix across sample config ([#7990](https://github.com/traefik/traefik/pull/7990) by [deepyaman](https://github.com/deepyaman))
- **[middleware]** Remove a no longer needed note ([#7979](https://github.com/traefik/traefik/pull/7979) by [cmcga1125](https://github.com/cmcga1125))
## [v2.4.7](https://github.com/traefik/traefik/tree/v2.4.7) (2021-03-08)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.6...v2.4.7)
**Bug fixes:**
- **[acme]** Fix: double close chan on TLS challenge ([#7956](https://github.com/traefik/traefik/pull/7956) by [ldez](https://github.com/ldez))
- **[provider]** Bump paerser to v0.1.2 ([#7945](https://github.com/traefik/traefik/pull/7945) by [jbdoumenjou](https://github.com/jbdoumenjou))
- **[server]** Feature: tune transport buffer size to increase performance ([#7957](https://github.com/traefik/traefik/pull/7957) by [mvertes](https://github.com/mvertes))
**Documentation:**
- **[service]** Fix ServersTransport documentation ([#7942](https://github.com/traefik/traefik/pull/7942) by [rtribotte](https://github.com/rtribotte))
## [v2.4.6](https://github.com/traefik/traefik/tree/v2.4.6) (2021-03-01)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.5...v2.4.6)
**Bug fixes:**
- **[plugins]** Update Yaegi to v0.9.13 ([#7928](https://github.com/traefik/traefik/pull/7928) by [ldez](https://github.com/ldez))
- **[provider]** Fix: wait for file and internal before applying configurations ([#7925](https://github.com/traefik/traefik/pull/7925) by [juliens](https://github.com/juliens))
**Documentation:**
- **[file]** Fix reflink typo in file provider documentation ([#7913](https://github.com/traefik/traefik/pull/7913) by [vgerak](https://github.com/vgerak))
- **[k8s/serviceapi]** Fix Kubernetes Gateway API documentation links ([#7914](https://github.com/traefik/traefik/pull/7914) by [kevinpollet](https://github.com/kevinpollet))
- **[service]** Fix typo in routing/services/index.md ([#7922](https://github.com/traefik/traefik/pull/7922) by [snikch](https://github.com/snikch))
- Fixing doc for default value of checknewversion ([#7933](https://github.com/traefik/traefik/pull/7933) by [tomMoulard](https://github.com/tomMoulard))
## [v2.4.5](https://github.com/traefik/traefik/tree/v2.4.5) (2021-02-18)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.3...v2.4.5)
**Bug fixes:**
- **[webui]** Only allow iframes to be loaded from our domain ([#7904](https://github.com/traefik/traefik/pull/7904) by [SantoDE](https://github.com/SantoDE))
## [v2.4.4](https://github.com/traefik/traefik/tree/v2.4.4) (2021-02-18)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.3...v2.4.4)
Release canceled.
## [v2.4.3](https://github.com/traefik/traefik/tree/v2.4.3) (2021-02-15)
[All Commits](https://github.com/traefik/traefik/compare/v2.4.2...v2.4.3)

View File

@@ -63,18 +63,18 @@ generate-webui: build-webui-image
mkdir -p static; \
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui npm run build:nc; \
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui chown -R $(shell id -u):$(shell id -g) ../static; \
echo 'For more informations show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
echo 'For more information show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
fi
## Build the linux binary
binary: generate-webui $(PRE_TARGET)
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate binary
## Build the binary for the standard plaforms (linux, darwin, windows)
## Build the binary for the standard platforms (linux, darwin, windows)
crossbinary-default: generate-webui build-dev-image
$(DOCKER_RUN_TRAEFIK_NOTTY) ./script/make.sh generate crossbinary-default
## Build the binary for the standard plaforms (linux, darwin, windows) in parallel
## Build the binary for the standard platforms (linux, darwin, windows) in parallel
crossbinary-default-parallel:
$(MAKE) generate-webui
$(MAKE) build-dev-image crossbinary-default
@@ -127,6 +127,10 @@ docs:
docs-serve:
make -C ./docs docs-serve
## Pull image for doc building
docs-pull-images:
make -C ./docs docs-pull-images
## Generate CRD clientset
generate-crd:
./script/update-generated-crd-code.sh

View File

@@ -1,4 +1,4 @@
FROM golang:1.15-alpine
FROM golang:1.16-alpine
RUN apk --update upgrade \
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \
@@ -19,7 +19,7 @@ RUN mkdir -p /usr/local/bin \
&& chmod +x /usr/local/bin/go-bindata
# Download golangci-lint binary to bin folder in $GOPATH
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.36.0
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.38.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

@@ -13,10 +13,8 @@ func ContextWithSignal(ctx context.Context) context.Context {
signals := make(chan os.Signal)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
go func() {
select {
case <-signals:
cancel()
}
<-signals
cancel()
}()
return newCtx
}

View File

@@ -222,6 +222,10 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
})
}
if staticConfiguration.Pilot != nil {
version.PilotEnabled = staticConfiguration.Pilot.Dashboard
}
// Plugins
pluginBuilder, err := createPluginBuilder(staticConfiguration)
@@ -256,6 +260,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
providerAggregator,
time.Duration(staticConfiguration.Providers.ProvidersThrottleDuration),
getDefaultsEntrypoints(staticConfiguration),
"internal",
)
// TLS
@@ -365,30 +370,32 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr
var resolvers []*acme.Provider
for name, resolver := range c.CertificatesResolvers {
if resolver.ACME != nil {
if localStores[resolver.ACME.Storage] == nil {
localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage)
}
p := &acme.Provider{
Configuration: resolver.ACME,
Store: localStores[resolver.ACME.Storage],
ResolverName: name,
HTTPChallengeProvider: httpChallengeProvider,
TLSChallengeProvider: tlsChallengeProvider,
}
if err := providerAggregator.AddProvider(p); err != nil {
log.WithoutContext().Errorf("The ACME resolver %q is skipped from the resolvers list because: %v", name, err)
continue
}
p.SetTLSManager(tlsManager)
p.SetConfigListenerChan(make(chan dynamic.Configuration))
resolvers = append(resolvers, p)
if resolver.ACME == nil {
continue
}
if localStores[resolver.ACME.Storage] == nil {
localStores[resolver.ACME.Storage] = acme.NewLocalStore(resolver.ACME.Storage)
}
p := &acme.Provider{
Configuration: resolver.ACME,
Store: localStores[resolver.ACME.Storage],
ResolverName: name,
HTTPChallengeProvider: httpChallengeProvider,
TLSChallengeProvider: tlsChallengeProvider,
}
if err := providerAggregator.AddProvider(p); err != nil {
log.WithoutContext().Errorf("The ACME resolver %q is skipped from the resolvers list because: %v", name, err)
continue
}
p.SetTLSManager(tlsManager)
p.SetConfigListenerChan(make(chan dynamic.Configuration))
resolvers = append(resolvers, p)
}
return resolvers

View File

@@ -12,7 +12,7 @@ TRAEFIK_DOCS_CHECK_IMAGE ?= $(TRAEFIK_DOCS_BUILD_IMAGE)-check
SITE_DIR := $(CURDIR)/site
DOCKER_RUN_DOC_PORT := 8000
DOCKER_RUN_DOC_MOUNTS := -v $(CURDIR):/mkdocs
DOCKER_RUN_DOC_MOUNTS := -v $(CURDIR):/mkdocs
DOCKER_RUN_DOC_OPTS := --rm $(DOCKER_RUN_DOC_MOUNTS) -p $(DOCKER_RUN_DOC_PORT):8000
# Default: generates the documentation into $(SITE_DIR)
@@ -22,6 +22,10 @@ docs: docs-clean docs-image docs-lint docs-build docs-verify
docs-serve: docs-image
docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_DOCS_BUILD_IMAGE) mkdocs serve
## Pull image for doc building
docs-pull-images:
grep --no-filename -E '^FROM' ./*.Dockerfile | awk '{print $$2}' | sort | uniq | xargs -P 6 -n 1 docker pull
# Utilities Targets for each step
docs-image:
docker build -t $(TRAEFIK_DOCS_BUILD_IMAGE) -f docs.Dockerfile ./

View File

@@ -30,7 +30,7 @@ Successfully tagged traefik-webui:latest
[...]
docker build -t "traefik-dev:4475--feature-documentation" -f build.Dockerfile .
Sending build context to Docker daemon 279MB
Step 1/10 : FROM golang:1.14-alpine
Step 1/10 : FROM golang:1.16-alpine
---> f4bfb3d22bda
[...]
Successfully built 5c3c1a911277
@@ -62,7 +62,7 @@ PRE_TARGET= make test-unit
Requirements:
- `go` v1.14+
- `go` v1.16+
- environment variable `GO111MODULE=on`
- [go-bindata](https://github.com/containous/go-bindata) `GO111MODULE=off go get -u github.com/containous/go-bindata/...`

View File

@@ -303,6 +303,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [DNS Made Easy](https://dnsmadeeasy.com) | `dnsmadeeasy` | `DNSMADEEASY_API_KEY`, `DNSMADEEASY_API_SECRET`, `DNSMADEEASY_SANDBOX` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsmadeeasy) |
| [DNSPod](https://www.dnspod.com/) | `dnspod` | `DNSPOD_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dnspod) |
| [Domain Offensive (do.de)](https://www.do.de/) | `dode` | `DODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/dode) |
| [Domeneshop](https://domene.shop) | `domeneshop` | `DOMENESHOP_API_TOKEN`, `DOMENESHOP_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/domeneshop) |
| [DreamHost](https://www.dreamhost.com/) | `dreamhost` | `DREAMHOST_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/dreamhost) |
| [Duck DNS](https://www.duckdns.org/) | `duckdns` | `DUCKDNS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/duckdns) |
| [Dyn](https://dyn.com) | `dyn` | `DYN_CUSTOMER_NAME`, `DYN_USER_NAME`, `DYN_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/dyn) |
@@ -324,7 +325,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [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) |
| [Infomaniak](https://www.infomaniak.com) | `infomaniak` | `INFOMANIAK_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/infomaniak) |
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) |
| [ionos](https://ionos.com/) | `ionos` | `IONOS_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ionos) |
| [ionos](https://ionos.com/) | `ionos` | `IONOS_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ionos) |
| [Joker.com](https://joker.com) | `joker` | `JOKER_API_MODE` with `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) |
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) |
| [Linode v4](https://www.linode.com) | `linode` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
@@ -340,6 +341,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [Netcup](https://www.netcup.eu/) | `netcup` | `NETCUP_CUSTOMER_NUMBER`, `NETCUP_API_KEY`, `NETCUP_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/netcup) |
| [Netlify](https://www.netlify.com) | `netlify` | `NETLIFY_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/netlify) |
| [NIFCloud](https://cloud.nifty.com/service/dns.htm) | `nifcloud` | `NIFCLOUD_ACCESS_KEY_ID`, `NIFCLOUD_SECRET_ACCESS_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/nifcloud) |
| [Njalla](https://njal.la) | `njalla` | `NJALLA_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/njalla) |
| [NS1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ns1) |
| [Open Telekom Cloud](https://cloud.telekom.de) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` | [Additional configuration](https://go-acme.github.io/lego/dns/otc) |
| [OVH](https://www.ovh.com) | `ovh` | `OVH_ENDPOINT`, `OVH_APPLICATION_KEY`, `OVH_APPLICATION_SECRET`, `OVH_CONSUMER_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ovh) |

View File

@@ -14,7 +14,7 @@ The BasicAuth middleware restricts access to your services to known users.
#
# Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping.
# To create user:password pair, it's possible to use this command:
# echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
# echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g
#
# Also note that dollar signs should NOT be doubled when they not evaluated (e.g. Ansible docker_container module).
labels:

View File

@@ -21,7 +21,7 @@ labels:
- "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "traefik.http.middlewares.https-only.redirectscheme.scheme=https"
- "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32"
- "http.services.service1.loadbalancer.server.port=80"
- "traefik.http.services.service1.loadbalancer.server.port=80"
```
```yaml tab="Kubernetes"
@@ -89,7 +89,7 @@ spec:
- "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "traefik.http.middlewares.https-only.redirectscheme.scheme=https"
- "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32"
- "http.services.service1.loadbalancer.server.port=80"
- "traefik.http.services.service1.loadbalancer.server.port=80"
```
```json tab="Marathon"
@@ -101,7 +101,7 @@ spec:
"traefik.http.middlewares.auth-users.basicauth.users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"traefik.http.middlewares.https-only.redirectscheme.scheme": "https",
"traefik.http.middlewares.known-ips.ipwhitelist.sourceRange": "192.168.1.7,127.0.0.1/32",
"http.services.service1.loadbalancer.server.port": "80"
"traefik.http.services.service1.loadbalancer.server.port": "80"
}
```
@@ -114,7 +114,7 @@ labels:
- "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "traefik.http.middlewares.https-only.redirectscheme.scheme=https"
- "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32"
- "http.services.service1.loadbalancer.server.port=80"
- "traefik.http.services.service1.loadbalancer.server.port=80"
```
```toml tab="File (TOML)"

View File

@@ -75,8 +75,6 @@ http:
In the following example, requests are proxied with an extra `X-Script-Name` header while their `X-Custom-Request-Header` header gets stripped,
and responses are stripped of their `X-Custom-Response-Header` header.
Please note that it is not possible to remove headers through the use of labels (Docker, Rancher, Marathon, ...) for now.
```yaml tab="Docker"
labels:
- "traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name=test"

View File

@@ -336,3 +336,18 @@ The file parser has been changed, since v2.3 the unknown options/fields in a dyn
In `v2.3`, the support of `IngressClass`, which is available since Kubernetes version `1.18`, has been introduced.
In order to be able to use this new resource the [Kubernetes RBAC](../reference/dynamic-configuration/kubernetes-crd.md#rbac) must be updated.
## v2.4.7 to v2.4.8
### Non-ASCII Domain Names
In `v2.4.8` we introduced a new check on domain names used in HTTP router rule `Host` and `HostRegexp` expressions,
and in TCP router rule `HostSNI` expression.
This check ensures that provided domain names don't contain non-ASCII characters.
If not, an error is raised, and the associated router will be shown as invalid in the dashboard.
This new behavior is intended to show what was failing silently previously and to help troubleshooting configuration issues.
It doesn't change the support for non-ASCII domain names in routers rules, which is not part of the Traefik feature set so far.
In order to use non-ASCII domain names in a router's rule, one should use the Punycode form of the domain name.
For more information, please read the [HTTP routers rule](../routing/routers/index.md#rule) part or [TCP router rules](../routing/routers/index.md#rule_1) part of the documentation.

View File

@@ -5,7 +5,7 @@ Good Old Configuration File
The file provider lets you define the [dynamic configuration](./overview.md) in a TOML or YAML file.
It supports providing configuration through a [single configuration file]](#filename) or [multiple separate files](#directory).
It supports providing configuration through a [single configuration file](#filename) or [multiple separate files](#directory).
!!! info

View File

@@ -6,10 +6,10 @@ The Kubernetes Gateway API, The Experimental Way.
Gateway API is the evolution of Kubernetes APIs that relate to `Services`, such as `Ingress`.
The Gateway API project is part of Kubernetes, working under SIG-NETWORK.
The Kubernetes Gateway provider is a Traefik implementation of the [Service APIs](https://kubernetes-sigs.github.io/gateway-api/)
The Kubernetes Gateway provider is a Traefik implementation of the [Gateway API](https://gateway-api.sigs.k8s.io/)
specifications from the Kubernetes Special Interest Groups (SIGs).
This provider is proposed as an experimental feature and partially supports the Service APIs [v0.1.0](https://github.com/kubernetes-sigs/service-apis/releases/tag/v0.1.0) specification.
This provider is proposed as an experimental feature and partially supports the Gateway API [v0.2.0](https://github.com/kubernetes-sigs/gateway-api/releases/tag/v0.2.0) specification.
!!! warning "Enabling The Experimental Kubernetes Gateway Provider"
@@ -71,9 +71,9 @@ This provider is proposed as an experimental feature and partially supports the
--8<-- "content/reference/dynamic-configuration/kubernetes-gateway-rbac.yml"
```
The Kubernetes Service APIs project provides several [guides](https://kubernetes-sigs.github.io/gateway-api/guides/) on how to use the APIs.
The Kubernetes Gateway API project provides several [guides](https://gateway-api.sigs.k8s.io/guides/) on how to use the APIs.
These guides can help you to go further than the example above.
The [getting started guide](https://kubernetes-sigs.github.io/gateway-api/getting-started/) details how to install the CRDs from their repository.
The [getting started guide](https://gateway-api.sigs.k8s.io/getting-started/) details how to install the CRDs from their repository.
!!! note ""
@@ -81,9 +81,9 @@ The [getting started guide](https://kubernetes-sigs.github.io/gateway-api/gettin
For now, the Traefik Gateway Provider can be used while following the below guides:
* [Simple Gateway](https://kubernetes-sigs.github.io/gateway-api/simple-gateway/)
* [HTTP routing](https://kubernetes-sigs.github.io/gateway-api/http-routing/)
* [TLS](https://kubernetes-sigs.github.io/gateway-api/tls/) (Partial support: only on listeners with terminate mode)
* [Simple Gateway](https://gateway-api.sigs.k8s.io/simple-gateway/)
* [HTTP routing](https://gateway-api.sigs.k8s.io/http-routing/)
* [TLS](https://gateway-api.sigs.k8s.io/tls/) (Partial support: only on listeners with terminate mode)
## Resource Configuration
@@ -91,7 +91,7 @@ When using Kubernetes Gateway API as a provider, Traefik uses Kubernetes
[Custom Resource Definitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)
to retrieve its routing configuration.
All concepts can be found in the official API concepts [documentation](https://kubernetes-sigs.github.io/gateway-api/api-overview/).
All concepts can be found in the official API concepts [documentation](https://gateway-api.sigs.k8s.io/api-overview/).
Traefik implements the following resources:
* `GatewayClass` defines a set of Gateways that share a common configuration and behaviour.

View File

@@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
controller-gen.kubebuilder.io/version: v0.4.1
creationTimestamp: null
name: gatewayclasses.networking.x-k8s.io
spec:
@@ -25,7 +25,7 @@ spec:
name: v1alpha1
schema:
openAPIV3Schema:
description: "GatewayClass describes a class of Gateways available to the user for creating Gateway resources. \n GatewayClass is a Cluster level resource. \n Support: Core."
description: "GatewayClass describes a class of Gateways available to the user for creating Gateway resources. \n GatewayClass is a Cluster level resource."
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
@@ -36,14 +36,14 @@ spec:
metadata:
type: object
spec:
description: Spec for this GatewayClass.
description: Spec defines the desired state of GatewayClass.
properties:
controller:
description: "Controller is a domain/path string that indicates the controller that is managing Gateways of this class. \n Example: \"acme.io/gateway-controller\". \n This field is not mutable and cannot be empty. \n The format of this field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). \n Support: Core"
maxLength: 253
type: string
parametersRef:
description: "ParametersRef is a controller-specific resource containing the configuration parameters corresponding to this class. This is optional if the controller does not require any additional configuration. \n Parameters resources are implementation specific custom resources. These resources must be cluster-scoped. \n If the referent cannot be found, the GatewayClass's \"InvalidParameters\" status condition will be true. \n Support: Custom"
description: "ParametersRef is a reference to a resource that contains the configuration parameters corresponding to the GatewayClass. This is optional if the controller does not require any additional configuration. \n ParametersRef can reference a standard Kubernetes resource, i.e. ConfigMap, or an implementation-specific custom resource. The resource can be cluster-scoped or namespace-scoped. \n If the referent cannot be found, the GatewayClass's \"InvalidParameters\" status condition will be true. \n Support: Custom"
properties:
group:
description: Group is the group of the referent.
@@ -60,6 +60,18 @@ spec:
maxLength: 253
minLength: 1
type: string
namespace:
description: Namespace is the namespace of the referent. This field is required when scope is set to "Namespace" and ignored when scope is set to "Cluster".
maxLength: 253
minLength: 1
type: string
scope:
default: Cluster
description: Scope represents if the referent is a Cluster or Namespace scoped resource. This may be set to "Cluster" or "Namespace".
enum:
- Cluster
- Namespace
type: string
required:
- group
- kind
@@ -74,9 +86,9 @@ spec:
- lastTransitionTime: "1970-01-01T00:00:00Z"
message: Waiting for controller
reason: Waiting
status: Unknown
type: InvalidParameters
description: Status of the GatewayClass.
status: "False"
type: Admitted
description: Status defines the current state of GatewayClass.
properties:
conditions:
default:
@@ -85,7 +97,7 @@ spec:
reason: Waiting
status: "False"
type: Admitted
description: Conditions is the current status from the controller for this GatewayClass.
description: "Conditions is the current status from the controller for this GatewayClass. \n Controllers should prefer to publish conditions using values of GatewayClassConditionType for the type of each Condition."
items:
description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:

View File

@@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
controller-gen.kubebuilder.io/version: v0.4.1
creationTimestamp: null
name: gateways.networking.x-k8s.io
spec:
@@ -36,7 +36,7 @@ spec:
metadata:
type: object
spec:
description: "GatewaySpec defines the desired state of Gateway. \n Not all possible combinations of options specified in the Spec are valid. Some invalid configurations can be caught synchronously via a webhook, but there are many cases that will require asynchronous signaling via the GatewayStatus block."
description: Spec defines the desired state of Gateway.
properties:
addresses:
description: "Addresses requested for this gateway. This is optional and behavior can depend on the GatewayClass. If a value is set in the spec and the requested address is invalid, the GatewayClass MUST indicate this in the associated entry in GatewayStatus.Addresses. \n If no Addresses are specified, the GatewayClass may schedule the Gateway in an implementation-defined manner, assigning an appropriate set of Addresses. \n The GatewayClass MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway. \n Support: Core"
@@ -45,13 +45,13 @@ spec:
properties:
type:
default: IPAddress
description: "Type of the Address. This is either \"IPAddress\" or \"NamedAddress\". \n Support: Extended"
description: "Type of the address. \n Support: Extended"
enum:
- IPAddress
- NamedAddress
type: string
value:
description: 'Value. Examples: "1.2.3.4", "128::1", "my-ip-address". Validity of the values will depend on `Type` and support by the controller.'
description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`."
maxLength: 253
minLength: 1
type: string
@@ -71,7 +71,7 @@ spec:
description: Listener embodies the concept of a logical endpoint where a Gateway can accept network connections. Each listener in a Gateway must have a unique combination of Hostname, Port, and Protocol. This will be enforced by a validating webhook.
properties:
hostname:
description: "Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified or \"*\", all hostnames are matched. This field can be omitted for protocols that don't require hostname based matching. \n Hostname is the fully qualified domain name of a network host, as defined by RFC 3986. Note the following deviations from the \"host\" part of the URI as defined in the RFC: \n 1. IP literals are not allowed. 2. The `:` delimiter is not respected because ports are not allowed. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. \"*.example.com\"). The wildcard character '*' must appear by itself as the first DNS label and matches only a single label. \n Support: Core"
description: "Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified, \"\", or `*`, all hostnames are matched. This field can be omitted for protocols that don't require hostname based matching. \n Hostname is the fully qualified domain name of a network host, as defined by RFC 3986. Note the following deviations from the \"host\" part of the URI as defined in the RFC: \n 1. IP literals are not allowed. 2. The `:` delimiter is not respected because ports are not allowed. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). The wildcard character `*` must appear by itself as the first DNS label and matches only a single label. \n Support: Core"
maxLength: 253
minLength: 1
type: string
@@ -94,7 +94,7 @@ spec:
minLength: 1
type: string
kind:
description: "Kind is the kind of the route resource to select. \n Kind MUST correspond to kinds of routes that are compatible with the application protocol specified in the Listener's Protocol field. \n If an implementation does not support or recognize this resource type, it SHOULD raise a \"ConditionInvalidRoutes\" condition for the affected Listener. \n Support: Core"
description: "Kind is the kind of the route resource to select. \n Kind MUST correspond to kinds of routes that are compatible with the application protocol specified in the Listener's Protocol field. \n If an implementation does not support or recognize this resource type, it SHOULD set the \"ResolvedRefs\" condition to false for this listener with the \"InvalidRoutesRef\" reason. \n Support: Core"
type: string
namespaces:
default:
@@ -102,6 +102,7 @@ spec:
description: "Namespaces indicates in which namespaces Routes should be selected for this Gateway. This is restricted to the namespace of this Gateway by default. \n Support: Core"
properties:
from:
default: Same
description: "From indicates where Routes will be selected for this Gateway. Possible values are: * All: Routes in all namespaces may be used by this Gateway. * Selector: Routes in namespaces selected by the selector may be used by this Gateway. * Same: Only Routes in the same namespace may be used by this Gateway. \n Support: Core"
enum:
- All
@@ -140,7 +141,7 @@ spec:
type: object
type: object
selector:
description: "Selector specifies a set of route labels used for selecting routes to associate with the Gateway. If RouteSelector is defined, only routes matching the RouteSelector are associated with the Gateway. An empty RouteSelector matches all routes. \n Support: Core"
description: "Selector specifies a set of route labels used for selecting routes to associate with the Gateway. If this Selector is defined, only routes matching the Selector are associated with the Gateway. An empty Selector matches all routes. \n Support: Core"
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
@@ -176,7 +177,7 @@ spec:
description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\" and ignored otherwise. \n The association of SNIs to Certificate defined in GatewayTLSConfig is defined based on the Hostname field for this listener. \n The GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake. \n Support: Core"
properties:
certificateRef:
description: 'CertificateRef is the reference to Kubernetes object that contain a TLS certificate and private key. This certificate MUST be used for TLS handshakes for the domain this GatewayTLSConfig is associated with. If an entry in this list omits or specifies the empty string for both the group and the resource, the resource defaults to "secrets". An implementation may support other resources (for example, resource "mycertificates" in group "networking.acme.io"). Support: Core (Kubernetes Secrets) Support: Implementation-specific (Other resource types)'
description: "CertificateRef is the reference to Kubernetes object that contain a TLS certificate and private key. This certificate MUST be used for TLS handshakes for the domain this GatewayTLSConfig is associated with. \n This field is required when mode is set to \"Terminate\" (default) and optional otherwise. \n If an entry in this list omits or specifies the empty string for both the group and the resource, the resource defaults to \"secrets\". An implementation may support other resources (for example, resource \"mycertificates\" in group \"networking.acme.io\"). \n Support: Core (Kubernetes Secrets) \n Support: Implementation-specific (Other resource types)"
properties:
group:
description: Group is the group of the referent.
@@ -199,7 +200,8 @@ spec:
- name
type: object
mode:
description: 'Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes: - Terminate: The TLS session between the downstream client and the Gateway is terminated at the Gateway. - Passthrough: The TLS session is NOT terminated by the Gateway. This implies that the Gateway can''t decipher the TLS stream except for the ClientHello message of the TLS protocol. CertificateRef field is ignored in this mode.'
default: Terminate
description: "Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes: - Terminate: The TLS session between the downstream client and the Gateway is terminated at the Gateway. This mode requires certificateRef to be set. - Passthrough: The TLS session is NOT terminated by the Gateway. This implies that the Gateway can't decipher the TLS stream except for the ClientHello message of the TLS protocol. CertificateRef field is ignored in this mode. \n Support: Core"
enum:
- Terminate
- Passthrough
@@ -207,12 +209,12 @@ spec:
options:
additionalProperties:
type: string
description: "Options are a list of key/value pairs to give extended options to the provider. \n There variation among providers as to how ciphersuites are expressed. If there is a common subset for expressing ciphers then it will make sense to loft that as a core API construct. \n Support: Implementation-specific."
description: "Options are a list of key/value pairs to give extended options to the provider. \n There variation among providers as to how ciphersuites are expressed. If there is a common subset for expressing ciphers then it will make sense to loft that as a core API construct. \n Support: Implementation-specific"
type: object
routeOverride:
default:
certificate: Deny
description: "RouteOverride dictates if TLS settings can be configured via Routes or not. \n CertificateRef must be defined even if `routeOverride.certificate` is set to 'Allow' as it will be used as the default certificate for the listener."
description: "RouteOverride dictates if TLS settings can be configured via Routes or not. \n CertificateRef must be defined even if `routeOverride.certificate` is set to 'Allow' as it will be used as the default certificate for the listener. \n Support: Core"
properties:
certificate:
default: Deny
@@ -221,8 +223,6 @@ spec:
- Allow
- Deny
type: string
required:
- certificate
type: object
type: object
required:
@@ -245,7 +245,7 @@ spec:
reason: NotReconciled
status: "False"
type: Scheduled
description: GatewayStatus defines the observed state of Gateway.
description: Status defines the current state of Gateway.
properties:
addresses:
description: "Addresses lists the IP addresses that have actually been bound to the Gateway. These addresses may differ from the addresses in the Spec, e.g. if the Gateway automatically assigns an address from a reserved pool. \n These addresses should all be of type \"IPAddress\"."
@@ -254,13 +254,13 @@ spec:
properties:
type:
default: IPAddress
description: "Type of the Address. This is either \"IPAddress\" or \"NamedAddress\". \n Support: Extended"
description: "Type of the address. \n Support: Extended"
enum:
- IPAddress
- NamedAddress
type: string
value:
description: 'Value. Examples: "1.2.3.4", "128::1", "my-ip-address". Validity of the values will depend on `Type` and support by the controller.'
description: "Value of the address. The validity of the values will depend on the type and support by the controller. \n Examples: `1.2.3.4`, `128::1`, `my-ip-address`."
maxLength: 253
minLength: 1
type: string

View File

@@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
controller-gen.kubebuilder.io/version: v0.4.1
creationTimestamp: null
name: httproutes.networking.x-k8s.io
spec:
@@ -34,7 +34,7 @@ spec:
metadata:
type: object
spec:
description: HTTPRouteSpec defines the desired state of HTTPRoute
description: Spec defines the desired state of HTTPRoute.
properties:
gateways:
default:
@@ -71,7 +71,7 @@ spec:
type: array
type: object
hostnames:
description: "Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. Hostname is the fully qualified domain name of a network host, as defined by RFC 3986. Note the following deviations from the \"host\" part of the URI as defined in the RFC: \n 1. IPs are not allowed. 2. The `:` delimiter is not respected because ports are not allowed. \n Incoming requests are matched against the hostnames before the HTTPRoute rules. If no hostname is specified, traffic is routed based on the HTTPRouteRules. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. \"*.example.com\"). The wildcard character '*' must appear by itself as the first DNS label and matches only a single label. You cannot have a wildcard label by itself (e.g. Host == \"*\"). Requests will be matched against the Host field in the following order: 1. If Host is precise, the request matches this rule if the http host header is equal to Host. 2. If Host is a wildcard, then the request matches this rule if the http host header is to equal to the suffix (removing the first label) of the wildcard rule. \n Support: Core"
description: "Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request. Hostname is the fully qualified domain name of a network host, as defined by RFC 3986. Note the following deviations from the \"host\" part of the URI as defined in the RFC: \n 1. IPs are not allowed. 2. The `:` delimiter is not respected because ports are not allowed. \n Incoming requests are matched against the hostnames before the HTTPRoute rules. If no hostname is specified, traffic is routed based on the HTTPRouteRules. \n Hostname can be \"precise\" which is a domain name without the terminating dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain name prefixed with a single wildcard label (e.g. `*.example.com`). The wildcard character `*` must appear by itself as the first DNS label and matches only a single label. You cannot have a wildcard label by itself (e.g. Host == `*`). Requests will be matched against the Host field in the following order: \n 1. If Host is precise, the request matches this rule if the HTTP Host header is equal to Host. 2. If Host is a wildcard, then the request matches this rule if the HTTP Host header is to equal to the suffix (removing the first label) of the wildcard rule. \n Support: Core"
items:
description: Hostname is used to specify a hostname that should be matched.
maxLength: 253
@@ -80,12 +80,17 @@ spec:
maxItems: 16
type: array
rules:
default:
- matches:
- path:
type: Prefix
value: /
description: Rules are a list of HTTP matchers, filters and actions.
items:
description: HTTPRouteRule defines semantics for matching an HTTP request based on conditions, optionally executing additional processing steps, and forwarding the request to an API object.
properties:
filters:
description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: - ALL core filters MUST be supported by all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or custom conformance. \n Support: core"
description: "Filters define the filters that are applied to requests that match this rule. \n The effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage. \n Conformance-levels at this level are defined based on the type of filter: \n - ALL core filters MUST be supported by all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. \n Specifying a core filter multiple times has unspecified or custom conformance. \n Support: Core"
items:
description: 'HTTPRouteFilter defines additional processing steps that must be completed during the request or response lifecycle. HTTPRouteFilters are meant as an extension point to express additional processing that may be done in Gateway implementations. Some examples include request or response modification, implementing authentication strategies, rate-limiting, and traffic shaping. API guarantee/conformance is defined based on the type of the filter. TODO(hbagdi): re-render CRDs once controller-tools supports union tags: - https://github.com/kubernetes-sigs/controller-tools/pull/298 - https://github.com/kubernetes-sigs/controller-tools/issues/461'
properties:
@@ -118,14 +123,19 @@ spec:
add:
additionalProperties:
type: string
description: "Add adds the given header (name, value) to the request before the action. \n Input: GET /foo HTTP/1.1 \n Config: add: {\"my-header\": \"foo\"} \n Output: GET /foo HTTP/1.1 my-header: foo \n Support: Extended"
description: "Add adds the given header (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: {\"my-header\": \"bar\"} \n Output: GET /foo HTTP/1.1 my-header: foo my-header: bar \n Support: Extended"
type: object
remove:
description: "Remove the given header(s) from the HTTP request before the action. The value of RemoveHeader is a list of HTTP header names. Note that the header names are case-insensitive [RFC-2616 4.2]. \n Input: GET /foo HTTP/1.1 My-Header1: ABC My-Header2: DEF My-Header2: GHI \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 My-Header2: DEF \n Support: Extended"
description: "Remove the given header(s) from the HTTP request before the action. The value of RemoveHeader is a list of HTTP header names. Note that the header names are case-insensitive [RFC-2616 4.2]. \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar \n Support: Extended"
items:
type: string
maxItems: 16
type: array
set:
additionalProperties:
type: string
description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: {\"my-header\": \"bar\"} \n Output: GET /foo HTTP/1.1 my-header: bar \n Support: Extended"
type: object
type: object
requestMirror:
description: "RequestMirror defines a schema for a filter that mirrors requests. \n Support: Extended"
@@ -154,7 +164,7 @@ spec:
- name
type: object
port:
description: Port specifies the destination port number to use for the backend referenced by the ServiceName or BackendRef field.
description: "Port specifies the destination port number to use for the backend referenced by the ServiceName or BackendRef field. \n If unspecified, the destination port in the request is used when forwarding to a backendRef or serviceName."
format: int32
maximum: 65535
minimum: 1
@@ -163,8 +173,6 @@ spec:
description: "ServiceName refers to the name of the Service to mirror matched requests to. When specified, this takes the place of BackendRef. If both BackendRef and ServiceName are specified, ServiceName will be given precedence. \n If the referent cannot be found, the rule is not included in the route. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DegradedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n Support: Core"
maxLength: 253
type: string
required:
- port
type: object
type:
description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Custom: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior."
@@ -184,7 +192,7 @@ spec:
description: HTTPRouteForwardTo defines how a HTTPRoute should forward a request.
properties:
backendRef:
description: "BackendRef is a reference to a backend to forward matched requests to. If both BackendRef and ServiceName are specified, ServiceName will be given precedence. \n If the referent cannot be found, the route must be dropped from the Gateway. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DroppedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n Support: Custom"
description: "BackendRef is a reference to a backend to forward matched requests to. If both BackendRef and ServiceName are specified, ServiceName will be given precedence. \n If the referent cannot be found, the route must be dropped from the Gateway. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DegradedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n Support: Custom"
properties:
group:
description: Group is the group of the referent.
@@ -240,14 +248,19 @@ spec:
add:
additionalProperties:
type: string
description: "Add adds the given header (name, value) to the request before the action. \n Input: GET /foo HTTP/1.1 \n Config: add: {\"my-header\": \"foo\"} \n Output: GET /foo HTTP/1.1 my-header: foo \n Support: Extended"
description: "Add adds the given header (name, value) to the request before the action. It appends to any existing values associated with the header name. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: add: {\"my-header\": \"bar\"} \n Output: GET /foo HTTP/1.1 my-header: foo my-header: bar \n Support: Extended"
type: object
remove:
description: "Remove the given header(s) from the HTTP request before the action. The value of RemoveHeader is a list of HTTP header names. Note that the header names are case-insensitive [RFC-2616 4.2]. \n Input: GET /foo HTTP/1.1 My-Header1: ABC My-Header2: DEF My-Header2: GHI \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 My-Header2: DEF \n Support: Extended"
description: "Remove the given header(s) from the HTTP request before the action. The value of RemoveHeader is a list of HTTP header names. Note that the header names are case-insensitive [RFC-2616 4.2]. \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: bar my-header3: baz \n Config: remove: [\"my-header1\", \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: bar \n Support: Extended"
items:
type: string
maxItems: 16
type: array
set:
additionalProperties:
type: string
description: "Set overwrites the request with the given header (name, value) before the action. \n Input: GET /foo HTTP/1.1 my-header: foo \n Config: set: {\"my-header\": \"bar\"} \n Output: GET /foo HTTP/1.1 my-header: bar \n Support: Extended"
type: object
type: object
requestMirror:
description: "RequestMirror defines a schema for a filter that mirrors requests. \n Support: Extended"
@@ -276,7 +289,7 @@ spec:
- name
type: object
port:
description: Port specifies the destination port number to use for the backend referenced by the ServiceName or BackendRef field.
description: "Port specifies the destination port number to use for the backend referenced by the ServiceName or BackendRef field. \n If unspecified, the destination port in the request is used when forwarding to a backendRef or serviceName."
format: int32
maximum: 65535
minimum: 1
@@ -285,8 +298,6 @@ spec:
description: "ServiceName refers to the name of the Service to mirror matched requests to. When specified, this takes the place of BackendRef. If both BackendRef and ServiceName are specified, ServiceName will be given precedence. \n If the referent cannot be found, the rule is not included in the route. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DegradedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n Support: Core"
maxLength: 253
type: string
required:
- port
type: object
type:
description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels: \n - Core: Filter types and their corresponding configuration defined by \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All implementations must support core filters. \n - Extended: Filter types and their corresponding configuration defined by \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers are encouraged to support extended filters. \n - Custom: Filters that are defined and supported by specific vendors. In the future, filters showing convergence in behavior across multiple implementations will be considered for inclusion in extended or core conformance levels. Filter-specific configuration for such filters is specified using the ExtensionRef field. `Type` should be set to \"ExtensionRef\" for custom filters. \n Implementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior."
@@ -301,13 +312,13 @@ spec:
maxItems: 16
type: array
port:
description: "Port specifies the destination port number to use for the backend referenced by the ServiceName or BackendRef field. \n Support: Core"
description: "Port specifies the destination port number to use for the backend referenced by the ServiceName or BackendRef field. If unspecified, the destination port in the request is used when forwarding to a backendRef or serviceName. \n Support: Core"
format: int32
maximum: 65535
minimum: 1
type: integer
serviceName:
description: "ServiceName refers to the name of the Service to forward matched requests to. When specified, this takes the place of BackendRef. If both BackendRef and ServiceName are specified, ServiceName will be given precedence. \n If the referent cannot be found, the route must be dropped from the Gateway. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DroppedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n The protocol to use should be specified with the AppProtocol field on Service resources. This field was introduced in Kubernetes 1.18. If using an earlier version of Kubernetes, a `networking.x-k8s.io/app-protocol` annotation on the BackendPolicy resource may be used to define the protocol. If the AppProtocol field is available, this annotation should not be used. The AppProtocol field, when populated, takes precedence over the annotation in the BackendPolicy resource. For custom backends, it is encouraged to add a semantically-equivalent field in the Custom Resource Definition. \n Support: Core"
description: "ServiceName refers to the name of the Service to forward matched requests to. When specified, this takes the place of BackendRef. If both BackendRef and ServiceName are specified, ServiceName will be given precedence. \n If the referent cannot be found, the route must be dropped from the Gateway. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DegradedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n The protocol to use should be specified with the AppProtocol field on Service resources. This field was introduced in Kubernetes 1.18. If using an earlier version of Kubernetes, a `networking.x-k8s.io/app-protocol` annotation on the BackendPolicy resource may be used to define the protocol. If the AppProtocol field is available, this annotation should not be used. The AppProtocol field, when populated, takes precedence over the annotation in the BackendPolicy resource. For custom backends, it is encouraged to add a semantically-equivalent field in the Custom Resource Definition. \n Support: Core"
maxLength: 253
type: string
weight:
@@ -317,22 +328,20 @@ spec:
maximum: 1000000
minimum: 0
type: integer
required:
- port
type: object
maxItems: 4
maxItems: 16
type: array
matches:
default:
- path:
type: Prefix
value: /
description: "Matches define conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - path: value: \"/foo\" headers: values: version: \"2\" - path: value: \"/v2/foo\" ``` \n For a request to match against this rule, a request should satisfy EITHER of the two conditions: \n - path prefixed with `/foo` AND contains the header `version: \"2\"` - path prefix of `/v2/foo` \n See the documentation for HTTPRouteMatch on how to specify multiple match conditions that should be ANDed together. \n If no matches are specified, the default is a prefix path match on \"/\", which has the effect of matching every HTTP request. \n A client request may match multiple HTTP route rules. Matching precedence MUST be determined in order of the following criteria, continuing on ties: * The longest matching hostname. * The longest matching path. * The largest number of header matches * The oldest Route based on creation timestamp. For example, a Route with a creation timestamp of \"2020-09-08 01:02:03\" is given precedence over a Route with a creation timestamp of \"2020-09-08 01:02:04\". * The Route appearing first in alphabetical order (namespace/name) for example, foo/bar is given precedence over foo/baz."
description: "Matches define conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied. \n For example, take the following matches configuration: \n ``` matches: - path: value: \"/foo\" headers: values: version: \"2\" - path: value: \"/v2/foo\" ``` \n For a request to match against this rule, a request should satisfy EITHER of the two conditions: \n - path prefixed with `/foo` AND contains the header `version: \"2\"` - path prefix of `/v2/foo` \n See the documentation for HTTPRouteMatch on how to specify multiple match conditions that should be ANDed together. \n If no matches are specified, the default is a prefix path match on \"/\", which has the effect of matching every HTTP request. \n A client request may match multiple HTTP route rules. Matching precedence MUST be determined in order of the following criteria, continuing on ties: \n * The longest matching hostname. * The longest matching path. * The largest number of header matches * The oldest Route based on creation timestamp. For example, a Route with a creation timestamp of \"2020-09-08 01:02:03\" is given precedence over a Route with a creation timestamp of \"2020-09-08 01:02:04\". * The Route appearing first in alphabetical order (namespace/name) for example, foo/bar is given precedence over foo/baz."
items:
description: "HTTPRouteMatch defines the predicate used to match requests to a given action. Multiple match types are ANDed together, i.e. the match will evaluate to true only if all conditions are satisfied. \n For example, the match below will match a HTTP request only if its path starts with `/foo` AND it contains the `version: \"1\"` header: \n ``` match: path: value: \"/foo\" headers: values: version: \"1\" ```"
properties:
extensionRef:
description: "ExtensionRef is an optional, implementation-specific extension to the \"match\" behavior. For example, resource \"myroutematcher\" in group \"networking.acme.io\". If the referent cannot be found, the rule is not included in the route. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DegradedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n Support: custom"
description: "ExtensionRef is an optional, implementation-specific extension to the \"match\" behavior. For example, resource \"myroutematcher\" in group \"networking.acme.io\". If the referent cannot be found, the rule is not included in the route. The controller should raise the \"ResolvedRefs\" condition on the Gateway with the \"DegradedRoutes\" reason. The gateway status for this route should be updated with a condition that describes the error more specifically. \n Support: Custom"
properties:
group:
description: Group is the group of the referent.
@@ -359,7 +368,7 @@ spec:
properties:
type:
default: Exact
description: "Type specifies how to match against the value of the header. \n Support: core (Exact) Support: custom (RegularExpression, ImplementationSpecific) \n Since RegularExpression PathType has custom conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect. \n HTTP Header name matching MUST be case-insensitive (RFC 2616 - section 4.2)."
description: "Type specifies how to match against the value of the header. \n Support: Core (Exact) \n Support: Custom (RegularExpression, ImplementationSpecific) \n Since RegularExpression PathType has custom conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect. \n HTTP Header name matching MUST be case-insensitive (RFC 2616 - section 4.2)."
enum:
- Exact
- RegularExpression
@@ -381,7 +390,7 @@ spec:
properties:
type:
default: Prefix
description: "Type specifies how to match against the path Value. \n Support: core (Exact, Prefix) Support: custom (RegularExpression, ImplementationSpecific) \n Since RegularExpression PathType has custom conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect."
description: "Type specifies how to match against the path Value. \n Support: Core (Exact, Prefix) \n Support: Custom (RegularExpression, ImplementationSpecific) \n Since RegularExpression PathType has custom conformance, implementations can support POSIX, PCRE or any other dialects of regular expressions. Please read the implementation's documentation to determine the supported dialect."
enum:
- Exact
- Prefix
@@ -400,13 +409,12 @@ spec:
type: array
type: object
maxItems: 16
minItems: 1
type: array
tls:
description: "TLS defines the TLS certificate to use for Hostnames defined in this Route. This configuration only takes effect if the AllowRouteOverride field is set to true in the associated Gateway resource. \n Collisions can happen if multiple HTTPRoutes define a TLS certificate for the same hostname. In such a case, conflict resolution guiding principles apply, specificallly, if hostnames are same and two different certificates are specified then the certificate in the oldest resource wins. \n Please note that HTTP Route-selection takes place after the TLS Handshake (ClientHello). Due to this, TLS certificate defined here will take precedence even if the request has the potential to match multiple routes (in case multiple HTTPRoutes share the same hostname). \n Support: Core"
description: "TLS defines the TLS certificate to use for Hostnames defined in this Route. This configuration only takes effect if the AllowRouteOverride field is set to true in the associated Gateway resource. \n Collisions can happen if multiple HTTPRoutes define a TLS certificate for the same hostname. In such a case, conflict resolution guiding principles apply, specifically, if hostnames are same and two different certificates are specified then the certificate in the oldest resource wins. \n Please note that HTTP Route-selection takes place after the TLS Handshake (ClientHello). Due to this, TLS certificate defined here will take precedence even if the request has the potential to match multiple routes (in case multiple HTTPRoutes share the same hostname). \n Support: Core"
properties:
certificateRef:
description: 'CertificateRef refers to a Kubernetes object that contains a TLS certificate and private key. This certificate MUST be used for TLS handshakes for the domain this RouteTLSConfig is associated with. If an entry in this list omits or specifies the empty string for both the group and kind, the resource defaults to "secrets". An implementation may support other resources (for example, resource "mycertificates" in group "networking.acme.io"). Support: Core (Kubernetes Secrets) Support: Implementation-specific (Other resource types)'
description: "CertificateRef refers to a Kubernetes object that contains a TLS certificate and private key. This certificate MUST be used for TLS handshakes for the domain this RouteTLSConfig is associated with. If an entry in this list omits or specifies the empty string for both the group and kind, the resource defaults to \"secrets\". An implementation may support other resources (for example, resource \"mycertificates\" in group \"networking.acme.io\"). \n Support: Core (Kubernetes Secrets) \n Support: Implementation-specific (Other resource types)"
properties:
group:
description: Group is the group of the referent.
@@ -431,19 +439,17 @@ spec:
required:
- certificateRef
type: object
required:
- rules
type: object
status:
description: HTTPRouteStatus defines the observed state of HTTPRoute.
description: Status defines the current state of HTTPRoute.
properties:
gateways:
description: "Gateways is a list of the Gateways that are associated with the route, and the status of the route with respect to each of these Gateways. When a Gateway selects this route, the controller that manages the Gateway should add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route is modified. \n A maximum of 100 Gateways will be represented in this list. If this list is full, there may be additional Gateways using this Route that are not included in the list."
description: "Gateways is a list of Gateways that are associated with the route, and the status of the route with respect to each Gateway. When a Gateway selects this route, the controller that manages the Gateway must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route is modified. \n A maximum of 100 Gateways will be represented in this list. If this list is full, there may be additional Gateways using this Route that are not included in the list. An empty list means the route has not been admitted by any Gateway."
items:
description: RouteGatewayStatus describes the status of a route with respect to an associated Gateway.
properties:
conditions:
description: Conditions describes the status of the route with respect to the Gateway. For example, the "Admitted" condition indicates whether the route has been admitted or rejected by the Gateway, and why. Note that the route's availability is also subject to the Gateway's own status conditions and listener status.
description: Conditions describes the status of the route with respect to the Gateway. The "Admitted" condition must always be specified by controllers to indicate whether the route has been admitted or rejected by the Gateway, and why. Note that the route's availability is also subject to the Gateway's own status conditions and listener status.
items:
description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:

View File

@@ -184,7 +184,7 @@ plugin's module name.
plugin's version.
`--global.checknewversion`:
Periodically check if a new version has been released. (Default: ```false```)
Periodically check if a new version has been released. (Default: ```true```)
`--global.sendanonymoususage`:
Periodically send anonymous usage statistics. If the option is not specified, it will be enabled by default. (Default: ```false```)
@@ -294,6 +294,9 @@ Prefix to use for metrics collection. (Default: ```traefik```)
`--metrics.statsd.pushinterval`:
StatsD push interval. (Default: ```10```)
`--pilot.dashboard`:
Enable Traefik Pilot in the dashboard. (Default: ```true```)
`--pilot.token`:
Traefik Pilot token.
@@ -694,7 +697,7 @@ Display additional provider logs. (Default: ```false```)
Watch provider. (Default: ```true```)
`--providers.providersthrottleduration`:
Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time. (Default: ```0```)
Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time. (Default: ```2```)
`--providers.rancher`:
Enable Rancher backend with default settings. (Default: ```false```)
@@ -802,7 +805,7 @@ The amount of time to wait for a server's response headers after fully writing t
Disable SSL certificate verification. (Default: ```false```)
`--serverstransport.maxidleconnsperhost`:
If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used (Default: ```0```)
If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used (Default: ```200```)
`--serverstransport.rootcas`:
Add cert file for self-signed certificate.

View File

@@ -184,7 +184,7 @@ plugin's module name.
plugin's version.
`TRAEFIK_GLOBAL_CHECKNEWVERSION`:
Periodically check if a new version has been released. (Default: ```false```)
Periodically check if a new version has been released. (Default: ```true```)
`TRAEFIK_GLOBAL_SENDANONYMOUSUSAGE`:
Periodically send anonymous usage statistics. If the option is not specified, it will be enabled by default. (Default: ```false```)
@@ -294,6 +294,9 @@ Prefix to use for metrics collection. (Default: ```traefik```)
`TRAEFIK_METRICS_STATSD_PUSHINTERVAL`:
StatsD push interval. (Default: ```10```)
`TRAEFIK_PILOT_DASHBOARD`:
Enable Traefik Pilot in the dashboard. (Default: ```true```)
`TRAEFIK_PILOT_TOKEN`:
Traefik Pilot token.
@@ -694,7 +697,7 @@ Display additional provider logs. (Default: ```false```)
Watch provider. (Default: ```true```)
`TRAEFIK_PROVIDERS_PROVIDERSTHROTTLEDURATION`:
Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time. (Default: ```0```)
Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time. (Default: ```2```)
`TRAEFIK_PROVIDERS_RANCHER`:
Enable Rancher backend with default settings. (Default: ```false```)
@@ -802,7 +805,7 @@ The amount of time to wait for a server's response headers after fully writing t
Disable SSL certificate verification. (Default: ```false```)
`TRAEFIK_SERVERSTRANSPORT_MAXIDLECONNSPERHOST`:
If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used (Default: ```0```)
If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used (Default: ```200```)
`TRAEFIK_SERVERSTRANSPORT_ROOTCAS`:
Add cert file for self-signed certificate.

View File

@@ -132,10 +132,11 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport) for more information.
```yaml
traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar
traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar@file
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"

View File

@@ -287,10 +287,11 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport) for more information.
```yaml
- "traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar"
- "traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar@file"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"

View File

@@ -135,10 +135,11 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport) for more information.
```yaml
traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar
traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar@file
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"

View File

@@ -292,15 +292,16 @@ The Kubernetes Ingress Controller, The Custom Resource Way.
You can find an excerpt of the available custom resources in the table below:
| Kind | Purpose | Concept Behind |
|------------------------------------------|---------------------------------------------------------------|----------------------------------------------------------------|
| [IngressRoute](#kind-ingressroute) | HTTP Routing | [HTTP router](../routers/index.md#configuring-http-routers) |
| [Middleware](#kind-middleware) | Tweaks the HTTP requests before they are sent to your service | [HTTP Middlewares](../../middlewares/overview.md) |
| [TraefikService](#kind-traefikservice) | Abstraction for HTTP loadbalancing/mirroring | [HTTP service](../services/index.md#configuring-http-services) |
| [IngressRouteTCP](#kind-ingressroutetcp) | TCP Routing | [TCP router](../routers/index.md#configuring-tcp-routers) |
| [IngressRouteUDP](#kind-ingressrouteudp) | UDP Routing | [UDP router](../routers/index.md#configuring-udp-routers) |
| [TLSOptions](#kind-tlsoption) | Allows to configure some parameters of the TLS connection | [TLSOptions](../../https/tls.md#tls-options) |
| [TLSStores](#kind-tlsstore) | Allows to configure the default TLS store | [TLSStores](../../https/tls.md#certificates-stores) |
| Kind | Purpose | Concept Behind |
|--------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------------------|
| [IngressRoute](#kind-ingressroute) | HTTP Routing | [HTTP router](../routers/index.md#configuring-http-routers) |
| [Middleware](#kind-middleware) | Tweaks the HTTP requests before they are sent to your service | [HTTP Middlewares](../../middlewares/overview.md) |
| [TraefikService](#kind-traefikservice) | Abstraction for HTTP loadbalancing/mirroring | [HTTP service](../services/index.md#configuring-http-services) |
| [IngressRouteTCP](#kind-ingressroutetcp) | TCP Routing | [TCP router](../routers/index.md#configuring-tcp-routers) |
| [IngressRouteUDP](#kind-ingressrouteudp) | UDP Routing | [UDP router](../routers/index.md#configuring-udp-routers) |
| [TLSOptions](#kind-tlsoption) | Allows to configure some parameters of the TLS connection | [TLSOptions](../../https/tls.md#tls-options) |
| [TLSStores](#kind-tlsstore) | Allows to configure the default TLS store | [TLSStores](../../https/tls.md#certificates-stores) |
| [ServersTransport](#kind-serverstransport) | Allows to configure the transport between Traefik and the backends | [ServersTransport](../../services/#serverstransport_1) |
### Kind: `IngressRoute`

View File

@@ -28,21 +28,21 @@ The Kubernetes Gateway API, The Experimental Way.
### Custom Resource Definition (CRD)
* You can find an exhaustive list, of the custom resources and their attributes in
[the reference page](../../reference/dynamic-configuration/kubernetes-gateway.md) or in the Kubernetes Sigs `Service APIs` [repository](https://github.com/kubernetes-sigs/service-apis/).
[the reference page](../../reference/dynamic-configuration/kubernetes-gateway.md) or in the Kubernetes Sigs `Gateway API` [repository](https://github.com/kubernetes-sigs/gateway-api).
* Validate that [the prerequisites](../../providers/kubernetes-gateway.md#configuration-requirements) are fulfilled before using the Traefik Kubernetes Gateway Provider.
You can find an excerpt of the supported Kubernetes Gateway API resources in the table below:
| Kind | Purpose | Concept Behind |
|------------------------------------|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
| [GatewayClass](#kind-gatewayclass) | Defines a set of Gateways that share a common configuration and behaviour | [GatewayClass](https://kubernetes-sigs.github.io/gateway-api/api-overview/#gatewayclass) |
| [Gateway](#kind-gateway) | Describes how traffic can be translated to Services within the cluster | [Gateway](https://kubernetes-sigs.github.io/gateway-api/api-overview/#gateway) |
| [HTTPRoute](#kind-httproute) | HTTP rules for mapping requests from a Gateway to Kubernetes Services | [Route](https://kubernetes-sigs.github.io/gateway-api/api-overview/#httptcpfooroute) |
| Kind | Purpose | Concept Behind |
|------------------------------------|---------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| [GatewayClass](#kind-gatewayclass) | Defines a set of Gateways that share a common configuration and behaviour | [GatewayClass](https://gateway-api.sigs.k8s.io/api-overview/#gatewayclass) |
| [Gateway](#kind-gateway) | Describes how traffic can be translated to Services within the cluster | [Gateway](https://gateway-api.sigs.k8s.io/api-overview/#gateway) |
| [HTTPRoute](#kind-httproute) | HTTP rules for mapping requests from a Gateway to Kubernetes Services | [Route](https://gateway-api.sigs.k8s.io/api-overview/#httptcpfooroute) |
### Kind: `GatewayClass`
`GatewayClass` is cluster-scoped resource defined by the infrastructure provider. This resource represents a class of Gateways that can be instantiated.
More details on the GatewayClass [official documentation](https://kubernetes-sigs.github.io/gateway-api/gatewayclass/).
More details on the GatewayClass [official documentation](https://gateway-api.sigs.k8s.io/gatewayclass/).
The `GatewayClass` should be declared by the infrastructure provider, otherwise please register the `GatewayClass`
[definition](../../reference/dynamic-configuration/kubernetes-gateway.md#definitions) in the Kubernetes cluster before
@@ -65,7 +65,7 @@ creating `GatewayClass` objects.
A `Gateway` is 1:1 with the life cycle of the configuration of infrastructure. When a user creates a Gateway,
some load balancing infrastructure is provisioned or configured by the GatewayClass controller.
More details on the Gateway [official documentation](https://kubernetes-sigs.github.io/gateway-api/gateway/).
More details on the Gateway [official documentation](https://gateway-api.sigs.k8s.io/gateway/).
Register the `Gateway` [definition](../../reference/dynamic-configuration/kubernetes-gateway.md#definitions) in the
Kubernetes cluster before creating `Gateway` objects.

View File

@@ -112,11 +112,12 @@ A Story of key & values
??? info "`traefik/http/services/<service_name>/loadbalancer/serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport) for more information.
| Key (Path) | Value |
|-----------------------------------------------------------------|----------|
| `traefik/http/services/myservice/loadbalancer/serverstransport` | `foobar` |
| Key (Path) | Value |
|-----------------------------------------------------------------|---------------|
| `traefik/http/services/myservice/loadbalancer/serverstransport` | `foobar@file` |
??? info "`traefik/http/services/<service_name>/loadbalancer/passhostheader`"

View File

@@ -161,11 +161,12 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi
```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport) for more information.
```json
"traefik.http.services.<service_name>.loadbalancer.serverstransport": "foobar"
"traefik.http.services.<service_name>.loadbalancer.serverstransport": "foobar@file"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"

View File

@@ -168,10 +168,11 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport) for more information.
```yaml
- "traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar"
- "traefik.http.services.<service_name>.loadbalancer.serverstransport=foobar@file"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"

View File

@@ -235,16 +235,22 @@ The table below lists all the available matchers:
| ```Host(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. |
| ```HostHeader(`example.com`, ...)``` | Check if the request domain (host header value) targets one of the given `domains`. |
| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)``` | Check if the request domain matches the given `regexp`. |
| ```Method(`GET`, ...)``` | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`) |
| ```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. It accepts a sequence of literal and regular expression paths. |
| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`)``` | Match request prefix path. It accepts a sequence of literal and regular expression prefix paths. |
| ```Query(`foo=bar`, `bar=baz`)``` | Match Query String parameters. It accepts a sequence of key=value pairs. |
!!! important "Non-ASCII Domain Names"
Non-ASCII characters are not supported in `Host` and `HostRegexp` expressions, and by doing so the associated router will be invalid.
For the `Host` expression, domain names containing non-ASCII characters must be provided as punycode encoded values ([rfc 3492](https://tools.ietf.org/html/rfc3492)).
As well, when using the `HostRegexp` expressions, in order to match domain names containing non-ASCII characters, the regular expression should match a punycode encoded domain name.
!!! important "Regexp Syntax"
In order to use regular expressions with `Host` and `Path` expressions,
you must declare an arbitrarily named variable followed by the colon-separated regular expression, all enclosed in curly braces.
Any pattern supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used (example: `/posts/{id:[0-9]+}`).
`HostRegexp` and `Path` accept an expression with zero or more groups enclosed by curly braces.
Named groups can be like `{name:pattern}` that matches the given regexp pattern or like `{name}` that matches anything until the next dot.
Any pattern supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used (example: `{subdomain:[a-z]+}.{domain}.com`).
!!! info "Combining Matchers Using Operators and Parenthesis"
@@ -782,6 +788,11 @@ If you want to limit the router scope to a set of entry points, set the entry po
|--------------------------------|-------------------------------------------------------------------------|
| ```HostSNI(`domain-1`, ...)``` | Check if the Server Name Indication corresponds to the given `domains`. |
!!! important "Non-ASCII Domain Names"
Non-ASCII characters are not supported in the `HostSNI` expression, and by doing so the associated TCP router will be invalid.
Domain names containing non-ASCII characters must be provided as punycode encoded values ([rfc 3492](https://tools.ietf.org/html/rfc3492)).
!!! important "HostSNI & TLS"
It is important to note that the Server Name Indication is an extension of the TLS protocol.

View File

@@ -332,7 +332,7 @@ Below are the available options for the health check mechanism:
!!! info "Recovering Servers"
Traefik keeps monitoring the health of unhealthy servers.
If a server has recovered (returning `2xx` -> `3xx` responses again), it will be added back to the load balacer rotation pool.
If a server has recovered (returning `2xx` -> `3xx` responses again), it will be added back to the load balancer rotation pool.
!!! warning "Health check in Kubernetes"

View File

@@ -12,7 +12,7 @@ RUN npm install
RUN npm run build
# BUILD
FROM golang:1.15-alpine as gobuild
FROM golang:1.16-alpine as gobuild
RUN apk --update upgrade \
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar ca-certificates tzdata \

46
go.mod
View File

@@ -1,7 +1,8 @@
module github.com/traefik/traefik/v2
go 1.15
go 1.16
// github.com/docker/docker v17.12.0-ce-rc1.0.20200204220554-5f6d6f3f2203+incompatible => v19.03.6
require (
github.com/BurntSushi/toml v0.3.1
github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61
@@ -11,15 +12,15 @@ require (
github.com/Shopify/sarama v1.23.1 // indirect
github.com/abbot/go-http-auth v0.0.0-00010101000000-000000000000
github.com/abronan/valkeyrie v0.0.0-20200127174252-ef4277a138cd
github.com/aws/aws-sdk-go v1.30.20
github.com/cenkalti/backoff/v4 v4.0.2
github.com/aws/aws-sdk-go v1.37.27
github.com/cenkalti/backoff/v4 v4.1.0
github.com/containerd/containerd v1.3.2 // indirect
github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/davecgh/go-spew v1.1.1
github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0
github.com/docker/docker v17.12.0-ce-rc1.0.20200204220554-5f6d6f3f2203+incompatible
github.com/docker/docker-credential-helpers v0.6.3 // indirect
github.com/docker/go-connections v0.4.0
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 // indirect
@@ -31,10 +32,10 @@ require (
github.com/fatih/structs v1.1.0
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
github.com/go-acme/lego/v4 v4.2.0
github.com/go-acme/lego/v4 v4.3.1
github.com/go-check/check v0.0.0-00010101000000-000000000000
github.com/go-kit/kit v0.10.1-0.20200915143503-439c4d2ed3ea
github.com/golang/protobuf v1.4.2
github.com/golang/protobuf v1.4.3
github.com/google/go-github/v28 v28.1.1
github.com/gorilla/mux v1.7.3
github.com/gorilla/websocket v1.4.2
@@ -46,9 +47,8 @@ require (
github.com/libkermit/compose v0.0.0-20171122111507-c04e39c026ad
github.com/libkermit/docker v0.0.0-20171122101128-e6674d32b807
github.com/libkermit/docker-check v0.0.0-20171122104347-1113af38e591
github.com/magiconair/properties v1.8.1 // indirect
github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f
github.com/miekg/dns v1.1.31
github.com/miekg/dns v1.1.40
github.com/mitchellh/copystructure v1.0.0
github.com/mitchellh/hashstructure v1.0.0
github.com/mitchellh/mapstructure v1.3.3
@@ -61,9 +61,9 @@ require (
github.com/openzipkin/zipkin-go v0.2.2
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/philhofer/fwd v1.0.0 // indirect
github.com/pires/go-proxyproto v0.3.1
github.com/pires/go-proxyproto v0.5.0
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang v1.3.0
github.com/prometheus/client_golang v1.7.1
github.com/prometheus/client_model v0.2.0
github.com/rancher/go-rancher-metadata v0.0.0-20200311180630-7f4c936a06ac
github.com/sirupsen/logrus v1.7.0
@@ -71,36 +71,32 @@ require (
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
github.com/tinylib/msgp v1.0.2 // indirect
github.com/traefik/gziphandler v1.1.2-0.20210212101304-175e0fad6888
github.com/traefik/paerser v0.1.1
github.com/traefik/yaegi v0.9.8
github.com/traefik/paerser v0.1.2
github.com/traefik/yaegi v0.9.13
github.com/uber/jaeger-client-go v2.25.0+incompatible
github.com/uber/jaeger-lib v2.2.0+incompatible
github.com/unrolled/render v1.0.2
github.com/unrolled/secure v1.0.7
github.com/vdemeester/shakers v0.1.0
github.com/vulcand/oxy v1.1.0
github.com/vulcand/oxy v1.2.0
github.com/vulcand/predicate v1.1.0
go.elastic.co/apm v1.7.0
go.elastic.co/apm/module/apmot v1.7.0
golang.org/x/mod v0.3.0
golang.org/x/net v0.0.0-20200904194848-62affa334b73
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
google.golang.org/grpc v1.27.1
gopkg.in/DataDog/dd-trace-go.v1 v1.19.0
gopkg.in/fsnotify.v1 v1.4.7
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
k8s.io/api v0.19.2
k8s.io/apimachinery v0.19.2
k8s.io/client-go v0.19.2
k8s.io/code-generator v0.19.2
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/api v0.20.2
k8s.io/apimachinery v0.20.2
k8s.io/client-go v0.20.2
k8s.io/code-generator v0.20.2
mvdan.cc/xurls/v2 v2.1.0
sigs.k8s.io/service-apis v0.1.0
sigs.k8s.io/gateway-api v0.2.0
)
// Docker v19.03.6
replace github.com/docker/docker => github.com/docker/engine v1.4.2-0.20200204220554-5f6d6f3f2203
// Containous forks
replace (
github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e

413
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ import (
"crypto/rand"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strconv"
@@ -58,7 +57,7 @@ func (s *AccessLogSuite) TestAccessLog(c *check.C) {
defer display(c)
defer func() {
traefikLog, err := ioutil.ReadFile(traefikTestLogFile)
traefikLog, err := os.ReadFile(traefikTestLogFile)
c.Assert(err, checker.IsNil)
log.WithoutContext().Info(string(traefikLog))
}()
@@ -545,7 +544,7 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontendSuccess(c *check.C) {
}
func checkNoOtherTraefikProblems(c *check.C) {
traefikLog, err := ioutil.ReadFile(traefikTestLogFile)
traefikLog, err := os.ReadFile(traefikTestLogFile)
c.Assert(err, checker.IsNil)
if len(traefikLog) > 0 {
fmt.Printf("%s\n", string(traefikLog))
@@ -583,7 +582,7 @@ func checkAccessLogExactValuesOutput(c *check.C, values []accessLogValue) int {
}
func extractLines(c *check.C) []string {
accessLog, err := ioutil.ReadFile(traefikTestAccessLogFile)
accessLog, err := os.ReadFile(traefikTestAccessLogFile)
c.Assert(err, checker.IsNil)
lines := strings.Split(string(accessLog), "\n")
@@ -613,7 +612,7 @@ func ensureWorkingDirectoryIsClean() {
}
func checkTraefikStarted(c *check.C) []byte {
traefikLog, err := ioutil.ReadFile(traefikTestLogFile)
traefikLog, err := os.ReadFile(traefikTestLogFile)
c.Assert(err, checker.IsNil)
if len(traefikLog) > 0 {
fmt.Printf("%s\n", string(traefikLog))
@@ -663,7 +662,7 @@ func waitForTraefik(c *check.C, containerName string) {
func displayTraefikLogFile(c *check.C, path string) {
if c.Failed() {
if _, err := os.Stat(path); !os.IsNotExist(err) {
content, errRead := ioutil.ReadFile(path)
content, errRead := os.ReadFile(path)
fmt.Printf("%s: Traefik logs: \n", c.TestName())
if errRead == nil {
fmt.Println(content)

View File

@@ -4,7 +4,6 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -67,7 +66,7 @@ func setupPebbleRootCA() (*http.Transport, error) {
os.Setenv("LEGO_CA_CERTIFICATES", path)
os.Setenv("LEGO_CA_SERVER_NAME", "pebble")
customCAs, err := ioutil.ReadFile(path)
customCAs, err := os.ReadFile(path)
if err != nil {
return nil, err
}

View File

@@ -3,7 +3,6 @@ package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -138,11 +137,11 @@ func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
expectedJSON := filepath.FromSlash("testdata/rawdata-consul.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0o666)
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {

View File

@@ -3,7 +3,7 @@ package integration
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"os"
"strings"
@@ -135,7 +135,7 @@ func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
var version map[string]interface{}
@@ -228,7 +228,7 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
var version map[string]interface{}
@@ -307,7 +307,7 @@ func (s *DockerSuite) TestRestartDockerContainers(c *check.C) {
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
var version map[string]interface{}

View File

@@ -3,7 +3,6 @@ package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -138,11 +137,11 @@ func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
expectedJSON := filepath.FromSlash("testdata/rawdata-etcd.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0o666)
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ import (
"crypto/tls"
"crypto/x509"
"errors"
"io/ioutil"
"math/rand"
"net"
"os"
@@ -35,9 +34,9 @@ type myserver struct {
func (s *GRPCSuite) SetUpSuite(c *check.C) {
var err error
LocalhostCert, err = ioutil.ReadFile("./resources/tls/local.cert")
LocalhostCert, err = os.ReadFile("./resources/tls/local.cert")
c.Assert(err, check.IsNil)
LocalhostKey, err = ioutil.ReadFile("./resources/tls/local.key")
LocalhostKey, err = os.ReadFile("./resources/tls/local.key")
c.Assert(err, check.IsNil)
}
@@ -112,7 +111,7 @@ func callHelloClientGRPC(name string, secure bool) (string, error) {
} else {
client, closer, err = getHelloClientGRPCh2c()
}
defer closer()
defer func() { _ = closer() }()
if err != nil {
return "", err
@@ -139,6 +138,7 @@ func callStreamExampleClientGRPC() (helloworld.Greeter_StreamExampleClient, func
func (s *GRPCSuite) TestGRPC(c *check.C) {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
@@ -181,6 +181,7 @@ func (s *GRPCSuite) TestGRPC(c *check.C) {
func (s *GRPCSuite) TestGRPCh2c(c *check.C) {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
@@ -219,6 +220,7 @@ func (s *GRPCSuite) TestGRPCh2c(c *check.C) {
func (s *GRPCSuite) TestGRPCh2cTermination(c *check.C) {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
@@ -261,6 +263,7 @@ func (s *GRPCSuite) TestGRPCh2cTermination(c *check.C) {
func (s *GRPCSuite) TestGRPCInsecure(c *check.C) {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
@@ -340,7 +343,7 @@ func (s *GRPCSuite) TestGRPCBuffer(c *check.C) {
c.Assert(err, check.IsNil)
var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC()
defer closer()
defer func() { _ = closer() }()
c.Assert(err, check.IsNil)
received := make(chan bool)
@@ -400,8 +403,10 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC()
defer closer()
defer func() { stopStreamExample <- true }()
defer func() {
_ = closer()
stopStreamExample <- true
}()
c.Assert(err, check.IsNil)
received := make(chan bool)
@@ -425,6 +430,7 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
func (s *GRPCSuite) TestGRPCWithRetry(c *check.C) {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)

View File

@@ -5,7 +5,6 @@ import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"net"
"os"
"os/exec"
@@ -143,7 +142,7 @@ func (s *BaseSuite) traefikCmd(args ...string) (*exec.Cmd, func(*check.C)) {
func (s *BaseSuite) displayLogK3S(c *check.C) {
filePath := "./fixtures/k8s/config.skip/k3s.log"
if _, err := os.Stat(filePath); err == nil {
content, errR := ioutil.ReadFile(filePath)
content, errR := os.ReadFile(filePath)
if errR != nil {
log.WithoutContext().Error(errR)
}
@@ -178,7 +177,7 @@ func (s *BaseSuite) adaptFile(c *check.C, path string, tempObjects interface{})
c.Assert(err, checker.IsNil)
folder, prefix := filepath.Split(path)
tmpFile, err := ioutil.TempFile(folder, strings.TrimSuffix(prefix, filepath.Ext(prefix))+"_*"+filepath.Ext(prefix))
tmpFile, err := os.CreateTemp(folder, strings.TrimSuffix(prefix, filepath.Ext(prefix))+"_*"+filepath.Ext(prefix))
c.Assert(err, checker.IsNil)
defer tmpFile.Close()

View File

@@ -7,7 +7,6 @@ import (
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -153,14 +152,14 @@ func testConfiguration(c *check.C, path, apiPort string) {
newJSON, err := json.MarshalIndent(rtRepr, "", "\t")
c.Assert(err, checker.IsNil)
err = ioutil.WriteFile(expectedJSON, newJSON, 0o644)
err = os.WriteFile(expectedJSON, newJSON, 0o644)
c.Assert(err, checker.IsNil)
c.Errorf("We do not want a passing test in file update mode")
}
func matchesConfig(wantConfig string, buf *bytes.Buffer) try.ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
@@ -187,7 +186,7 @@ func matchesConfig(wantConfig string, buf *bytes.Buffer) try.ResponseCondition {
return err
}
expected, err := ioutil.ReadFile(wantConfig)
expected, err := os.ReadFile(wantConfig)
if err != nil {
return err
}

View File

@@ -4,7 +4,6 @@ package integration
import (
"bufio"
"io/ioutil"
"net/http"
"os"
"strings"
@@ -130,14 +129,14 @@ func (s *LogRotationSuite) TestTraefikLogRotation(c *check.C) {
}
func logAccessLogFile(c *check.C, fileName string) {
output, err := ioutil.ReadFile(fileName)
output, err := os.ReadFile(fileName)
c.Assert(err, checker.IsNil)
c.Logf("Contents of file %s\n%s", fileName, string(output))
}
func verifyEmptyErrorLog(c *check.C, name string) {
err := try.Do(5*time.Second, func() error {
traefikLog, e2 := ioutil.ReadFile(name)
traefikLog, e2 := os.ReadFile(name)
if e2 != nil {
return e2
}

View File

@@ -3,7 +3,6 @@ package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -138,11 +137,11 @@ func (s *RedisSuite) TestSimpleConfiguration(c *check.C) {
expectedJSON := filepath.FromSlash("testdata/rawdata-redis.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0o666)
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {

View File

@@ -203,10 +203,10 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
}
for _, test := range testCase {
json, err := json.Marshal(test.config)
data, err := json.Marshal(test.config)
c.Assert(err, checker.IsNil)
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/secure/api/providers/rest", bytes.NewReader(json))
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/secure/api/providers/rest", bytes.NewReader(data))
c.Assert(err, checker.IsNil)
response, err := http.DefaultClient.Do(request)

View File

@@ -5,7 +5,7 @@ import (
"crypto/rand"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
@@ -688,7 +688,7 @@ func (s *SimpleSuite) TestWRR(c *check.C) {
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
body, err := ioutil.ReadAll(response.Body)
body, err := io.ReadAll(response.Body)
c.Assert(err, checker.IsNil)
if strings.Contains(string(body), server1) {
@@ -739,7 +739,7 @@ func (s *SimpleSuite) TestWRRSticky(c *check.C) {
req.AddCookie(cookie)
}
body, err := ioutil.ReadAll(response.Body)
body, err := io.ReadAll(response.Body)
c.Assert(err, checker.IsNil)
if strings.Contains(string(body), server1) {
@@ -819,7 +819,7 @@ func (s *SimpleSuite) TestMirrorWithBody(c *check.C) {
c.Assert(err, checker.IsNil)
verifyBody := func(req *http.Request) {
b, _ := ioutil.ReadAll(req.Body)
b, _ := io.ReadAll(req.Body)
switch req.Header.Get("Size") {
case "20":
if !bytes.Equal(b, body20) {
@@ -1030,7 +1030,7 @@ func (s *SimpleSuite) TestContentTypeDisableAutoDetect(c *check.C) {
rw.WriteHeader(http.StatusOK)
data, err := ioutil.ReadFile("fixtures/test.pdf")
data, err := os.ReadFile("fixtures/test.pdf")
c.Assert(err, checker.IsNil)
_, err = rw.Write(data)

View File

@@ -2,7 +2,6 @@ package integration
import (
"crypto/tls"
"io/ioutil"
"net/http"
"os"
"time"
@@ -26,11 +25,11 @@ func (s *TLSClientHeadersSuite) SetUpSuite(c *check.C) {
}
func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) {
rootCertContent, err := ioutil.ReadFile(rootCertPath)
rootCertContent, err := os.ReadFile(rootCertPath)
c.Assert(err, check.IsNil)
serverCertContent, err := ioutil.ReadFile(certPemPath)
serverCertContent, err := os.ReadFile(certPemPath)
c.Assert(err, check.IsNil)
ServerKeyContent, err := ioutil.ReadFile(certKeyPath)
ServerKeyContent, err := os.ReadFile(certKeyPath)
c.Assert(err, check.IsNil)
file := s.adaptFile(c, "fixtures/tlsclientheaders/simple.toml", struct {

View File

@@ -3,7 +3,7 @@ package try
import (
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"reflect"
"strings"
@@ -19,7 +19,7 @@ type ResponseCondition func(*http.Response) error
// The condition returns an error if the request body does not contain all the given strings.
func BodyContains(values ...string) ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
@@ -37,7 +37,7 @@ func BodyContains(values ...string) ResponseCondition {
// The condition returns an error if the request body contain one of the given strings.
func BodyNotContains(values ...string) ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
@@ -55,7 +55,7 @@ func BodyNotContains(values ...string) ResponseCondition {
// The condition returns an error if the request body does not contain one of the given strings.
func BodyContainsOr(values ...string) ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
@@ -73,7 +73,7 @@ func BodyContainsOr(values ...string) ResponseCondition {
// The condition returns an error if the request body does not have body content.
func HasBody() ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}

View File

@@ -120,7 +120,7 @@ func Do(timeout time.Duration, operation DoCondition) error {
fmt.Print("*")
if err = operation(); err == nil {
fmt.Println("+")
return err
return nil
}
}
}

View File

@@ -4,7 +4,6 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/base64"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
@@ -279,7 +278,7 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
// Add client self-signed cert
roots := x509.NewCertPool()
certContent, err := ioutil.ReadFile("./resources/tls/local.cert")
certContent, err := os.ReadFile("./resources/tls/local.cert")
c.Assert(err, checker.IsNil)
roots.AppendCertsFromPEM(certContent)
gorillawebsocket.DefaultDialer.TLSClientConfig = &tls.Config{
@@ -461,8 +460,7 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
}))
ts.TLS = &tls.Config{}
ts.TLS.NextProtos = append(ts.TLS.NextProtos, `h2`)
ts.TLS.NextProtos = append(ts.TLS.NextProtos, `http/1.1`)
ts.TLS.NextProtos = append(ts.TLS.NextProtos, `h2`, `http/1.1`)
ts.StartTLS()
file := s.adaptFile(c, "fixtures/websocket/config_https.toml", struct {
@@ -485,7 +483,7 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
// Add client self-signed cert
roots := x509.NewCertPool()
certContent, err := ioutil.ReadFile("./resources/tls/local.cert")
certContent, err := os.ReadFile("./resources/tls/local.cert")
c.Assert(err, checker.IsNil)
roots.AppendCertsFromPEM(certContent)
gorillawebsocket.DefaultDialer.TLSClientConfig = &tls.Config{

View File

@@ -3,7 +3,6 @@ package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -138,11 +137,11 @@ func (s *ZookeeperSuite) TestSimpleConfiguration(c *check.C) {
expectedJSON := filepath.FromSlash("testdata/rawdata-zk.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0o666)
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {

View File

@@ -14,7 +14,7 @@ import (
"github.com/traefik/paerser/flag"
"github.com/traefik/paerser/generator"
"github.com/traefik/paerser/parser"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/cmd"
"github.com/traefik/traefik/v2/pkg/log"
)
@@ -29,7 +29,7 @@ func main() {
func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
logger := log.WithoutContext().WithField("file", outputFile)
element := &static.Configuration{}
element := &cmd.NewTraefikConfiguration().Configuration
generator.Generate(element)

View File

@@ -40,7 +40,7 @@ func Do(baseConfig interface{}, indent bool) (string, error) {
}
func doOnJSON(input string) string {
mailExp := regexp.MustCompile(`\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3}"`)
mailExp := regexp.MustCompile(`\w[-.\w]*\w@\w[-.\w]*\w\.\w{2,3}"`)
return xurls.Relaxed().ReplaceAllString(mailExp.ReplaceAllString(input, maskLarge+"\""), maskLarge)
}

View File

@@ -2,7 +2,6 @@ package anonymize
import (
"flag"
"io/ioutil"
"os"
"strings"
"testing"
@@ -462,14 +461,14 @@ func TestDo_dynamicConfiguration(t *testing.T) {
},
}
expectedConfiguration, err := ioutil.ReadFile("./testdata/anonymized-dynamic-config.json")
expectedConfiguration, err := os.ReadFile("./testdata/anonymized-dynamic-config.json")
require.NoError(t, err)
cleanJSON, err := Do(config, true)
require.NoError(t, err)
if *updateExpected {
require.NoError(t, ioutil.WriteFile("testdata/anonymized-dynamic-config.json", []byte(cleanJSON), 0666))
require.NoError(t, os.WriteFile("testdata/anonymized-dynamic-config.json", []byte(cleanJSON), 0666))
}
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
@@ -965,14 +964,14 @@ func TestDo_staticConfiguration(t *testing.T) {
},
}
expectedConfiguration, err := ioutil.ReadFile("./testdata/anonymized-static-config.json")
expectedConfiguration, err := os.ReadFile("./testdata/anonymized-static-config.json")
require.NoError(t, err)
cleanJSON, err := Do(config, true)
require.NoError(t, err)
if *updateExpected {
require.NoError(t, ioutil.WriteFile("testdata/anonymized-static-config.json", []byte(cleanJSON), 0666))
require.NoError(t, os.WriteFile("testdata/anonymized-static-config.json", []byte(cleanJSON), 0666))
}
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")

View File

@@ -1,7 +1,7 @@
package anonymize
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -9,12 +9,12 @@ import (
)
func Test_doOnJSON(t *testing.T) {
baseConfiguration, err := ioutil.ReadFile("./testdata/example.json")
baseConfiguration, err := os.ReadFile("./testdata/example.json")
require.NoError(t, err)
anomConfiguration := doOnJSON(string(baseConfiguration))
expectedConfiguration, err := ioutil.ReadFile("./testdata/expected.json")
expectedConfiguration, err := os.ReadFile("./testdata/expected.json")
require.NoError(t, err)
assert.JSONEq(t, string(expectedConfiguration), anomConfiguration)

View File

@@ -33,6 +33,13 @@ func (g DashboardHandler) Append(router *mux.Router) {
Handler(http.StripPrefix("/dashboard/", http.FileServer(g.Assets)))
}
func (g DashboardHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// allow iframes from our domains only
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;")
http.FileServer(g.Assets).ServeHTTP(w, r)
}
func safePrefix(req *http.Request) string {
prefix := req.Header.Get("X-Forwarded-Prefix")
if prefix == "" {

View File

@@ -1,9 +1,12 @@
package api
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -52,3 +55,70 @@ func Test_safePrefix(t *testing.T) {
})
}
}
func Test_ContentSecurityPolicy(t *testing.T) {
testCases := []struct {
desc string
handler DashboardHandler
expected int
}{
{
desc: "OK",
handler: DashboardHandler{
Assets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) {
return []byte{}, nil
},
AssetDir: func(path string) ([]string, error) {
return []string{}, nil
},
},
},
expected: http.StatusOK,
},
{
desc: "Not found",
handler: DashboardHandler{
Assets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) {
return []byte{}, fmt.Errorf("not found")
},
AssetDir: func(path string) ([]string, error) {
return []string{}, fmt.Errorf("not found")
},
},
},
expected: http.StatusNotFound,
},
{
desc: "Internal server error",
handler: DashboardHandler{
Assets: &assetfs.AssetFS{
Asset: func(path string) ([]byte, error) {
return []byte{}, fmt.Errorf("oops")
},
AssetDir: func(path string) ([]string, error) {
return []string{}, fmt.Errorf("oops")
},
},
},
expected: http.StatusInternalServerError,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodGet, "/foobar.html", nil)
rw := httptest.NewRecorder()
test.handler.ServeHTTP(rw, req)
assert.Equal(t, test.expected, rw.Code)
assert.Equal(t, "frame-src 'self' https://traefik.io https://*.traefik.io;", rw.Result().Header.Get("Content-Security-Policy"))
})
}
}

View File

@@ -3,9 +3,10 @@ package api
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
"strconv"
"testing"
@@ -212,7 +213,7 @@ func TestHandler_EntryPoints(t *testing.T) {
}
assert.Equal(t, resp.Header.Get("Content-Type"), "application/json")
contents, err := ioutil.ReadAll(resp.Body)
contents, err := io.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()
@@ -226,11 +227,11 @@ func TestHandler_EntryPoints(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
err = os.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}
data, err := ioutil.ReadFile(test.expected.jsonFile)
data, err := os.ReadFile(test.expected.jsonFile)
require.NoError(t, err)
assert.JSONEq(t, string(data), string(contents))
})

View File

@@ -4,9 +4,10 @@ import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
"strconv"
"testing"
@@ -826,7 +827,7 @@ func TestHandler_HTTP(t *testing.T) {
}
assert.Equal(t, resp.Header.Get("Content-Type"), "application/json")
contents, err := ioutil.ReadAll(resp.Body)
contents, err := io.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()
@@ -840,11 +841,11 @@ func TestHandler_HTTP(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
err = os.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}
data, err := ioutil.ReadFile(test.expected.jsonFile)
data, err := os.ReadFile(test.expected.jsonFile)
require.NoError(t, err)
assert.JSONEq(t, string(data), string(contents))
})

View File

@@ -2,9 +2,10 @@ package api
import (
"encoding/json"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -263,7 +264,7 @@ func TestHandler_Overview(t *testing.T) {
}
assert.Equal(t, resp.Header.Get("Content-Type"), "application/json")
contents, err := ioutil.ReadAll(resp.Body)
contents, err := io.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()
@@ -277,11 +278,11 @@ func TestHandler_Overview(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
err = os.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}
data, err := ioutil.ReadFile(test.expected.jsonFile)
data, err := os.ReadFile(test.expected.jsonFile)
require.NoError(t, err)
assert.JSONEq(t, string(data), string(contents))
})

View File

@@ -3,9 +3,10 @@ package api
import (
"context"
"encoding/json"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -534,7 +535,7 @@ func TestHandler_TCP(t *testing.T) {
assert.Equal(t, resp.Header.Get("Content-Type"), "application/json")
contents, err := ioutil.ReadAll(resp.Body)
contents, err := io.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()
@@ -548,11 +549,11 @@ func TestHandler_TCP(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
err = os.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}
data, err := ioutil.ReadFile(test.expected.jsonFile)
data, err := os.ReadFile(test.expected.jsonFile)
require.NoError(t, err)
assert.JSONEq(t, string(data), string(contents))
})

View File

@@ -3,9 +3,10 @@ package api
import (
"encoding/json"
"flag"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -144,7 +145,7 @@ func TestHandler_RawData(t *testing.T) {
assert.Equal(t, test.expected.statusCode, resp.StatusCode)
assert.Equal(t, resp.Header.Get("Content-Type"), "application/json")
contents, err := ioutil.ReadAll(resp.Body)
contents, err := io.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()
@@ -161,11 +162,11 @@ func TestHandler_RawData(t *testing.T) {
newJSON, err := json.MarshalIndent(rtRepr, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.json, newJSON, 0o644)
err = os.WriteFile(test.expected.json, newJSON, 0o644)
require.NoError(t, err)
}
data, err := ioutil.ReadFile(test.expected.json)
data, err := os.ReadFile(test.expected.json)
require.NoError(t, err)
assert.JSONEq(t, string(data), string(contents))
})
@@ -267,7 +268,7 @@ func TestHandler_GetMiddleware(t *testing.T) {
return
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()

View File

@@ -3,9 +3,10 @@ package api
import (
"context"
"encoding/json"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -511,7 +512,7 @@ func TestHandler_UDP(t *testing.T) {
assert.Equal(t, resp.Header.Get("Content-Type"), "application/json")
contents, err := ioutil.ReadAll(resp.Body)
contents, err := io.ReadAll(resp.Body)
require.NoError(t, err)
err = resp.Body.Close()
@@ -525,11 +526,11 @@ func TestHandler_UDP(t *testing.T) {
newJSON, err := json.MarshalIndent(results, "", "\t")
require.NoError(t, err)
err = ioutil.WriteFile(test.expected.jsonFile, newJSON, 0o644)
err = os.WriteFile(test.expected.jsonFile, newJSON, 0o644)
require.NoError(t, err)
}
data, err := ioutil.ReadFile(test.expected.jsonFile)
data, err := os.ReadFile(test.expected.jsonFile)
require.NoError(t, err)
assert.JSONEq(t, string(data), string(contents))
})

View File

@@ -1,7 +1,6 @@
package cli
import (
"io/ioutil"
"os"
"strings"
@@ -56,7 +55,7 @@ func (f *FileLoader) Load(args []string, cmd *cli.Command) (bool, error) {
logger := log.WithoutContext()
logger.Printf("Configuration loaded from file: %s", configFile)
content, _ := ioutil.ReadFile(configFile)
content, _ := os.ReadFile(configFile)
logger.Debug(string(content))
return true, nil
@@ -79,7 +78,7 @@ func loadConfigFiles(configFile string, element interface{}) (string, error) {
return "", nil
}
if err = file.Decode(filePath, element); err != nil {
if err := file.Decode(filePath, element); err != nil {
return "", err
}
return filePath, nil

View File

@@ -4,7 +4,6 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"time"
@@ -446,7 +445,7 @@ func (c *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
if c.CA != "" {
var ca []byte
if _, errCA := os.Stat(c.CA); errCA == nil {
ca, err = ioutil.ReadFile(c.CA)
ca, err = os.ReadFile(c.CA)
if err != nil {
return nil, fmt.Errorf("failed to read CA. %w", err)
}

View File

@@ -2,5 +2,11 @@ package static
// Pilot Configuration related to Traefik Pilot.
type Pilot struct {
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Dashboard bool `description:"Enable Traefik Pilot in the dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty"`
}
// SetDefaults sets the default values.
func (p *Pilot) SetDefaults() {
p.Dashboard = true
}

View File

@@ -231,6 +231,12 @@ func (c *Configuration) SetEffectiveConfiguration() {
c.Global.SendAnonymousUsage = true
}
// Create Pilot struct to apply default value on undefined configuration.
if c.Pilot == nil {
c.Pilot = &Pilot{}
c.Pilot.SetDefaults()
}
// Disable Gateway API provider if not enabled in experimental
if c.Experimental == nil || !c.Experimental.KubernetesGateway {
c.Providers.KubernetesGateway = nil

View File

@@ -24,9 +24,21 @@ func TestJobBackOff(t *testing.T) {
exp.MinJobInterval = testMinJobInterval
exp.Reset()
expectedResults := []time.Duration{500, 500, 500, 1000, 2000, 4000, 5000, 5000, 500, 1000, 2000, 4000, 5000, 5000}
for i, d := range expectedResults {
expectedResults[i] = d * time.Millisecond
expectedResults := []time.Duration{
500 * time.Millisecond,
500 * time.Millisecond,
500 * time.Millisecond,
1 * time.Second,
2 * time.Second,
4 * time.Second,
5 * time.Second,
5 * time.Second,
500 * time.Millisecond,
1 * time.Second,
2 * time.Second,
4 * time.Second,
5 * time.Second,
5 * time.Second,
}
for i, expected := range expectedResults {

View File

@@ -3,7 +3,7 @@ package metrics
import (
"context"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"regexp"
@@ -69,7 +69,7 @@ func TestInfluxDB(t *testing.T) {
func TestInfluxDBHTTP(t *testing.T) {
c := make(chan *string)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "can't read body "+err.Error(), http.StatusBadRequest)
return

View File

@@ -30,7 +30,7 @@ func TestScalableHistogram(t *testing.T) {
measuredDuration, err := time.ParseDuration(extractedDurationString[0] + "ms")
assert.NoError(t, err)
assert.InDelta(t, 500*time.Millisecond, measuredDuration, float64(1*time.Millisecond))
assert.InDelta(t, 500*time.Millisecond, measuredDuration, float64(15*time.Millisecond))
}
func TestNewMultiRegistry(t *testing.T) {

View File

@@ -390,7 +390,7 @@ func newCollector(metricName string, labels stdprometheus.Labels, c stdprometheu
// collector wraps a Collector object from the Prometheus client library.
// It adds information on how many generations this metric should be present
// in the /metrics output, relatived to the time it was last tracked.
// in the /metrics output, relative to the time it was last tracked.
type collector struct {
id string
labels stdprometheus.Labels

View File

@@ -4,7 +4,6 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
@@ -42,9 +41,7 @@ var (
)
func TestLogRotation(t *testing.T) {
tempDir := createTempDir(t, "traefik_")
fileName := filepath.Join(tempDir, "traefik.log")
fileName := filepath.Join(t.TempDir(), "traefik.log")
rotatedFileName := fileName + ".rotated"
config := &types.AccessLog{FilePath: fileName, Format: CommonFormat}
@@ -100,7 +97,7 @@ func TestLogRotation(t *testing.T) {
func lineCount(t *testing.T, fileName string) int {
t.Helper()
fileContents, err := ioutil.ReadFile(fileName)
fileContents, err := os.ReadFile(fileName)
if err != nil {
t.Fatalf("Error reading from file %s: %s", fileName, err)
}
@@ -117,8 +114,6 @@ func lineCount(t *testing.T, fileName string) int {
}
func TestLoggerHeaderFields(t *testing.T) {
tmpDir := createTempDir(t, CommonFormat)
expectedValue := "expectedValue"
testCases := []struct {
@@ -172,7 +167,7 @@ func TestLoggerHeaderFields(t *testing.T) {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
logFile, err := ioutil.TempFile(tmpDir, "*.log")
logFile, err := os.CreateTemp(t.TempDir(), "*.log")
require.NoError(t, err)
config := &types.AccessLog{
@@ -202,7 +197,7 @@ func TestLoggerHeaderFields(t *testing.T) {
writer.WriteHeader(http.StatusOK)
}))
logData, err := ioutil.ReadFile(logFile.Name())
logData, err := os.ReadFile(logFile.Name())
require.NoError(t, err)
if test.expected == types.AccessLogDrop {
@@ -215,13 +210,11 @@ func TestLoggerHeaderFields(t *testing.T) {
}
func TestLoggerCLF(t *testing.T) {
tmpDir := createTempDir(t, CommonFormat)
logFilePath := filepath.Join(tmpDir, logFileNameSuffix)
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
config := &types.AccessLog{FilePath: logFilePath, Format: CommonFormat}
doLogging(t, config)
logData, err := ioutil.ReadFile(logFilePath)
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testRouter" "http://127.0.0.1/testService" 1ms`
@@ -229,13 +222,11 @@ func TestLoggerCLF(t *testing.T) {
}
func TestAsyncLoggerCLF(t *testing.T) {
tmpDir := createTempDir(t, CommonFormat)
logFilePath := filepath.Join(tmpDir, logFileNameSuffix)
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
config := &types.AccessLog{FilePath: logFilePath, Format: CommonFormat, BufferingSize: 1024}
doLogging(t, config)
logData, err := ioutil.ReadFile(logFilePath)
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testRouter" "http://127.0.0.1/testService" 1ms`
@@ -450,9 +441,7 @@ func TestLoggerJSON(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
tmpDir := createTempDir(t, JSONFormat)
logFilePath := filepath.Join(tmpDir, logFileNameSuffix)
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
test.config.FilePath = logFilePath
if test.tls {
@@ -461,7 +450,7 @@ func TestLoggerJSON(t *testing.T) {
doLogging(t, test.config)
}
logData, err := ioutil.ReadFile(logFilePath)
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
jsonData := make(map[string]interface{})
@@ -675,7 +664,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
doLogging(t, test.config)
written, err := ioutil.ReadFile(file.Name())
written, err := os.ReadFile(file.Name())
require.NoError(t, err, "unable to read captured stdout from file")
assertValidLogData(t, test.expectedLog, written)
})
@@ -711,16 +700,16 @@ func assertValidLogData(t *testing.T, expected string, logData []byte) {
assert.Equal(t, resultExpected[OriginContentSize], result[OriginContentSize], formatErrMessage)
assert.Equal(t, resultExpected[RequestRefererHeader], result[RequestRefererHeader], formatErrMessage)
assert.Equal(t, resultExpected[RequestUserAgentHeader], result[RequestUserAgentHeader], formatErrMessage)
assert.Regexp(t, regexp.MustCompile("[0-9]*"), result[RequestCount], formatErrMessage)
assert.Regexp(t, regexp.MustCompile(`\d*`), result[RequestCount], formatErrMessage)
assert.Equal(t, resultExpected[RouterName], result[RouterName], formatErrMessage)
assert.Equal(t, resultExpected[ServiceURL], result[ServiceURL], formatErrMessage)
assert.Regexp(t, regexp.MustCompile("[0-9]*ms"), result[Duration], formatErrMessage)
assert.Regexp(t, regexp.MustCompile(`\d*ms`), result[Duration], formatErrMessage)
}
func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) {
t.Helper()
file, err := ioutil.TempFile("", "testlogger")
file, err := os.CreateTemp("", "testlogger")
require.NoError(t, err, "failed to create temp file")
original := os.Stdout
@@ -734,17 +723,6 @@ func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) {
return file, restoreStdout
}
func createTempDir(t *testing.T, prefix string) string {
t.Helper()
tmpDir, err := ioutil.TempDir("", prefix)
require.NoError(t, err, "failed to create temp dir")
t.Cleanup(func() { _ = os.RemoveAll(tmpDir) })
return tmpDir
}
func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) {
t.Helper()

View File

@@ -1,7 +1,7 @@
package auth
import (
"io/ioutil"
"os"
"strings"
)
@@ -46,7 +46,7 @@ func loadUsers(fileName string, appendUsers []string) ([]string, error) {
}
func getLinesFromFile(filename string) ([]string, error) {
dat, err := ioutil.ReadFile(filename)
dat, err := os.ReadFile(filename)
if err != nil {
return nil, err
}

View File

@@ -3,7 +3,7 @@ package auth
import (
"context"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
@@ -66,7 +66,7 @@ func TestBasicAuthSuccess(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode, "they should be equal")
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
defer res.Body.Close()
@@ -97,7 +97,7 @@ func TestBasicAuthUserHeader(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode)
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
defer res.Body.Close()
@@ -128,7 +128,7 @@ func TestBasicAuthHeaderRemoved(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode)
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -159,7 +159,7 @@ func TestBasicAuthHeaderPresent(t *testing.T) {
assert.Equal(t, http.StatusOK, res.StatusCode)
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -215,9 +215,8 @@ func TestBasicAuthUsersFromFile(t *testing.T) {
t.Parallel()
// Creates the temporary configuration file with the users
usersFile, err := ioutil.TempFile("", "auth-users")
usersFile, err := os.CreateTemp(t.TempDir(), "auth-users")
require.NoError(t, err)
defer os.Remove(usersFile.Name())
_, err = usersFile.Write([]byte(test.userFileContent))
require.NoError(t, err)
@@ -250,7 +249,7 @@ func TestBasicAuthUsersFromFile(t *testing.T) {
require.Equal(t, http.StatusOK, res.StatusCode, "Cannot authenticate user "+userName)
var body []byte
body, err = ioutil.ReadAll(res.Body)
body, err = io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -270,7 +269,7 @@ func TestBasicAuthUsersFromFile(t *testing.T) {
require.Equal(t, `Basic realm="`+test.realm+`"`, res.Header.Get("WWW-Authenticate"))
}
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)

View File

@@ -3,7 +3,7 @@ package auth
import (
"context"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"os"
@@ -93,9 +93,8 @@ func TestDigestAuthUsersFromFile(t *testing.T) {
t.Parallel()
// Creates the temporary configuration file with the users
usersFile, err := ioutil.TempFile("", "auth-users")
usersFile, err := os.CreateTemp(t.TempDir(), "auth-users")
require.NoError(t, err)
defer os.Remove(usersFile.Name())
_, err = usersFile.Write([]byte(test.userFileContent))
require.NoError(t, err)
@@ -127,7 +126,7 @@ func TestDigestAuthUsersFromFile(t *testing.T) {
require.Equal(t, http.StatusOK, res.StatusCode, "Cannot authenticate user "+userName)
var body []byte
body, err = ioutil.ReadAll(res.Body)
body, err = io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -145,7 +144,7 @@ func TestDigestAuthUsersFromFile(t *testing.T) {
require.Equal(t, http.StatusUnauthorized, res.StatusCode)
var body []byte
body, err = ioutil.ReadAll(res.Body)
body, err = io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)

View File

@@ -4,7 +4,7 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"io"
"net"
"net/http"
"regexp"
@@ -126,7 +126,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
body, readError := ioutil.ReadAll(forwardResponse.Body)
body, readError := io.ReadAll(forwardResponse.Body)
if readError != nil {
logMessage := fmt.Sprintf("Error reading body %s. Cause: %s", fa.address, readError)
logger.Debug(logMessage)

View File

@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
@@ -44,7 +43,7 @@ func TestForwardAuthFail(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, res.StatusCode)
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -92,7 +91,7 @@ func TestForwardAuthSuccess(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -134,7 +133,7 @@ func TestForwardAuthRedirect(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "http://example.com/redirect-test", location.String())
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -187,7 +186,7 @@ func TestForwardAuthRemoveHopByHopHeaders(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "http://example.com/redirect-test", location.String(), "they should be equal")
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
assert.NotEmpty(t, string(body), "there should be something in the body")
}
@@ -238,7 +237,7 @@ func TestForwardAuthFailResponseHeaders(t *testing.T) {
assert.Equal(t, value, res.Header[key])
}
body, err := ioutil.ReadAll(res.Body)
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
err = res.Body.Close()
require.NoError(t, err)
@@ -489,5 +488,5 @@ type mockBackend struct {
}
func (b *mockBackend) Setup(componentName string) (opentracing.Tracer, io.Closer, error) {
return b.Tracer, ioutil.NopCloser(nil), nil
return b.Tracer, io.NopCloser(nil), nil
}

View File

@@ -2,7 +2,7 @@ package compress
import (
"context"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"testing"
@@ -205,7 +205,7 @@ func TestIntegrationShouldNotCompress(t *testing.T) {
assert.Equal(t, gzipValue, resp.Header.Get(contentEncodingHeader))
assert.Equal(t, acceptEncodingHeader, resp.Header.Get(varyHeader))
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
assert.EqualValues(t, fakeCompressedBody, body)
})
@@ -287,7 +287,7 @@ func TestIntegrationShouldCompress(t *testing.T) {
assert.Equal(t, gzipValue, resp.Header.Get(contentEncodingHeader))
assert.Equal(t, acceptEncodingHeader, resp.Header.Get(varyHeader))
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
if assert.ObjectsAreEqualValues(body, fakeBody) {
assert.Fail(t, "expected a compressed body", "got %v", body)

View File

@@ -92,39 +92,42 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// check the recorder code against the configured http status code ranges
code := catcher.getCode()
for _, block := range c.httpCodeRanges {
if code >= block[0] && code <= block[1] {
logger.Debugf("Caught HTTP Status Code %d, returning error page", code)
if code < block[0] || code > block[1] {
continue
}
var query string
if len(c.backendQuery) > 0 {
query = "/" + strings.TrimPrefix(c.backendQuery, "/")
query = strings.ReplaceAll(query, "{status}", strconv.Itoa(code))
}
logger.Debugf("Caught HTTP Status Code %d, returning error page", code)
pageReq, err := newRequest(backendURL + query)
if err != nil {
logger.Error(err)
rw.WriteHeader(code)
_, err = fmt.Fprint(rw, http.StatusText(code))
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
return
}
var query string
if len(c.backendQuery) > 0 {
query = "/" + strings.TrimPrefix(c.backendQuery, "/")
query = strings.ReplaceAll(query, "{status}", strconv.Itoa(code))
}
recorderErrorPage := newResponseRecorder(ctx, rw)
utils.CopyHeaders(pageReq.Header, req.Header)
c.backendHandler.ServeHTTP(recorderErrorPage, pageReq.WithContext(req.Context()))
utils.CopyHeaders(rw.Header(), recorderErrorPage.Header())
pageReq, err := newRequest(backendURL + query)
if err != nil {
logger.Error(err)
rw.WriteHeader(code)
if _, err = rw.Write(recorderErrorPage.GetBody().Bytes()); err != nil {
logger.Error(err)
_, err = fmt.Fprint(rw, http.StatusText(code))
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
return
}
recorderErrorPage := newResponseRecorder(ctx, rw)
utils.CopyHeaders(pageReq.Header, req.Header)
c.backendHandler.ServeHTTP(recorderErrorPage, pageReq.WithContext(req.Context()))
utils.CopyHeaders(rw.Header(), recorderErrorPage.Header())
rw.WriteHeader(code)
if _, err = rw.Write(recorderErrorPage.GetBody().Bytes()); err != nil {
logger.Error(err)
}
return
}
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
@@ -279,10 +280,12 @@ func TestRateLimit(t *testing.T) {
// actual default value
burst = 1
}
period := time.Duration(test.config.Period)
if period == 0 {
period = time.Second
}
if test.config.Average == 0 {
if reqCount < 75*test.incomingLoad/100 {
t.Fatalf("we (arbitrarily) expect at least 75%% of the requests to go through with no rate limiting, and yet only %d/%d went through", reqCount, test.incomingLoad)
@@ -297,14 +300,18 @@ func TestRateLimit(t *testing.T) {
// we take into account the configured burst,
// because it also helps absorbing non-bursty traffic.
rate := float64(test.config.Average) / float64(period)
wantCount := int(int64(rate*float64(test.loadDuration)) + burst)
// Allow for a 2% leeway
maxCount := wantCount * 102 / 100
// With very high CPU loads,
// we can expect some extra delay in addition to the rate limiting we already do,
// so we allow for some extra leeway there.
// Feel free to adjust wrt to the load on e.g. the CI.
minCount := wantCount * 95 / 100
minCount := computeMinCount(wantCount)
if reqCount < minCount {
t.Fatalf("rate was slower than expected: %d requests (wanted > %d) in %v", reqCount, minCount, elapsed)
}
@@ -314,3 +321,11 @@ func TestRateLimit(t *testing.T) {
})
}
}
func computeMinCount(wantCount int) int {
if os.Getenv("CI") != "" {
return wantCount * 60 / 100
}
return wantCount * 95 / 100
}

View File

@@ -4,7 +4,7 @@ import (
"bufio"
"context"
"fmt"
"io/ioutil"
"io"
"math"
"net"
"net/http"
@@ -73,12 +73,12 @@ func (r *retry) GetTracingInformation() (string, ext.SpanKindEnum) {
}
func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// if we might make multiple attempts, swap the body for an ioutil.NopCloser
// if we might make multiple attempts, swap the body for an io.NopCloser
// cf https://github.com/traefik/traefik/issues/1008
if r.attempts > 1 {
body := req.Body
defer body.Close()
req.Body = ioutil.NopCloser(body)
req.Body = io.NopCloser(body)
}
attempts := 1

View File

@@ -3,10 +3,10 @@ package retry
import (
"context"
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/http/httptrace"
"strconv"
"strings"
"testing"
"time"
@@ -16,10 +16,7 @@ import (
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/middlewares/emptybackendhandler"
"github.com/traefik/traefik/v2/pkg/testhelpers"
"github.com/vulcand/oxy/forward"
"github.com/vulcand/oxy/roundrobin"
)
func TestRetry(t *testing.T) {
@@ -32,14 +29,14 @@ func TestRetry(t *testing.T) {
}{
{
desc: "no retry on success",
config: dynamic.Retry{Attempts: 1},
config: dynamic.Retry{Attempts: 5},
wantRetryAttempts: 0,
wantResponseStatus: http.StatusOK,
amountFaultyEndpoints: 0,
},
{
desc: "no retry on success with backoff",
config: dynamic.Retry{Attempts: 1, InitialInterval: ptypes.Duration(time.Microsecond * 50)},
config: dynamic.Retry{Attempts: 5, InitialInterval: ptypes.Duration(time.Microsecond * 50)},
wantRetryAttempts: 0,
wantResponseStatus: http.StatusOK,
amountFaultyEndpoints: 0,
@@ -102,42 +99,28 @@ func TestRetry(t *testing.T) {
},
}
backendServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
_, err := rw.Write([]byte("OK"))
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}))
forwarder, err := forward.New()
require.NoError(t, err)
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
loadBalancer, err := roundrobin.New(forwarder)
require.NoError(t, err)
retryAttemps := 0
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
retryAttemps++
// out of range port
basePort := 1133444
for i := 0; i < test.amountFaultyEndpoints; i++ {
// 192.0.2.0 is a non-routable IP for testing purposes.
// See: https://stackoverflow.com/questions/528538/non-routable-ip-address/18436928#18436928
// We only use the port specification here because the URL is used as identifier
// in the load balancer and using the exact same URL would not add a new server.
err = loadBalancer.UpsertServer(testhelpers.MustParseURL("http://192.0.2.0:" + strconv.Itoa(basePort+i)))
require.NoError(t, err)
}
if retryAttemps > test.amountFaultyEndpoints {
// calls WroteHeaders on httptrace.
_ = r.Write(io.Discard)
// add the functioning server to the end of the load balancer list
err = loadBalancer.UpsertServer(testhelpers.MustParseURL(backendServer.URL))
require.NoError(t, err)
rw.WriteHeader(http.StatusOK)
return
}
rw.WriteHeader(http.StatusBadGateway)
})
retryListener := &countingRetryListener{}
retry, err := New(context.Background(), loadBalancer, test.config, retryListener, "traefikTest")
retry, err := New(context.Background(), next, test.config, retryListener, "traefikTest")
require.NoError(t, err)
recorder := httptest.NewRecorder()
@@ -152,15 +135,9 @@ func TestRetry(t *testing.T) {
}
func TestRetryEmptyServerList(t *testing.T) {
forwarder, err := forward.New()
require.NoError(t, err)
loadBalancer, err := roundrobin.New(forwarder)
require.NoError(t, err)
// The EmptyBackend middleware ensures that there is a 503
// response status set when there is no backend server in the pool.
next := emptybackendhandler.New(loadBalancer)
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusServiceUnavailable)
})
retryListener := &countingRetryListener{}
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 3}, retryListener, "traefikTest")
@@ -293,47 +270,29 @@ func TestRetryWebsocket(t *testing.T) {
},
}
forwarder, err := forward.New()
if err != nil {
t.Fatalf("Error creating forwarder: %v", err)
}
backendServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
upgrader := websocket.Upgrader{}
_, err := upgrader.Upgrade(rw, req, nil)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
}))
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
loadBalancer, err := roundrobin.New(forwarder)
if err != nil {
t.Fatalf("Error creating load balancer: %v", err)
}
retryAttemps := 0
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
retryAttemps++
// out of range port
basePort := 1133444
for i := 0; i < test.amountFaultyEndpoints; i++ {
// 192.0.2.0 is a non-routable IP for testing purposes.
// See: https://stackoverflow.com/questions/528538/non-routable-ip-address/18436928#18436928
// We only use the port specification here because the URL is used as identifier
// in the load balancer and using the exact same URL would not add a new server.
_ = loadBalancer.UpsertServer(testhelpers.MustParseURL("http://192.0.2.0:" + strconv.Itoa(basePort+i)))
}
if retryAttemps > test.amountFaultyEndpoints {
upgrader := websocket.Upgrader{}
_, err := upgrader.Upgrade(rw, r, nil)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
}
return
}
// add the functioning server to the end of the load balancer list
err = loadBalancer.UpsertServer(testhelpers.MustParseURL(backendServer.URL))
if err != nil {
t.Fatalf("Fail to upsert server: %v", err)
}
rw.WriteHeader(http.StatusBadGateway)
})
retryListener := &countingRetryListener{}
retryH, err := New(context.Background(), loadBalancer, dynamic.Retry{Attempts: test.maxRequestAttempts}, retryListener, "traefikTest")
retryH, err := New(context.Background(), next, dynamic.Retry{Attempts: test.maxRequestAttempts}, retryListener, "traefikTest")
require.NoError(t, err)
retryServer := httptest.NewServer(retryH)

View File

@@ -27,12 +27,12 @@ func (n MockTracer) Extract(format, carrier interface{}) (opentracing.SpanContex
return nil, opentracing.ErrSpanContextNotFound
}
// MockSpanContext.
// MockSpanContext a span context mock.
type MockSpanContext struct{}
func (n MockSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {}
// MockSpan.
// MockSpan a span mock.
type MockSpan struct {
OpName string
Tags map[string]interface{}

View File

@@ -6,7 +6,7 @@ import (
"encoding/json"
"fmt"
"hash/fnv"
"io/ioutil"
"io"
"net/http"
"time"
@@ -153,7 +153,7 @@ func (c *client) createUUID() (string, error) {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed read response body: %w", err)
}
@@ -236,7 +236,7 @@ func (c *client) sendDataRetryable(ctx context.Context, req *http.Request) error
defer func() { _ = resp.Body.Close() }()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}

View File

@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
@@ -68,7 +67,7 @@ func NewClient(opts ClientOptions) (*Client, error) {
return nil, err
}
goPath, err := ioutil.TempDir(sourcesRootPath, "gop-*")
goPath, err := os.MkdirTemp(sourcesRootPath, "gop-*")
if err != nil {
return nil, fmt.Errorf("failed to create GoPath: %w", err)
}
@@ -197,7 +196,7 @@ func (c *Client) Download(ctx context.Context, pName, pVersion string) (string,
return hash, nil
}
data, _ := ioutil.ReadAll(resp.Body)
data, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("error: %d: %s", resp.StatusCode, string(data))
}
@@ -353,7 +352,7 @@ func (c *Client) WriteState(plugins map[string]Descriptor) error {
return err
}
return ioutil.WriteFile(c.stateFile, mp, 0o600)
return os.WriteFile(c.stateFile, mp, 0o600)
}
// ResetAll resets all plugins related directories.

View File

@@ -63,27 +63,24 @@ func (c *ChallengeTLSALPN) Present(domain, _, keyAuth string) error {
timer := time.NewTimer(c.Timeout)
var errC error
select {
case t := <-timer.C:
timer.Stop()
close(c.chans[string(certPEMBlock)])
c.muChans.Lock()
c.cleanChan(string(certPEMBlock))
c.muChans.Unlock()
err = c.CleanUp(domain, "", keyAuth)
if err != nil {
logger.Errorf("Failed to clean up TLS challenge: %v", err)
}
errC = fmt.Errorf("timeout %s", t)
return fmt.Errorf("timeout %s", t)
case <-ch:
// noop
return nil
}
c.muChans.Lock()
delete(c.chans, string(certPEMBlock))
c.muChans.Unlock()
return errC
}
// CleanUp cleans the challenges when certificate is obtained.
@@ -115,16 +112,23 @@ func (c *ChallengeTLSALPN) Provide(configurationChan chan<- dynamic.Message, _ *
// ListenConfiguration sets a new Configuration into the configurationChan.
func (c *ChallengeTLSALPN) ListenConfiguration(conf dynamic.Configuration) {
c.muChans.Lock()
for _, certificate := range conf.TLS.Certificates {
if !containsACMETLS1(certificate.Stores) {
continue
}
c.muChans.Lock()
if _, ok := c.chans[certificate.CertFile.String()]; ok {
close(c.chans[certificate.CertFile.String()])
}
c.muChans.Unlock()
c.cleanChan(certificate.CertFile.String())
}
c.muChans.Unlock()
}
func (c *ChallengeTLSALPN) cleanChan(key string) {
if _, ok := c.chans[key]; ok {
close(c.chans[key])
delete(c.chans, key)
}
}

View File

@@ -2,7 +2,7 @@ package acme
import (
"encoding/json"
"io/ioutil"
"io"
"os"
"sync"
@@ -60,7 +60,7 @@ func (s *LocalStore) get(resolverName string) (*StoredData, error) {
}
defer f.Close()
file, err := ioutil.ReadAll(f)
file, err := io.ReadAll(f)
if err != nil {
return nil, err
}
@@ -108,7 +108,7 @@ func (s *LocalStore) listenSaveAction() {
logger.Error(err)
}
err = ioutil.WriteFile(s.filename, data, 0o600)
err = os.WriteFile(s.filename, data, 0o600)
if err != nil {
logger.Error(err)
}

View File

@@ -2,7 +2,7 @@ package acme
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
@@ -23,7 +23,7 @@ func TestLocalStore_GetAccount(t *testing.T) {
}
}`, email)
err := ioutil.WriteFile(acmeFile, []byte(filePayload), 0o600)
err := os.WriteFile(acmeFile, []byte(filePayload), 0o600)
require.NoError(t, err)
testCases := []struct {
@@ -68,7 +68,7 @@ func TestLocalStore_SaveAccount(t *testing.T) {
time.Sleep(100 * time.Millisecond)
file, err := ioutil.ReadFile(acmeFile)
file, err := os.ReadFile(acmeFile)
require.NoError(t, err)
expected := `{

View File

@@ -119,10 +119,6 @@ func (p ProviderAggregator) Init() error {
// Provide calls the provide method of every providers.
func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
if p.internalProvider != nil {
launchProvider(configurationChan, pool, p.internalProvider)
}
if p.fileProvider != nil {
launchProvider(configurationChan, pool, p.fileProvider)
}
@@ -134,6 +130,12 @@ func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, po
})
}
// internal provider must be the last because we use it to know if all the providers are loaded.
// ConfigurationWatcher will wait for this requiredProvider before applying configurations.
if p.internalProvider != nil {
launchProvider(configurationChan, pool, p.internalProvider)
}
return nil
}

View File

@@ -32,12 +32,11 @@ func TestProviderAggregator_Provide(t *testing.T) {
errCh <- aggregator.Provide(cfgCh, pool)
}()
// Make sure the internal provider is always called first, followed by the file provider.
requireReceivedMessageFromProviders(t, cfgCh, []string{"internal"})
// Make sure the file provider is always called first.
requireReceivedMessageFromProviders(t, cfgCh, []string{"file"})
// Check if all providers have been called, the order doesn't matter.
requireReceivedMessageFromProviders(t, cfgCh, []string{"salad", "tomato", "onion"})
requireReceivedMessageFromProviders(t, cfgCh, []string{"salad", "tomato", "onion", "internal"})
require.NoError(t, <-errCh)
}
@@ -52,7 +51,8 @@ func requireReceivedMessageFromProviders(t *testing.T, cfgCh <-chan dynamic.Mess
for range names {
select {
case <-time.After(10 * time.Millisecond):
case <-time.After(100 * time.Millisecond):
require.Fail(t, "Timeout while waiting for configuration.")
case msg = <-cfgCh:
receivedMessagesFrom = append(receivedMessagesFrom, msg.ProviderName)
}

View File

@@ -5,7 +5,6 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@@ -197,7 +196,7 @@ func flattenCertificates(ctx context.Context, tlsConfig *dynamic.TLSConfiguratio
}
func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory string, configuration *dynamic.Configuration) (*dynamic.Configuration, error) {
fileList, err := ioutil.ReadDir(directory)
fileList, err := os.ReadDir(directory)
if err != nil {
return configuration, fmt.Errorf("unable to read directory %s: %w", directory, err)
}
@@ -436,7 +435,7 @@ func (p *Provider) decodeConfiguration(filePath, content string) (*dynamic.Confi
func readFile(filename string) (string, error) {
if len(filename) > 0 {
buf, err := ioutil.ReadFile(filename)
buf, err := os.ReadFile(filename)
if err != nil {
return "", err
}

View File

@@ -3,7 +3,6 @@ package file
import (
"context"
"io"
"io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -27,13 +26,12 @@ type ProvideTestCase struct {
}
func TestTLSContent(t *testing.T) {
tempDir := createTempDir(t, "testdir")
defer os.RemoveAll(tempDir)
tempDir := t.TempDir()
fileTLS, err := createTempFile("./fixtures/toml/tls_file.cert", tempDir)
require.NoError(t, err)
fileConfig, err := ioutil.TempFile(tempDir, "temp*.toml")
fileConfig, err := os.CreateTemp(tempDir, "temp*.toml")
require.NoError(t, err)
content := `
@@ -245,7 +243,7 @@ func getTestCases() []ProvideTestCase {
func createProvider(t *testing.T, test ProvideTestCase, watch bool) *Provider {
t.Helper()
tempDir := createTempDir(t, "testdir")
tempDir := t.TempDir()
provider := &Provider{}
provider.Watch = true
@@ -265,7 +263,7 @@ func createProvider(t *testing.T, test ProvideTestCase, watch bool) *Provider {
var file *os.File
if watch {
var err error
file, err = ioutil.TempFile(tempDir, "temp*"+filepath.Ext(test.filePath))
file, err = os.CreateTemp(tempDir, "temp*"+filepath.Ext(test.filePath))
require.NoError(t, err)
} else {
var err error
@@ -283,17 +281,6 @@ func createProvider(t *testing.T, test ProvideTestCase, watch bool) *Provider {
return provider
}
// createTempDir Helper.
func createTempDir(t *testing.T, dir string) string {
t.Helper()
d, err := ioutil.TempDir("", dir)
if err != nil {
t.Fatal(err)
}
return d
}
func copyFile(srcPath, dstPath string) error {
dst, err := os.OpenFile(dstPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
if err != nil {
@@ -312,7 +299,7 @@ func copyFile(srcPath, dstPath string) error {
}
func createTempFile(srcPath, tempDir string) (*os.File, error) {
file, err := ioutil.TempFile(tempDir, "temp*"+filepath.Ext(srcPath))
file, err := os.CreateTemp(tempDir, "temp*"+filepath.Ext(srcPath))
if err != nil {
return nil, err
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"fmt"
"hash/fnv"
"io/ioutil"
"io"
"net/http"
"time"
@@ -139,7 +139,7 @@ func (p *Provider) fetchConfigurationData() ([]byte, error) {
return nil, fmt.Errorf("received non-ok response code: %d", res.StatusCode)
}
return ioutil.ReadAll(res.Body)
return io.ReadAll(res.Body)
}
// decodeConfiguration decodes and returns the dynamic configuration from the given data.

View File

@@ -3,7 +3,6 @@ package crd
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
@@ -147,7 +146,7 @@ func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrappe
}
if caFilePath != "" {
caData, err := ioutil.ReadFile(caFilePath)
caData, err := os.ReadFile(caFilePath)
if err != nil {
return nil, fmt.Errorf("failed to read CA file %s: %w", caFilePath, err)
}

View File

@@ -2,7 +2,7 @@ package crd
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
@@ -46,7 +46,7 @@ func newClientMock(paths ...string) clientMock {
var c clientMock
for _, path := range paths {
yamlContent, err := ioutil.ReadFile(filepath.FromSlash("./fixtures/" + path))
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
if err != nil {
panic(err)
}

View File

@@ -2,7 +2,7 @@ package crd
import (
"context"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
@@ -4394,7 +4394,7 @@ func TestCrossNamespace(t *testing.T) {
var k8sObjects []runtime.Object
var crdObjects []runtime.Object
for _, path := range test.paths {
yamlContent, err := ioutil.ReadFile(filepath.FromSlash("./fixtures/" + path))
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
if err != nil {
panic(err)
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/traefik/traefik/v2/pkg/log"
@@ -16,9 +16,9 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/service-apis/apis/v1alpha1"
"sigs.k8s.io/service-apis/pkg/client/clientset/versioned"
"sigs.k8s.io/service-apis/pkg/client/informers/externalversions"
"sigs.k8s.io/gateway-api/apis/v1alpha1"
"sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
"sigs.k8s.io/gateway-api/pkg/client/informers/externalversions"
)
const resyncPeriod = 10 * time.Minute
@@ -138,7 +138,7 @@ func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrappe
}
if caFilePath != "" {
caData, err := ioutil.ReadFile(caFilePath)
caData, err := os.ReadFile(caFilePath)
if err != nil {
return nil, fmt.Errorf("failed to read CA file %s: %w", caFilePath, err)
}

View File

@@ -2,7 +2,7 @@ package gateway
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/k8s"
@@ -10,7 +10,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/service-apis/apis/v1alpha1"
"sigs.k8s.io/gateway-api/apis/v1alpha1"
)
var _ Client = (*clientMock)(nil)
@@ -43,7 +43,7 @@ func newClientMock(paths ...string) clientMock {
var c clientMock
for _, path := range paths {
yamlContent, err := ioutil.ReadFile(filepath.FromSlash("./fixtures/" + path))
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
if err != nil {
panic(err)
}

Some files were not shown because too many files have changed in this diff Show More