Merge branch 'v2.2' into master

This commit is contained in:
Michael 2020-05-18 18:37:11 +02:00
commit 7928e6d0cd
No known key found for this signature in database
GPG key ID: 71EDE16780F920E8
167 changed files with 554 additions and 563 deletions

View file

@ -49,6 +49,9 @@
"wsl", # Too strict "wsl", # Too strict
"gomnd", # Too strict "gomnd", # Too strict
"stylecheck", # skip because report issues related to some generated files. "stylecheck", # skip because report issues related to some generated files.
"testpackage", # Too strict
"goerr113", # Too strict
"nestif", # Too many false-positive.
] ]
[issues] [issues]
@ -62,7 +65,7 @@
] ]
[[issues.exclude-rules]] [[issues.exclude-rules]]
path = "(.+)_test.go" path = "(.+)_test.go"
linters = ["goconst", "funlen"] linters = ["goconst", "funlen", "godot"]
[[issues.exclude-rules]] [[issues.exclude-rules]]
path = "integration/.+_test.go" path = "integration/.+_test.go"
text = "Error return value of `cmd\\.Process\\.Kill` is not checked" text = "Error return value of `cmd\\.Process\\.Kill` is not checked"
@ -105,3 +108,6 @@
[[issues.exclude-rules]] [[issues.exclude-rules]]
path = "pkg/tracing/tracing.go" path = "pkg/tracing/tracing.go"
text = "printf-like formatting function 'SetErrorWithEvent' should be named 'SetErrorWithEventf'" text = "printf-like formatting function 'SetErrorWithEvent' should be named 'SetErrorWithEventf'"
[[issues.exclude-rules]]
path = "pkg/log/deprecated.go"
linters = ["godot"]

View file

@ -32,7 +32,7 @@ TRAEFIK_ENVS := \
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)" TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)"
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)" DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
DOCKER_NON_INTERACTIVE ?= false DOCKER_NON_INTERACTIVE ?= false
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS) DOCKER_RUN_TRAEFIK := docker run --add-host=host.docker.internal:127.0.0.1 $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -it) $(DOCKER_RUN_OPTS)
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -i) $(DOCKER_RUN_OPTS) DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INTERACTIVE), , -i) $(DOCKER_RUN_OPTS)
PRE_TARGET ?= build-dev-image PRE_TARGET ?= build-dev-image

View file

@ -19,7 +19,7 @@ RUN mkdir -p /usr/local/bin \
&& chmod +x /usr/local/bin/go-bindata && chmod +x /usr/local/bin/go-bindata
# Download golangci-lint binary to bin folder in $GOPATH # 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.23.8 RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.26.0
# Download misspell binary to bin folder in $GOPATH # 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 RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4

View file

@ -7,7 +7,7 @@ import (
"syscall" "syscall"
) )
// ContextWithSignal creates a context canceled when SIGINT or SIGTERM are notified // ContextWithSignal creates a context canceled when SIGINT or SIGTERM are notified.
func ContextWithSignal(ctx context.Context) context.Context { func ContextWithSignal(ctx context.Context) context.Context {
newCtx, cancel := context.WithCancel(ctx) newCtx, cancel := context.WithCancel(ctx)
signals := make(chan os.Signal) signals := make(chan os.Signal)

View file

@ -45,7 +45,7 @@ func runCmd(traefikConfiguration *static.Configuration) func(_ []string) error {
} }
} }
// Do try to do a healthcheck // Do try to do a healthcheck.
func Do(staticConfiguration static.Configuration) (*http.Response, error) { func Do(staticConfiguration static.Configuration) (*http.Response, error) {
if staticConfiguration.Ping == nil { if staticConfiguration.Ping == nil {
return nil, errors.New("please enable `ping` to use health check") return nil, errors.New("please enable `ping` to use health check")

View file

@ -274,7 +274,7 @@ func switchRouter(routerFactory *server.RouterFactory, acmeProviders []*acme.Pro
} }
} }
// initACMEProvider creates an acme provider from the ACME part of globalConfiguration // initACMEProvider creates an acme provider from the ACME part of globalConfiguration.
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager) []*acme.Provider { func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager) []*acme.Provider {
challengeStore := acme.NewLocalChallengeStore() challengeStore := acme.NewLocalChallengeStore()
localStores := map[string]*acme.LocalStore{} localStores := map[string]*acme.LocalStore{}

View file

@ -17,7 +17,7 @@ Go version: {{.GoVersion}}
Built: {{.BuildTime}} Built: {{.BuildTime}}
OS/Arch: {{.Os}}/{{.Arch}}` OS/Arch: {{.Os}}/{{.Arch}}`
// NewCmd builds a new Version command // NewCmd builds a new Version command.
func NewCmd() *cli.Command { func NewCmd() *cli.Command {
return &cli.Command{ return &cli.Command{
Name: "version", Name: "version",
@ -33,7 +33,7 @@ func NewCmd() *cli.Command {
} }
} }
// GetPrint write Printable version // GetPrint write Printable version.
func GetPrint(wr io.Writer) error { func GetPrint(wr io.Writer) error {
tmpl, err := template.New("").Parse(versionTemplate) tmpl, err := template.New("").Parse(versionTemplate)
if err != nil { if err != nil {

View file

@ -83,7 +83,7 @@ helm install traefik traefik/traefik
```bash tab="Using Helm CLI" ```bash tab="Using Helm CLI"
helm install --namespace=traefik-v2 \ helm install --namespace=traefik-v2 \
--set="additionalArguments={--logs.level=DEBUG}" \ --set="additionalArguments={--log.level=DEBUG}" \
traefik traefik/traefik traefik traefik/traefik
``` ```

View file

@ -105,13 +105,13 @@ Please check the [configuration examples below](#configuration-examples) for mor
``` ```
```bash tab="CLI" ```bash tab="CLI"
--entryPoints.web.address=:80 --entrypoints.web.address=:80
--entryPoints.websecure.address=:443 --entrypoints.websecure.address=:443
# ... # ...
--certificatesResolvers.myresolver.acme.email=your-email@example.com --certificatesresolvers.myresolver.acme.email=your-email@example.com
--certificatesResolvers.myresolver.acme.storage=acme.json --certificatesresolvers.myresolver.acme.storage=acme.json
# used during the challenge # used during the challenge
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
``` ```
!!! important "Defining a certificates resolver does not result in all routers automatically using it. Each router that is supposed to use the resolver must [reference](../routing/routers/index.md#certresolver) it." !!! important "Defining a certificates resolver does not result in all routers automatically using it. Each router that is supposed to use the resolver must [reference](../routing/routers/index.md#certresolver) it."
@ -181,7 +181,7 @@ when using the `TLS-ALPN-01` challenge, Traefik must be reachable by Let's Encry
```bash tab="CLI" ```bash tab="CLI"
# ... # ...
--certificatesResolvers.myresolver.acme.tlsChallenge=true --certificatesresolvers.myresolver.acme.tlschallenge=true
``` ```
### `httpChallenge` ### `httpChallenge`
@ -189,7 +189,7 @@ when using the `TLS-ALPN-01` challenge, Traefik must be reachable by Let's Encry
Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning an HTTP resource under a well-known URI. Use the `HTTP-01` challenge to generate and renew ACME certificates by provisioning an HTTP resource under a well-known URI.
As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72), As described on the Let's Encrypt [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72),
when using the `HTTP-01` challenge, `certificatesResolvers.myresolver.acme.httpChallenge.entryPoint` must be reachable by Let's Encrypt through port 80. when using the `HTTP-01` challenge, `certificatesresolvers.myresolver.acme.httpchallenge.entrypoint` must be reachable by Let's Encrypt through port 80.
??? example "Using an EntryPoint Called web for the `httpChallenge`" ??? example "Using an EntryPoint Called web for the `httpChallenge`"
@ -224,10 +224,10 @@ when using the `HTTP-01` challenge, `certificatesResolvers.myresolver.acme.httpC
``` ```
```bash tab="CLI" ```bash tab="CLI"
--entryPoints.web.address=:80 --entrypoints.web.address=:80
--entryPoints.websecure.address=:443 --entrypoints.websecure.address=:443
# ... # ...
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
``` ```
!!! info "" !!! info ""
@ -261,8 +261,8 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
```bash tab="CLI" ```bash tab="CLI"
# ... # ...
--certificatesResolvers.myresolver.acme.dnsChallenge.provider=digitalocean --certificatesresolvers.myresolver.acme.dnschallenge.provider=digitalocean
--certificatesResolvers.myresolver.acme.dnsChallenge.delayBeforeCheck=0 --certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
# ... # ...
``` ```
@ -294,6 +294,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) | | [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) | | [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) |
| [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) | | [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) |
| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) |
| [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) | | [DigitalOcean](https://www.digitalocean.com) | `digitalocean` | `DO_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/digitalocean) |
| [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) | | [DNSimple](https://dnsimple.com) | `dnsimple` | `DNSIMPLE_OAUTH_TOKEN`, `DNSIMPLE_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/dnsimple) |
| [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) | | [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) |
@ -312,6 +313,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | [Additional configuration](https://go-acme.github.io/lego/dns/glesys) | | [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | [Additional configuration](https://go-acme.github.io/lego/dns/glesys) |
| [GoDaddy](https://godaddy.com/) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/godaddy) | | [GoDaddy](https://godaddy.com/) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | [Additional configuration](https://go-acme.github.io/lego/dns/godaddy) |
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | [Additional configuration](https://go-acme.github.io/lego/dns/gcloud) | | [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | [Additional configuration](https://go-acme.github.io/lego/dns/gcloud) |
| [Hetzner](https://hetzner.com) | `hetzner` | `HETZNER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hetzner) |
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) | | [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) |
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) | | HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) |
| [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) | | [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) |
@ -321,12 +323,15 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) | | [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linodev4) | | [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linodev4) |
| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) | | [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) |
| [LuaDNS](https://luadns.com) | `luadns` | `LUADNS_API_USERNAME`, `LUADNS_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/luadns) |
| manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | | | manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) | | [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
| [Mythic Beasts](https://www.mythic-beasts.com) | `mythicbeasts` | `MYTHICBEASTS_USER_NAME`, `MYTHICBEASTS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mythicbeasts) |
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) | | [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) | | [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |
| [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) | | [Namesilo](https://www.namesilo.com/) | `namesilo` | `NAMESILO_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namesilo) |
| [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) | | [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) | | [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) |
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ns1) | | [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) | | [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) |
@ -349,6 +354,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) | | [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) |
| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vscale) | | [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vscale) |
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/vultr) | | [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/vultr) |
| [Yandex](https://yandex.com) | `yandex` | `YANDEX_PDD_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/yandex) |
| [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) | | [Zone.ee](https://www.zone.ee) | `zoneee` | `ZONEEE_API_USER`, `ZONEEE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zoneee) |
| [Zonomi](https://zonomi.com) | `zonomi` | `ZONOMI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zonomi) | | [Zonomi](https://zonomi.com) | `zonomi` | `ZONOMI_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/zonomi) |
@ -389,7 +395,7 @@ certificatesResolvers:
```bash tab="CLI" ```bash tab="CLI"
# ... # ...
--certificatesResolvers.myresolver.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53 --certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53
``` ```
#### Wildcard Domains #### Wildcard Domains
@ -428,7 +434,7 @@ The CA server to use:
```bash tab="CLI" ```bash tab="CLI"
# ... # ...
--certificatesResolvers.myresolver.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
# ... # ...
``` ```
@ -456,7 +462,7 @@ certificatesResolvers:
```bash tab="CLI" ```bash tab="CLI"
# ... # ...
--certificatesResolvers.myresolver.acme.storage=acme.json --certificatesresolvers.myresolver.acme.storage=acme.json
# ... # ...
``` ```
@ -473,7 +479,7 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
``` ```
!!! warning !!! warning
For concurrency reason, this file cannot be shared across multiple instances of Traefik. For concurrency reasons, this file cannot be shared across multiple instances of Traefik.
## Fallback ## Fallback

View file

@ -4,13 +4,13 @@
# #
# Required # Required
# #
--certificatesResolvers.myresolver.acme.email=test@example.com --certificatesresolvers.myresolver.acme.email=test@example.com
# File or key used for certificates storage. # File or key used for certificates storage.
# #
# Required # Required
# #
--certificatesResolvers.myresolver.acme.storage=acme.json --certificatesresolvers.myresolver.acme.storage=acme.json
# CA server to use. # CA server to use.
# Uncomment the line to use Let's Encrypt's staging server, # Uncomment the line to use Let's Encrypt's staging server,
@ -19,7 +19,7 @@
# Optional # Optional
# Default: "https://acme-v02.api.letsencrypt.org/directory" # Default: "https://acme-v02.api.letsencrypt.org/directory"
# #
--certificatesResolvers.myresolver.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
# KeyType to use. # KeyType to use.
# #
@ -28,38 +28,38 @@
# #
# Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192" # Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192"
# #
--certificatesResolvers.myresolver.acme.keyType=RSA4096 --certificatesresolvers.myresolver.acme.keytype=RSA4096
# Use a TLS-ALPN-01 ACME challenge. # Use a TLS-ALPN-01 ACME challenge.
# #
# Optional (but recommended) # Optional (but recommended)
# #
--certificatesResolvers.myresolver.acme.tlsChallenge=true --certificatesresolvers.myresolver.acme.tlschallenge=true
# Use a HTTP-01 ACME challenge. # Use a HTTP-01 ACME challenge.
# #
# Optional # Optional
# #
--certificatesResolvers.myresolver.acme.httpChallenge=true --certificatesresolvers.myresolver.acme.httpchallenge=true
# EntryPoint to use for the HTTP-01 challenges. # EntryPoint to use for the HTTP-01 challenges.
# #
# Required # Required
# #
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge. # Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
# Note: mandatory for wildcard certificate generation. # Note: mandatory for wildcard certificate generation.
# #
# Optional # Optional
# #
--certificatesResolvers.myresolver.acme.dnsChallenge=true --certificatesresolvers.myresolver.acme.dnschallenge=true
# DNS provider used. # DNS provider used.
# #
# Required # Required
# #
--certificatesResolvers.myresolver.acme.dnsChallenge.provider=digitalocean --certificatesresolvers.myresolver.acme.dnschallenge.provider=digitalocean
# By default, the provider will verify the TXT DNS challenge record before letting ACME verify. # By default, the provider will verify the TXT DNS challenge record before letting ACME verify.
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds. # If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
@ -68,14 +68,14 @@
# Optional # Optional
# Default: 0 # Default: 0
# #
--certificatesResolvers.myresolver.acme.dnsChallenge.delayBeforeCheck=0 --certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
# Use following DNS servers to resolve the FQDN authority. # Use following DNS servers to resolve the FQDN authority.
# #
# Optional # Optional
# Default: empty # Default: empty
# #
--certificatesResolvers.myresolver.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53 --certificatesresolvers.myresolver.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53
# Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. # Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready.
# #
@ -85,4 +85,4 @@
# Optional # Optional
# Default: false # Default: false
# #
--certificatesResolvers.myresolver.acme.dnsChallenge.disablePropagationCheck=true --certificatesresolvers.myresolver.acme.dnschallenge.disablepropagationcheck=true

View file

@ -208,7 +208,7 @@ metadata:
spec: spec:
redirectScheme: redirectScheme:
# ... # ...
port: 443 port: "443"
``` ```
```yaml tab="Consul Catalog" ```yaml tab="Consul Catalog"
@ -247,5 +247,7 @@ http:
test-redirectscheme: test-redirectscheme:
redirectScheme: redirectScheme:
# ... # ...
port: 443 port: "443"
``` ```
!!! info "Port in this configuration is a string, not a numeric value."

View file

@ -358,17 +358,3 @@ providers:
If one wants to know more about the various aspects of the Ingress spec that Traefik supports, If one wants to know more about the various aspects of the Ingress spec that Traefik supports,
many examples of Ingresses definitions are located in the tests [data](https://github.com/containous/traefik/tree/v2.2/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository. many examples of Ingresses definitions are located in the tests [data](https://github.com/containous/traefik/tree/v2.2/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
## LetsEncrypt Support with the Ingress Provider
By design, Traefik is a stateless application, meaning that it only derives its configuration from the environment it runs in, without additional configuration.
For this reason, users can run multiple instances of Traefik at the same time to achieve HA, as is a common pattern in the kubernetes ecosystem.
When using a single instance of Traefik with LetsEncrypt, no issues should be encountered, however this could be a single point of failure.
Unfortunately, it is not possible to run multiple instances of Traefik 2.0 with LetsEncrypt enabled, because there is no way to ensure that the correct instance of Traefik will receive the challenge request, and subsequent responses.
Previous versions of Traefik used a [KV store](https://docs.traefik.io/v1.7/configuration/acme/#storage) to attempt to achieve this, but due to sub-optimal performance was dropped as a feature in 2.0.
If you require LetsEncrypt with HA in a kubernetes environment, we recommend using [TraefikEE](https://containo.us/traefikee/) where distributed LetsEncrypt is a supported feature.
If you are wanting to continue to run Traefik Community Edition, LetsEncrypt HA can be achieved by using a Certificate Controller such as [Cert-Manager](https://docs.cert-manager.io/en/latest/index.html).
When using Cert-Manager to manage certificates, it will create secrets in your namespaces that can be referenced as TLS secrets in your [ingress objects](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls).

View file

@ -26,7 +26,7 @@ theme:
prev: 'Previous' prev: 'Previous'
next: 'Next' next: 'Next'
copyright: "Copyright &copy; 2016-2019 Containous" copyright: "Copyright &copy; 2016-2020 Containous"
google_analytics: google_analytics:
- 'UA-51880359-3' - 'UA-51880359-3'

2
go.mod
View file

@ -36,7 +36,7 @@ require (
github.com/fatih/structs v1.1.0 github.com/fatih/structs v1.1.0
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2 github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
github.com/go-acme/lego/v3 v3.6.0 github.com/go-acme/lego/v3 v3.7.0
github.com/go-check/check v0.0.0-00010101000000-000000000000 github.com/go-check/check v0.0.0-00010101000000-000000000000
github.com/go-kit/kit v0.9.0 github.com/go-kit/kit v0.9.0
github.com/golang/protobuf v1.3.4 github.com/golang/protobuf v1.3.4

17
go.sum
View file

@ -109,8 +109,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.16.23/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.16.23/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.0 h1:ilfJN/vJtFo1XDFxB2YMBYGeOvGZl6Qow17oyD4+Z9A= github.com/aws/aws-sdk-go v1.30.20 h1:ktsy2vodSZxz/arYqo7DlpkIeNohHL+4Rmjdo7YGtrE=
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.20/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -182,8 +182,8 @@ github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TR
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2 h1:G9/PqfhOrt8JXnw0DGTfVoOkKHDhOlEZqhE/cu+NvQM= github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2 h1:G9/PqfhOrt8JXnw0DGTfVoOkKHDhOlEZqhE/cu+NvQM=
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dnsimple/dnsimple-go v0.30.0 h1:IBIrn9jMKRMwporIRwdFyKdnHXVmwy6obnguB+ZMDIY= github.com/dnsimple/dnsimple-go v0.60.0 h1:N+q+ML1CZGf+5r4udu9Opy7WJNtOaFT9aM86Af9gLhk=
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= github.com/dnsimple/dnsimple-go v0.60.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0 h1:hlGHcYGaaHs/yffSubcUKlp8TyV1v7qhcZZ5nGNQ2Fw= github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0 h1:hlGHcYGaaHs/yffSubcUKlp8TyV1v7qhcZZ5nGNQ2Fw=
github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v0.0.0-20200221155518-740919cc7fc0/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
@ -247,8 +247,8 @@ github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2/go.mod h1:GLy
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-acme/lego/v3 v3.6.0 h1:Rv0MrX3DpVp9Xg77yR7x+PCksLLph3Ut/69/9Kim8ac= github.com/go-acme/lego/v3 v3.7.0 h1:qC5/8/CbltyAE8fGLE6bGlqucj7pXc/vBxiLwLOsmAQ=
github.com/go-acme/lego/v3 v3.6.0/go.mod h1:sB/T7hfyz0HYIBvPmz/C8jIaxF6scbbiGKTzbQ22V6A= github.com/go-acme/lego/v3 v3.7.0/go.mod h1:4eDjjYkAsDXyNcwN8IhhZAwxz9Ltiks1Zmpv0q20J7A=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@ -277,6 +277,7 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
@ -425,6 +426,8 @@ github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
@ -587,6 +590,8 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

View file

@ -24,7 +24,7 @@ const (
traefikTestAccessLogFile = "access.log" traefikTestAccessLogFile = "access.log"
) )
// AccessLogSuite // AccessLogSuite tests suite.
type AccessLogSuite struct{ BaseSuite } type AccessLogSuite struct{ BaseSuite }
type accessLogValue struct { type accessLogValue struct {
@ -562,7 +562,7 @@ func extractLines(c *check.C) []string {
func checkStatsForLogFile(c *check.C) { func checkStatsForLogFile(c *check.C) {
err := try.Do(1*time.Second, func() error { err := try.Do(1*time.Second, func() error {
if _, errStat := os.Stat(traefikTestLogFile); errStat != nil { if _, errStat := os.Stat(traefikTestLogFile); errStat != nil {
return fmt.Errorf("could not get stats for log file: %s", errStat) return fmt.Errorf("could not get stats for log file: %w", errStat)
} }
return nil return nil
}) })

View file

@ -20,7 +20,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// ACME test suites (using libcompose) // ACME test suites (using libcompose).
type AcmeSuite struct { type AcmeSuite struct {
BaseSuite BaseSuite
pebbleIP string pebbleIP string
@ -74,7 +74,7 @@ func setupPebbleRootCA() (*http.Transport, error) {
certPool := x509.NewCertPool() certPool := x509.NewCertPool()
if ok := certPool.AppendCertsFromPEM(customCAs); !ok { if ok := certPool.AppendCertsFromPEM(customCAs); !ok {
return nil, fmt.Errorf("error creating x509 cert pool from %q: %v", path, err) return nil, fmt.Errorf("error creating x509 cert pool from %q: %w", path, err)
} }
return &http.Transport{ return &http.Transport{
@ -394,7 +394,7 @@ func (s *AcmeSuite) TestTLSALPN01DomainsInSAN(c *check.C) {
s.retrieveAcmeCertificate(c, testCase) s.retrieveAcmeCertificate(c, testCase)
} }
// Test Let's encrypt down // Test Let's encrypt down.
func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) { func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{ file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{
Acme: map[string]static.CertificateResolver{ Acme: map[string]static.CertificateResolver{
@ -417,7 +417,7 @@ func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
} }
// Doing an HTTPS request and test the response certificate // Doing an HTTPS request and test the response certificate.
func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) { func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
if len(testCase.template.PortHTTP) == 0 { if len(testCase.template.PortHTTP) == 0 {
testCase.template.PortHTTP = ":5002" testCase.template.PortHTTP = ":5002"

View file

@ -47,7 +47,7 @@ func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
leader, err := s.consulClient.Status().Leader() leader, err := s.consulClient.Status().Leader()
if err != nil || len(leader) == 0 { if err != nil || len(leader) == 0 {
return fmt.Errorf("leader not found. %v", err) return fmt.Errorf("leader not found. %w", err)
} }
return nil return nil

View file

@ -19,7 +19,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// Consul test suites (using libcompose) // Consul test suites (using libcompose).
type ConsulSuite struct { type ConsulSuite struct {
BaseSuite BaseSuite
kvClient store.Store kvClient store.Store

View file

@ -18,7 +18,7 @@ const (
composeProject = "minimal" composeProject = "minimal"
) )
// Docker test suites // Docker tests suite.
type DockerComposeSuite struct { type DockerComposeSuite struct {
BaseSuite BaseSuite
} }

View file

@ -17,14 +17,14 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// Images to have or pull before the build in order to make it work // Images to have or pull before the build in order to make it work.
// FIXME handle this offline but loading them before build // FIXME handle this offline but loading them before build.
var RequiredImages = map[string]string{ var RequiredImages = map[string]string{
"swarm": "1.0.0", "swarm": "1.0.0",
"containous/whoami": "latest", "containous/whoami": "latest",
} }
// Docker test suites // Docker tests suite.
type DockerSuite struct { type DockerSuite struct {
BaseSuite BaseSuite
project *docker.Project project *docker.Project

View file

@ -10,7 +10,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// ErrorPagesSuite test suites (using libcompose) // ErrorPagesSuite test suites (using libcompose).
type ErrorPagesSuite struct { type ErrorPagesSuite struct {
BaseSuite BaseSuite
ErrorPageIP string ErrorPageIP string

View file

@ -19,7 +19,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// etcd test suites (using libcompose) // etcd test suites (using libcompose).
type EtcdSuite struct { type EtcdSuite struct {
BaseSuite BaseSuite
kvClient store.Store kvClient store.Store

View file

@ -10,7 +10,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// File test suites // File tests suite.
type FileSuite struct{ BaseSuite } type FileSuite struct{ BaseSuite }
func (s *FileSuite) SetUpSuite(c *check.C) { func (s *FileSuite) SetUpSuite(c *check.C) {
@ -32,7 +32,7 @@ func (s *FileSuite) TestSimpleConfiguration(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
} }
// #56 regression test, make sure it does not fail // #56 regression test, make sure it does not fail?
func (s *FileSuite) TestSimpleConfigurationNoPanic(c *check.C) { func (s *FileSuite) TestSimpleConfigurationNoPanic(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/file/56-simple-panic.toml")) cmd, display := s.traefikCmd(withConfigFile("fixtures/file/56-simple-panic.toml"))
defer display(c) defer display(c)

View file

@ -24,7 +24,7 @@ var LocalhostKey []byte
const randCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" const randCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
// GRPCSuite // GRPCSuite tests suite.
type GRPCSuite struct{ BaseSuite } type GRPCSuite struct{ BaseSuite }
type myserver struct { type myserver struct {

View file

@ -10,7 +10,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// Headers test suites // Headers tests suite.
type HeadersSuite struct{ BaseSuite } type HeadersSuite struct{ BaseSuite }
func (s *HeadersSuite) TestSimpleConfiguration(c *check.C) { func (s *HeadersSuite) TestSimpleConfiguration(c *check.C) {

View file

@ -11,7 +11,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// HealthCheck test suites (using libcompose) // HealthCheck test suites (using libcompose).
type HealthCheckSuite struct { type HealthCheckSuite struct {
BaseSuite BaseSuite
whoami1IP string whoami1IP string
@ -206,7 +206,7 @@ func (s *HealthCheckSuite) TestPortOverload(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
} }
// Checks if all the loadbalancers created will correctly update the server status // Checks if all the loadbalancers created will correctly update the server status.
func (s *HealthCheckSuite) TestMultipleRoutersOnSameService(c *check.C) { func (s *HealthCheckSuite) TestMultipleRoutersOnSameService(c *check.C) {
file := s.adaptFile(c, "fixtures/healthcheck/multiple-routers-one-same-service.toml", struct { file := s.adaptFile(c, "fixtures/healthcheck/multiple-routers-one-same-service.toml", struct {
Server1 string Server1 string

View file

@ -18,7 +18,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// HTTPSSuite // HTTPSSuite tests suite.
type HTTPSSuite struct{ BaseSuite } type HTTPSSuite struct{ BaseSuite }
// TestWithSNIConfigHandshake involves a client sending a SNI hostname of // TestWithSNIConfigHandshake involves a client sending a SNI hostname of
@ -441,7 +441,7 @@ func (s *HTTPSSuite) TestWithOverlappingDynamicCertificate(c *check.C) {
} }
// TestWithClientCertificateAuthentication // TestWithClientCertificateAuthentication
// The client can send a certificate signed by a CA trusted by the server but it's optional // The client can send a certificate signed by a CA trusted by the server but it's optional.
func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) { func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
file := s.adaptFile(c, "fixtures/https/clientca/https_1ca1config.toml", struct{}{}) file := s.adaptFile(c, "fixtures/https/clientca/https_1ca1config.toml", struct{}{})
defer os.Remove(file) defer os.Remove(file)
@ -499,7 +499,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
} }
// TestWithClientCertificateAuthentication // TestWithClientCertificateAuthentication
// Use two CA:s and test that clients with client signed by either of them can connect // Use two CA:s and test that clients with client signed by either of them can connect.
func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAs(c *check.C) { func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAs(c *check.C) {
server1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server1")) })) server1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server1")) }))
server2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server2")) })) server2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server2")) }))
@ -596,7 +596,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAs(c *check
} }
// TestWithClientCertificateAuthentication // TestWithClientCertificateAuthentication
// Use two CA:s in two different files and test that clients with client signed by either of them can connect // Use two CA:s in two different files and test that clients with client signed by either of them can connect.
func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAsMultipleFiles(c *check.C) { func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAsMultipleFiles(c *check.C) {
server1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server1")) })) server1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server1")) }))
server2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server2")) })) server2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { _, _ = rw.Write([]byte("server2")) }))

View file

@ -24,7 +24,7 @@ import (
var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata") var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata")
// K8sSuite // K8sSuite tests suite.
type K8sSuite struct{ BaseSuite } type K8sSuite struct{ BaseSuite }
func (s *K8sSuite) SetUpSuite(c *check.C) { func (s *K8sSuite) SetUpSuite(c *check.C) {
@ -128,7 +128,7 @@ func matchesConfig(wantConfig string, buf *bytes.Buffer) try.ResponseCondition {
return func(res *http.Response) error { return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return fmt.Errorf("failed to read response body: %s", err) return fmt.Errorf("failed to read response body: %w", err)
} }
if err := res.Body.Close(); err != nil { if err := res.Body.Close(); err != nil {

View file

@ -16,7 +16,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// Log rotation integration test suite // Log rotation integration test suite.
type LogRotationSuite struct{ BaseSuite } type LogRotationSuite struct{ BaseSuite }
func (s *LogRotationSuite) SetUpSuite(c *check.C) { func (s *LogRotationSuite) SetUpSuite(c *check.C) {

View file

@ -12,7 +12,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// Marathon test suites (using libcompose) // Marathon test suites (using libcompose).
type MarathonSuite15 struct { type MarathonSuite15 struct {
BaseSuite BaseSuite
marathonURL string marathonURL string

View file

@ -17,7 +17,7 @@ const (
containerNameMarathon = "marathon" containerNameMarathon = "marathon"
) )
// Marathon test suites (using libcompose) // Marathon test suites (using libcompose).
type MarathonSuite struct { type MarathonSuite struct {
BaseSuite BaseSuite
marathonURL string marathonURL string

View file

@ -19,7 +19,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// Redis test suites (using libcompose) // Redis test suites (using libcompose).
type RedisSuite struct { type RedisSuite struct {
BaseSuite BaseSuite
kvClient store.Store kvClient store.Store

View file

@ -20,7 +20,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// SimpleSuite // SimpleSuite tests suite.
type SimpleSuite struct{ BaseSuite } type SimpleSuite struct{ BaseSuite }
func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) { func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) {

View file

@ -12,18 +12,16 @@ import (
) )
// ResponseCondition is a retry condition function. // ResponseCondition is a retry condition function.
// It receives a response, and returns an error // It receives a response, and returns an error if the response failed the condition.
// if the response failed the condition.
type ResponseCondition func(*http.Response) error type ResponseCondition func(*http.Response) error
// BodyContains returns a retry condition function. // BodyContains returns a retry condition function.
// The condition returns an error if the request body does not contain all the given // The condition returns an error if the request body does not contain all the given strings.
// strings.
func BodyContains(values ...string) ResponseCondition { func BodyContains(values ...string) ResponseCondition {
return func(res *http.Response) error { return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return fmt.Errorf("failed to read response body: %s", err) return fmt.Errorf("failed to read response body: %w", err)
} }
for _, value := range values { for _, value := range values {
@ -36,13 +34,12 @@ func BodyContains(values ...string) ResponseCondition {
} }
// BodyNotContains returns a retry condition function. // BodyNotContains returns a retry condition function.
// The condition returns an error if the request body contain one of the given // The condition returns an error if the request body contain one of the given strings.
// strings.
func BodyNotContains(values ...string) ResponseCondition { func BodyNotContains(values ...string) ResponseCondition {
return func(res *http.Response) error { return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return fmt.Errorf("failed to read response body: %s", err) return fmt.Errorf("failed to read response body: %w", err)
} }
for _, value := range values { for _, value := range values {
@ -55,13 +52,12 @@ func BodyNotContains(values ...string) ResponseCondition {
} }
// BodyContainsOr returns a retry condition function. // BodyContainsOr returns a retry condition function.
// The condition returns an error if the request body does not contain one of the given // The condition returns an error if the request body does not contain one of the given strings.
// strings.
func BodyContainsOr(values ...string) ResponseCondition { func BodyContainsOr(values ...string) ResponseCondition {
return func(res *http.Response) error { return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return fmt.Errorf("failed to read response body: %s", err) return fmt.Errorf("failed to read response body: %w", err)
} }
for _, value := range values { for _, value := range values {
@ -79,7 +75,7 @@ func HasBody() ResponseCondition {
return func(res *http.Response) error { return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return fmt.Errorf("failed to read response body: %s", err) return fmt.Errorf("failed to read response body: %w", err)
} }
if len(body) == 0 { if len(body) == 0 {
@ -182,11 +178,11 @@ func HasHeaderStruct(header http.Header) ResponseCondition {
} }
// DoCondition is a retry condition function. // DoCondition is a retry condition function.
// It returns an error // It returns an error.
type DoCondition func() error type DoCondition func() error
// KVExists is a retry condition function. // KVExists is a retry condition function.
// Verify if a Key exists in the store // Verify if a Key exists in the store.
func KVExists(kv store.Store, key string) DoCondition { func KVExists(kv store.Store, key string) DoCondition {
return func() error { return func() error {
_, err := kv.Exists(key, nil) _, err := kv.Exists(key, nil)

View file

@ -115,7 +115,7 @@ func Do(timeout time.Duration, operation DoCondition) error {
select { select {
case <-stopTimer.C: case <-stopTimer.C:
fmt.Println("-") fmt.Println("-")
return fmt.Errorf("try operation failed: %s", err) return fmt.Errorf("try operation failed: %w", err)
case <-retryTick.C: case <-retryTick.C:
fmt.Print("*") fmt.Print("*")
if err = operation(); err == nil { if err = operation(); err == nil {

View file

@ -18,7 +18,7 @@ import (
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
// WebsocketSuite // WebsocketSuite tests suite.
type WebsocketSuite struct{ BaseSuite } type WebsocketSuite struct{ BaseSuite }
func (s *WebsocketSuite) TestBase(c *check.C) { func (s *WebsocketSuite) TestBase(c *check.C) {

View file

@ -19,7 +19,7 @@ import (
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
) )
// Zk test suites (using libcompose) // Zk test suites (using libcompose).
type ZookeeperSuite struct { type ZookeeperSuite struct {
BaseSuite BaseSuite
kvClient store.Store kvClient store.Store

View file

@ -15,7 +15,7 @@ const (
maskLarge = maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort maskLarge = maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort
) )
// Do configuration. // Do sends configuration.
func Do(baseConfig interface{}, indent bool) (string, error) { func Do(baseConfig interface{}, indent bool) (string, error) {
anomConfig, err := copystructure.Copy(baseConfig) anomConfig, err := copystructure.Copy(baseConfig)
if err != nil { if err != nil {
@ -120,7 +120,7 @@ func reset(field reflect.Value, name string) error {
return nil return nil
} }
// isExported return true is a struct field is exported, else false // isExported return true is a struct field is exported, else false.
func isExported(f reflect.StructField) bool { func isExported(f reflect.StructField) bool {
if f.PkgPath != "" && !f.Anonymous { if f.PkgPath != "" && !f.Anonymous {
return false return false

View file

@ -8,12 +8,12 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
// DashboardHandler expose dashboard routes // DashboardHandler expose dashboard routes.
type DashboardHandler struct { type DashboardHandler struct {
Assets *assetfs.AssetFS Assets *assetfs.AssetFS
} }
// Append add dashboard routes on a router // Append add dashboard routes on a router.
func (g DashboardHandler) Append(router *mux.Router) { func (g DashboardHandler) Append(router *mux.Router) {
if g.Assets == nil { if g.Assets == nil {
log.WithoutContext().Error("No assets for dashboard") log.WithoutContext().Error("No assets for dashboard")

View file

@ -19,10 +19,10 @@ func goroutines() interface{} {
return runtime.NumGoroutine() return runtime.NumGoroutine()
} }
// DebugHandler expose debug routes // DebugHandler expose debug routes.
type DebugHandler struct{} type DebugHandler struct{}
// Append add debug routes on a router // Append add debug routes on a router.
func (g DebugHandler) Append(router *mux.Router) { func (g DebugHandler) Append(router *mux.Router) {
router.Methods(http.MethodGet).Path("/debug/vars"). router.Methods(http.MethodGet).Path("/debug/vars").
HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {

View file

@ -55,7 +55,7 @@ type Handler struct {
runtimeConfiguration *runtime.Configuration runtimeConfiguration *runtime.Configuration
} }
// NewBuilder returns a http.Handler builder based on runtime.Configuration // NewBuilder returns a http.Handler builder based on runtime.Configuration.
func NewBuilder(staticConfig static.Configuration) func(*runtime.Configuration) http.Handler { func NewBuilder(staticConfig static.Configuration) func(*runtime.Configuration) http.Handler {
return func(configuration *runtime.Configuration) http.Handler { return func(configuration *runtime.Configuration) http.Handler {
return New(staticConfig, configuration).createRouter() return New(staticConfig, configuration).createRouter()

View file

@ -55,7 +55,7 @@ func execute(cmd *Command, args []string, root bool) error {
// Calls command without args. // Calls command without args.
if len(args) == 1 { if len(args) == 1 {
if err := run(cmd, args[1:]); err != nil { if err := run(cmd, args[1:]); err != nil {
return fmt.Errorf("command %s error: %v", args[0], err) return fmt.Errorf("command %s error: %w", args[0], err)
} }
return nil return nil
} }
@ -65,7 +65,7 @@ func execute(cmd *Command, args []string, root bool) error {
// then we run the top level command itself. // then we run the top level command itself.
if root && cmd.Name != args[1] && !contains(cmd.subCommands, args[1]) { if root && cmd.Name != args[1] && !contains(cmd.subCommands, args[1]) {
if err := run(cmd, args[1:]); err != nil { if err := run(cmd, args[1:]); err != nil {
return fmt.Errorf("command %s error: %v", filepath.Base(args[0]), err) return fmt.Errorf("command %s error: %w", filepath.Base(args[0]), err)
} }
return nil return nil
} }
@ -74,7 +74,7 @@ func execute(cmd *Command, args []string, root bool) error {
if len(args) >= 2 && cmd.Name == args[1] { if len(args) >= 2 && cmd.Name == args[1] {
if len(args) < 3 || !contains(cmd.subCommands, args[2]) { if len(args) < 3 || !contains(cmd.subCommands, args[2]) {
if err := run(cmd, args[2:]); err != nil { if err := run(cmd, args[2:]); err != nil {
return fmt.Errorf("command %s error: %v", cmd.Name, err) return fmt.Errorf("command %s error: %w", cmd.Name, err)
} }
return nil return nil
} }
@ -83,7 +83,7 @@ func execute(cmd *Command, args []string, root bool) error {
// No sub-command, calls the current command. // No sub-command, calls the current command.
if len(cmd.subCommands) == 0 { if len(cmd.subCommands) == 0 {
if err := run(cmd, args[1:]); err != nil { if err := run(cmd, args[1:]); err != nil {
return fmt.Errorf("command %s error: %v", cmd.Name, err) return fmt.Errorf("command %s error: %w", cmd.Name, err)
} }
return nil return nil
} }

View file

@ -21,7 +21,7 @@ func (e *EnvLoader) Load(_ []string, cmd *Command) (bool, error) {
if err := env.Decode(vars, env.DefaultNamePrefix, cmd.Configuration); err != nil { if err := env.Decode(vars, env.DefaultNamePrefix, cmd.Configuration); err != nil {
log.WithoutContext().Debug("environment variables", strings.Join(vars, ", ")) log.WithoutContext().Debug("environment variables", strings.Join(vars, ", "))
return false, fmt.Errorf("failed to decode configuration from environment variables: %v ", err) return false, fmt.Errorf("failed to decode configuration from environment variables: %w ", err)
} }
log.WithoutContext().Println("Configuration loaded from environment variables.") log.WithoutContext().Println("Configuration loaded from environment variables.")

View file

@ -17,7 +17,7 @@ func (*FlagLoader) Load(args []string, cmd *Command) (bool, error) {
} }
if err := flag.Decode(args, cmd.Configuration); err != nil { if err := flag.Decode(args, cmd.Configuration); err != nil {
return false, fmt.Errorf("failed to decode configuration from flags: %v", err) return false, fmt.Errorf("failed to decode configuration from flags: %w", err)
} }
log.WithoutContext().Println("Configuration loaded from flags.") log.WithoutContext().Println("Configuration loaded from flags.")

View file

@ -16,10 +16,10 @@ import (
"github.com/mitchellh/hashstructure" "github.com/mitchellh/hashstructure"
) )
// collectorURL URL where the stats are send // collectorURL URL where the stats are send.
const collectorURL = "https://collect.traefik.io/9vxmmkcdmalbdi635d4jgc5p5rx0h7h8" const collectorURL = "https://collect.traefik.io/9vxmmkcdmalbdi635d4jgc5p5rx0h7h8"
// Collected data // Collected data.
type data struct { type data struct {
Version string Version string
Codename string Codename string

View file

@ -19,7 +19,7 @@ type Configurations map[string]*Configuration
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// Configuration is the root of the dynamic configuration // Configuration is the root of the dynamic configuration.
type Configuration struct { type Configuration struct {
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty"` HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty"`
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty"` TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty"`

View file

@ -47,7 +47,7 @@ type Router struct {
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// RouterTLSConfig holds the TLS configuration for a router // RouterTLSConfig holds the TLS configuration for a router.
type RouterTLSConfig struct { type RouterTLSConfig struct {
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"` Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"` CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`

View file

@ -95,7 +95,7 @@ type Buffering struct {
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// Chain holds a chain of middlewares // Chain holds a chain of middlewares.
type Chain struct { type Chain struct {
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"` Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
} }
@ -191,13 +191,13 @@ type Headers struct {
IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty"` IsDevelopment bool `json:"isDevelopment,omitempty" toml:"isDevelopment,omitempty" yaml:"isDevelopment,omitempty"`
} }
// HasCustomHeadersDefined checks to see if any of the custom header elements have been set // HasCustomHeadersDefined checks to see if any of the custom header elements have been set.
func (h *Headers) HasCustomHeadersDefined() bool { func (h *Headers) HasCustomHeadersDefined() bool {
return h != nil && (len(h.CustomResponseHeaders) != 0 || return h != nil && (len(h.CustomResponseHeaders) != 0 ||
len(h.CustomRequestHeaders) != 0) len(h.CustomRequestHeaders) != 0)
} }
// HasCorsHeadersDefined checks to see if any of the cors header elements have been set // HasCorsHeadersDefined checks to see if any of the cors header elements have been set.
func (h *Headers) HasCorsHeadersDefined() bool { func (h *Headers) HasCorsHeadersDefined() bool {
return h != nil && (h.AccessControlAllowCredentials || return h != nil && (h.AccessControlAllowCredentials ||
len(h.AccessControlAllowHeaders) != 0 || len(h.AccessControlAllowHeaders) != 0 ||
@ -208,7 +208,7 @@ func (h *Headers) HasCorsHeadersDefined() bool {
h.AddVaryHeader) h.AddVaryHeader)
} }
// HasSecureHeadersDefined checks to see if any of the secure header elements have been set // HasSecureHeadersDefined checks to see if any of the secure header elements have been set.
func (h *Headers) HasSecureHeadersDefined() bool { func (h *Headers) HasSecureHeadersDefined() bool {
return h != nil && (len(h.AllowedHosts) != 0 || return h != nil && (len(h.AllowedHosts) != 0 ||
len(h.HostsProxyHeaders) != 0 || len(h.HostsProxyHeaders) != 0 ||
@ -245,7 +245,7 @@ type IPStrategy struct {
// Get an IP selection strategy. // Get an IP selection strategy.
// If nil return the RemoteAddr strategy // If nil return the RemoteAddr strategy
// else return a strategy base on the configuration using the X-Forwarded-For Header. // else return a strategy base on the configuration using the X-Forwarded-For Header.
// Depth override the ExcludedIPs // Depth override the ExcludedIPs.
func (s *IPStrategy) Get() (ip.Strategy, error) { func (s *IPStrategy) Get() (ip.Strategy, error) {
if s == nil { if s == nil {
return &ip.RemoteAddrStrategy{}, nil return &ip.RemoteAddrStrategy{}, nil
@ -420,7 +420,7 @@ type TLSCLientCertificateDNInfo struct {
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// Users holds a list of users // Users holds a list of users.
type Users []string type Users []string
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
@ -449,7 +449,7 @@ func (c *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
if _, errCA := os.Stat(c.CA); errCA == nil { if _, errCA := os.Stat(c.CA); errCA == nil {
ca, err = ioutil.ReadFile(c.CA) ca, err = ioutil.ReadFile(c.CA)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read CA. %s", err) return nil, fmt.Errorf("failed to read CA. %w", err)
} }
} else { } else {
ca = []byte(c.CA) ca = []byte(c.CA)
@ -478,7 +478,7 @@ func (c *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
if errKeyIsFile == nil { if errKeyIsFile == nil {
cert, err = tls.LoadX509KeyPair(c.Cert, c.Key) cert, err = tls.LoadX509KeyPair(c.Cert, c.Key)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %v", err) return nil, fmt.Errorf("failed to load TLS keypair: %w", err)
} }
} else { } else {
return nil, fmt.Errorf("tls cert is a file, but tls key is not") return nil, fmt.Errorf("tls cert is a file, but tls key is not")
@ -487,7 +487,7 @@ func (c *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
if errKeyIsFile != nil { if errKeyIsFile != nil {
cert, err = tls.X509KeyPair([]byte(c.Cert), []byte(c.Key)) cert, err = tls.X509KeyPair([]byte(c.Cert), []byte(c.Key))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %v", err) return nil, fmt.Errorf("failed to load TLS keypair: %w", err)
} }
} else { } else {
return nil, fmt.Errorf("TLS key is a file, but tls cert is not") return nil, fmt.Errorf("TLS key is a file, but tls cert is not")

View file

@ -55,7 +55,7 @@ type TCPRouter struct {
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// RouterTCPTLSConfig holds the TLS configuration for a router // RouterTCPTLSConfig holds the TLS configuration for a router.
type RouterTCPTLSConfig struct { type RouterTCPTLSConfig struct {
Passthrough bool `json:"passthrough" toml:"passthrough" yaml:"passthrough"` Passthrough bool `json:"passthrough" toml:"passthrough" yaml:"passthrough"`
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"` Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
@ -76,7 +76,7 @@ type TCPServersLoadBalancer struct {
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"` Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server"`
} }
// SetDefaults Default values for a TCPServersLoadBalancer // SetDefaults Default values for a TCPServersLoadBalancer.
func (l *TCPServersLoadBalancer) SetDefaults() { func (l *TCPServersLoadBalancer) SetDefaults() {
defaultTerminationDelay := 100 // in milliseconds defaultTerminationDelay := 100 // in milliseconds
l.TerminationDelay = &defaultTerminationDelay l.TerminationDelay = &defaultTerminationDelay
@ -101,7 +101,7 @@ func (l *TCPServersLoadBalancer) Mergeable(loadBalancer *TCPServersLoadBalancer)
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// TCPServer holds a TCP Server configuration // TCPServer holds a TCP Server configuration.
type TCPServer struct { type TCPServer struct {
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty" label:"-"` Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty" label:"-"`
Port string `toml:"-" json:"-" yaml:"-"` Port string `toml:"-" json:"-" yaml:"-"`

View file

@ -17,7 +17,7 @@ const DefaultNamePrefix = "TRAEFIK_"
// env vars -> map // env vars -> map
// map -> tree of untyped nodes // map -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element) // untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> typed element // "typed" nodes -> typed element.
func Decode(environ []string, prefix string, element interface{}) error { func Decode(environ []string, prefix string, element interface{}) error {
if err := checkPrefix(prefix); err != nil { if err := checkPrefix(prefix); err != nil {
return err return err
@ -40,7 +40,7 @@ func Decode(environ []string, prefix string, element interface{}) error {
// The operation goes through three stages roughly summarized as: // The operation goes through three stages roughly summarized as:
// typed configuration in element -> tree of untyped nodes // typed configuration in element -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element) // untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> environment variables with default values (determined by type/kind) // "typed" nodes -> environment variables with default values (determined by type/kind).
func Encode(element interface{}) ([]parser.Flat, error) { func Encode(element interface{}) ([]parser.Flat, error) {
if element == nil { if element == nil {
return nil, nil return nil, nil

View file

@ -9,7 +9,7 @@ import (
// The operation goes through three stages roughly summarized as: // The operation goes through three stages roughly summarized as:
// file contents -> tree of untyped nodes // file contents -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element) // untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> typed element // "typed" nodes -> typed element.
func Decode(filePath string, element interface{}) error { func Decode(filePath string, element interface{}) error {
if element == nil { if element == nil {
return nil return nil

View file

@ -10,7 +10,7 @@ import (
// flag arguments -> parsed map of flags // flag arguments -> parsed map of flags
// map -> tree of untyped nodes // map -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element) // untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> typed element // "typed" nodes -> typed element.
func Decode(args []string, element interface{}) error { func Decode(args []string, element interface{}) error {
ref, err := Parse(args, element) ref, err := Parse(args, element)
if err != nil { if err != nil {
@ -24,7 +24,7 @@ func Decode(args []string, element interface{}) error {
// The operation goes through three stages roughly summarized as: // The operation goes through three stages roughly summarized as:
// typed configuration in element -> tree of untyped nodes // typed configuration in element -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element) // untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> flags with default values (determined by type/kind) // "typed" nodes -> flags with default values (determined by type/kind).
func Encode(element interface{}) ([]parser.Flat, error) { func Encode(element interface{}) ([]parser.Flat, error) {
if element == nil { if element == nil {
return nil, nil return nil, nil

View file

@ -12,7 +12,7 @@ import (
// The operation goes through three stages roughly summarized as: // The operation goes through three stages roughly summarized as:
// KV pairs -> tree of untyped nodes // KV pairs -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element) // untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> typed element // "typed" nodes -> typed element.
func Decode(pairs []*store.KVPair, element interface{}, rootName string) error { func Decode(pairs []*store.KVPair, element interface{}, rootName string) error {
if element == nil { if element == nil {
return nil return nil

View file

@ -28,7 +28,7 @@ func EncodeConfiguration(conf *dynamic.Configuration) (map[string]string, error)
} }
// Decode converts the labels to an element. // Decode converts the labels to an element.
// labels -> [ node -> node + metadata (type) ] -> element (node) // labels -> [ node -> node + metadata (type) ] -> element (node).
func Decode(labels map[string]string, element interface{}, filters ...string) error { func Decode(labels map[string]string, element interface{}, filters ...string) error {
return parser.Decode(labels, element, parser.DefaultRootName, filters...) return parser.Decode(labels, element, parser.DefaultRootName, filters...)
} }

View file

@ -15,7 +15,7 @@ type EncoderToNodeOpts struct {
} }
// EncodeToNode converts an element to a node. // EncodeToNode converts an element to a node.
// element -> nodes // element -> nodes.
func EncodeToNode(element interface{}, rootName string, opts EncoderToNodeOpts) (*Node, error) { func EncodeToNode(element interface{}, rootName string, opts EncoderToNodeOpts) (*Node, error) {
rValue := reflect.ValueOf(element) rValue := reflect.ValueOf(element)
node := &Node{Name: rootName} node := &Node{Name: rootName}

View file

@ -1,7 +1,7 @@
package parser package parser
// EncodeNode Converts a node to labels. // EncodeNode Converts a node to labels.
// nodes -> labels // nodes -> labels.
func EncodeNode(node *Node) map[string]string { func EncodeNode(node *Node) map[string]string {
labels := make(map[string]string) labels := make(map[string]string)
encodeNode(labels, node.Name, node) encodeNode(labels, node.Name, node)

View file

@ -6,7 +6,7 @@ package parser
// The operation goes through three stages roughly summarized as: // The operation goes through three stages roughly summarized as:
// labels -> tree of untyped nodes // labels -> tree of untyped nodes
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element) // untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
// "typed" nodes -> typed element // "typed" nodes -> typed element.
func Decode(labels map[string]string, element interface{}, rootName string, filters ...string) error { func Decode(labels map[string]string, element interface{}, rootName string, filters ...string) error {
node, err := DecodeToNode(labels, rootName, filters...) node, err := DecodeToNode(labels, rootName, filters...)
if err != nil { if err != nil {
@ -28,7 +28,7 @@ func Decode(labels map[string]string, element interface{}, rootName string, filt
} }
// Encode converts an element to labels. // Encode converts an element to labels.
// element -> node (value) -> label (node) // element -> node (value) -> label (node).
func Encode(element interface{}, rootName string) (map[string]string, error) { func Encode(element interface{}, rootName string) (map[string]string, error) {
etnOpts := EncoderToNodeOpts{OmitEmpty: true, TagName: TagLabel, AllowSliceAsStruct: true} etnOpts := EncoderToNodeOpts{OmitEmpty: true, TagName: TagLabel, AllowSliceAsStruct: true}
node, err := EncodeToNode(element, rootName, etnOpts) node, err := EncodeToNode(element, rootName, etnOpts)

View file

@ -8,7 +8,7 @@ import (
"github.com/containous/traefik/v2/pkg/log" "github.com/containous/traefik/v2/pkg/log"
) )
// Status of the router/service // Status of the router/service.
const ( const (
StatusEnabled = "enabled" StatusEnabled = "enabled"
StatusDisabled = "disabled" StatusDisabled = "disabled"

View file

@ -179,7 +179,7 @@ func (s *ServiceInfo) UpdateServerStatus(server string, status string) {
} }
// GetAllStatus returns all the statuses of all the servers in ServiceInfo. // GetAllStatus returns all the statuses of all the servers in ServiceInfo.
// It is the responsibility of the caller to check that s is not nil // It is the responsibility of the caller to check that s is not nil.
func (s *ServiceInfo) GetAllStatus() map[string]string { func (s *ServiceInfo) GetAllStatus() map[string]string {
s.serverStatusMu.RLock() s.serverStatusMu.RLock()
defer s.serverStatusMu.RUnlock() defer s.serverStatusMu.RUnlock()

View file

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// all the Routers/Middlewares/Services are considered fully qualified // all the Routers/Middlewares/Services are considered fully qualified.
func TestPopulateUsedBy(t *testing.T) { func TestPopulateUsedBy(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string

View file

@ -49,7 +49,7 @@ const (
DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory" DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory"
) )
// Configuration is the static configuration // Configuration is the static configuration.
type Configuration struct { type Configuration struct {
Global *Global `description:"Global configuration options" json:"global,omitempty" toml:"global,omitempty" yaml:"global,omitempty" export:"true"` Global *Global `description:"Global configuration options" json:"global,omitempty" toml:"global,omitempty" yaml:"global,omitempty" export:"true"`
@ -81,7 +81,7 @@ type Global struct {
SendAnonymousUsage bool `description:"Periodically send anonymous usage statistics. If the option is not specified, it will be enabled by default." json:"sendAnonymousUsage,omitempty" toml:"sendAnonymousUsage,omitempty" yaml:"sendAnonymousUsage,omitempty" label:"allowEmpty" export:"true"` SendAnonymousUsage bool `description:"Periodically send anonymous usage statistics. If the option is not specified, it will be enabled by default." json:"sendAnonymousUsage,omitempty" toml:"sendAnonymousUsage,omitempty" yaml:"sendAnonymousUsage,omitempty" label:"allowEmpty" export:"true"`
} }
// ServersTransport options to configure communication between Traefik and the servers // ServersTransport options to configure communication between Traefik and the servers.
type ServersTransport struct { type ServersTransport struct {
InsecureSkipVerify bool `description:"Disable SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"` InsecureSkipVerify bool `description:"Disable SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
RootCAs []tls.FileOrContent `description:"Add cert file for self-signed certificate." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"` RootCAs []tls.FileOrContent `description:"Add cert file for self-signed certificate." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
@ -89,7 +89,7 @@ type ServersTransport struct {
ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"` ForwardingTimeouts *ForwardingTimeouts `description:"Timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
} }
// API holds the API configuration // API holds the API configuration.
type API struct { type API struct {
Insecure bool `description:"Activate API directly on the entryPoint named traefik." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"` Insecure bool `description:"Activate API directly on the entryPoint named traefik." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
Dashboard bool `description:"Activate dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty" export:"true"` Dashboard bool `description:"Activate dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty" export:"true"`
@ -158,7 +158,7 @@ func (t *Tracing) SetDefaults() {
t.SpanNameLimit = 0 t.SpanNameLimit = 0
} }
// Providers contains providers configuration // Providers contains providers configuration.
type Providers struct { type Providers struct {
ProvidersThrottleDuration types.Duration `description:"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." json:"providersThrottleDuration,omitempty" toml:"providersThrottleDuration,omitempty" yaml:"providersThrottleDuration,omitempty" export:"true"` ProvidersThrottleDuration types.Duration `description:"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." json:"providersThrottleDuration,omitempty" toml:"providersThrottleDuration,omitempty" yaml:"providersThrottleDuration,omitempty" export:"true"`
@ -224,7 +224,7 @@ func (c *Configuration) initACMEProvider() {
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0) legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
} }
// ValidateConfiguration validate that configuration is coherent // ValidateConfiguration validate that configuration is coherent.
func (c *Configuration) ValidateConfiguration() error { func (c *Configuration) ValidateConfiguration() error {
var acmeEmail string var acmeEmail string
for name, resolver := range c.CertificatesResolvers { for name, resolver := range c.CertificatesResolvers {

View file

@ -25,8 +25,7 @@ const (
var singleton *HealthCheck var singleton *HealthCheck
var once sync.Once var once sync.Once
// Balancer is the set of operations required to manage the list of servers in a // Balancer is the set of operations required to manage the list of servers in a load-balancer.
// load-balancer.
type Balancer interface { type Balancer interface {
Servers() []*url.URL Servers() []*url.URL
RemoveServer(u *url.URL) error RemoveServer(u *url.URL) error
@ -39,8 +38,9 @@ type BalancerHandler interface {
Balancer Balancer
} }
// metricsRegistry is a local interface in the health check package, exposing only the required metrics // metricsRegistry is a local interface in the health check package,
// necessary for the health check package. This makes it easier for the tests. // exposing only the required metrics necessary for the health check package.
// This makes it easier for the tests.
type metricsRegistry interface { type metricsRegistry interface {
BackendServerUpGauge() metrics.Gauge BackendServerUpGauge() metrics.Gauge
} }
@ -68,7 +68,7 @@ type backendURL struct {
weight int weight int
} }
// BackendConfig HealthCheck configuration for a backend // BackendConfig HealthCheck configuration for a backend.
type BackendConfig struct { type BackendConfig struct {
Options Options
name string name string
@ -92,7 +92,7 @@ func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {
return http.NewRequest(http.MethodGet, u.String(), http.NoBody) return http.NewRequest(http.MethodGet, u.String(), http.NoBody)
} }
// this function adds additional http headers and hostname to http.request // this function adds additional http headers and hostname to http.request.
func (b *BackendConfig) addHeadersAndHost(req *http.Request) *http.Request { func (b *BackendConfig) addHeadersAndHost(req *http.Request) *http.Request {
if b.Options.Hostname != "" { if b.Options.Hostname != "" {
req.Host = b.Options.Hostname req.Host = b.Options.Hostname
@ -104,14 +104,14 @@ func (b *BackendConfig) addHeadersAndHost(req *http.Request) *http.Request {
return req return req
} }
// HealthCheck struct // HealthCheck struct.
type HealthCheck struct { type HealthCheck struct {
Backends map[string]*BackendConfig Backends map[string]*BackendConfig
metrics metricsRegistry metrics metricsRegistry
cancel context.CancelFunc cancel context.CancelFunc
} }
// SetBackendsConfiguration set backends configuration // SetBackendsConfiguration set backends configuration.
func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backends map[string]*BackendConfig) { func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backends map[string]*BackendConfig) {
hc.Backends = backends hc.Backends = backends
if hc.cancel != nil { if hc.cancel != nil {
@ -152,28 +152,21 @@ func (hc *HealthCheck) checkBackend(ctx context.Context, backend *BackendConfig)
enabledURLs := backend.LB.Servers() enabledURLs := backend.LB.Servers()
var newDisabledURLs []backendURL var newDisabledURLs []backendURL
// FIXME re enable metrics
for _, disabledURL := range backend.disabledURLs { for _, disabledURL := range backend.disabledURLs {
// FIXME serverUpMetricValue := float64(0)
if err := checkHealth(disabledURL.url, backend); err == nil { if err := checkHealth(disabledURL.url, backend); err == nil {
logger.Warnf("Health check up: Returning to server list. Backend: %q URL: %q Weight: %d", logger.Warnf("Health check up: Returning to server list. Backend: %q URL: %q Weight: %d",
backend.name, disabledURL.url.String(), disabledURL.weight) backend.name, disabledURL.url.String(), disabledURL.weight)
if err = backend.LB.UpsertServer(disabledURL.url, roundrobin.Weight(disabledURL.weight)); err != nil { if err = backend.LB.UpsertServer(disabledURL.url, roundrobin.Weight(disabledURL.weight)); err != nil {
logger.Error(err) logger.Error(err)
} }
// FIXME serverUpMetricValue = 1
} else { } else {
logger.Warnf("Health check still failing. Backend: %q URL: %q Reason: %s", backend.name, disabledURL.url.String(), err) logger.Warnf("Health check still failing. Backend: %q URL: %q Reason: %s", backend.name, disabledURL.url.String(), err)
newDisabledURLs = append(newDisabledURLs, disabledURL) newDisabledURLs = append(newDisabledURLs, disabledURL)
} }
// FIXME labelValues := []string{"backend", backend.name, "url", backendurl.url.String()}
// FIXME hc.metrics.BackendServerUpGauge().With(labelValues...).Set(serverUpMetricValue)
} }
backend.disabledURLs = newDisabledURLs backend.disabledURLs = newDisabledURLs
// FIXME re enable metrics
for _, enableURL := range enabledURLs { for _, enableURL := range enabledURLs {
// FIXME serverUpMetricValue := float64(1)
if err := checkHealth(enableURL, backend); err != nil { if err := checkHealth(enableURL, backend); err != nil {
weight := 1 weight := 1
rr, ok := backend.LB.(*roundrobin.RoundRobin) rr, ok := backend.LB.(*roundrobin.RoundRobin)
@ -189,35 +182,25 @@ func (hc *HealthCheck) checkBackend(ctx context.Context, backend *BackendConfig)
logger.Error(err) logger.Error(err)
} }
backend.disabledURLs = append(backend.disabledURLs, backendURL{enableURL, weight}) backend.disabledURLs = append(backend.disabledURLs, backendURL{enableURL, weight})
// FIXME serverUpMetricValue = 0
} }
// FIXME labelValues := []string{"backend", backend.name, "url", enableURL.String()}
// FIXME hc.metrics.BackendServerUpGauge().With(labelValues...).Set(serverUpMetricValue)
} }
} }
// FIXME re add metrics
//func GetHealthCheck(metrics metricsRegistry) *HealthCheck {
// GetHealthCheck returns the health check which is guaranteed to be a singleton. // GetHealthCheck returns the health check which is guaranteed to be a singleton.
func GetHealthCheck() *HealthCheck { func GetHealthCheck() *HealthCheck {
once.Do(func() { once.Do(func() {
singleton = newHealthCheck() singleton = newHealthCheck()
//singleton = newHealthCheck(metrics)
}) })
return singleton return singleton
} }
// FIXME re add metrics
//func newHealthCheck(metrics metricsRegistry) *HealthCheck {
func newHealthCheck() *HealthCheck { func newHealthCheck() *HealthCheck {
return &HealthCheck{ return &HealthCheck{
Backends: make(map[string]*BackendConfig), Backends: make(map[string]*BackendConfig),
//metrics: metrics,
} }
} }
// NewBackendConfig Instantiate a new BackendConfig // NewBackendConfig Instantiate a new BackendConfig.
func NewBackendConfig(options Options, backendName string) *BackendConfig { func NewBackendConfig(options Options, backendName string) *BackendConfig {
return &BackendConfig{ return &BackendConfig{
Options: options, Options: options,
@ -230,7 +213,7 @@ func NewBackendConfig(options Options, backendName string) *BackendConfig {
func checkHealth(serverURL *url.URL, backend *BackendConfig) error { func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
req, err := backend.newRequest(serverURL) req, err := backend.newRequest(serverURL)
if err != nil { if err != nil {
return fmt.Errorf("failed to create HTTP request: %s", err) return fmt.Errorf("failed to create HTTP request: %w", err)
} }
req = backend.addHeadersAndHost(req) req = backend.addHeadersAndHost(req)
@ -248,7 +231,7 @@ func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return fmt.Errorf("HTTP request failed: %s", err) return fmt.Errorf("HTTP request failed: %w", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -260,7 +243,7 @@ func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
return nil return nil
} }
// NewLBStatusUpdater returns a new LbStatusUpdater // NewLBStatusUpdater returns a new LbStatusUpdater.
func NewLBStatusUpdater(bh BalancerHandler, info *runtime.ServiceInfo) *LbStatusUpdater { func NewLBStatusUpdater(bh BalancerHandler, info *runtime.ServiceInfo) *LbStatusUpdater {
return &LbStatusUpdater{ return &LbStatusUpdater{
BalancerHandler: bh, BalancerHandler: bh,
@ -298,7 +281,7 @@ func (lb *LbStatusUpdater) UpsertServer(u *url.URL, options ...roundrobin.Server
// Balancers is a list of Balancers(s) that implements the Balancer interface. // Balancers is a list of Balancers(s) that implements the Balancer interface.
type Balancers []Balancer type Balancers []Balancer
// Servers returns the servers url from all the BalancerHandler // Servers returns the servers url from all the BalancerHandler.
func (b Balancers) Servers() []*url.URL { func (b Balancers) Servers() []*url.URL {
var servers []*url.URL var servers []*url.URL
for _, lb := range b { for _, lb := range b {

View file

@ -7,13 +7,13 @@ import (
"strings" "strings"
) )
// Checker allows to check that addresses are in a trusted IPs // Checker allows to check that addresses are in a trusted IPs.
type Checker struct { type Checker struct {
authorizedIPs []*net.IP authorizedIPs []*net.IP
authorizedIPsNet []*net.IPNet authorizedIPsNet []*net.IPNet
} }
// NewChecker builds a new Checker given a list of CIDR-Strings to trusted IPs // NewChecker builds a new Checker given a list of CIDR-Strings to trusted IPs.
func NewChecker(trustedIPs []string) (*Checker, error) { func NewChecker(trustedIPs []string) (*Checker, error) {
if len(trustedIPs) == 0 { if len(trustedIPs) == 0 {
return nil, errors.New("no trusted IPs provided") return nil, errors.New("no trusted IPs provided")
@ -27,7 +27,7 @@ func NewChecker(trustedIPs []string) (*Checker, error) {
} else { } else {
_, ipAddr, err := net.ParseCIDR(ipMask) _, ipAddr, err := net.ParseCIDR(ipMask)
if err != nil { if err != nil {
return nil, fmt.Errorf("parsing CIDR trusted IPs %s: %v", ipAddr, err) return nil, fmt.Errorf("parsing CIDR trusted IPs %s: %w", ipAddr, err)
} }
checker.authorizedIPsNet = append(checker.authorizedIPsNet, ipAddr) checker.authorizedIPsNet = append(checker.authorizedIPsNet, ipAddr)
} }
@ -36,7 +36,7 @@ func NewChecker(trustedIPs []string) (*Checker, error) {
return checker, nil return checker, nil
} }
// IsAuthorized checks if provided request is authorized by the trusted IPs // IsAuthorized checks if provided request is authorized by the trusted IPs.
func (ip *Checker) IsAuthorized(addr string) error { func (ip *Checker) IsAuthorized(addr string) error {
var invalidMatches []string var invalidMatches []string
@ -58,7 +58,7 @@ func (ip *Checker) IsAuthorized(addr string) error {
return nil return nil
} }
// Contains checks if provided address is in the trusted IPs // Contains checks if provided address is in the trusted IPs.
func (ip *Checker) Contains(addr string) (bool, error) { func (ip *Checker) Contains(addr string) (bool, error) {
if len(addr) == 0 { if len(addr) == 0 {
return false, errors.New("empty IP address") return false, errors.New("empty IP address")
@ -66,13 +66,13 @@ func (ip *Checker) Contains(addr string) (bool, error) {
ipAddr, err := parseIP(addr) ipAddr, err := parseIP(addr)
if err != nil { if err != nil {
return false, fmt.Errorf("unable to parse address: %s: %s", addr, err) return false, fmt.Errorf("unable to parse address: %s: %w", addr, err)
} }
return ip.ContainsIP(ipAddr), nil return ip.ContainsIP(ipAddr), nil
} }
// ContainsIP checks if provided address is in the trusted IPs // ContainsIP checks if provided address is in the trusted IPs.
func (ip *Checker) ContainsIP(addr net.IP) bool { func (ip *Checker) ContainsIP(addr net.IP) bool {
for _, authorizedIP := range ip.authorizedIPs { for _, authorizedIP := range ip.authorizedIPs {
if authorizedIP.Equal(addr) { if authorizedIP.Equal(addr) {

View file

@ -10,15 +10,15 @@ const (
xForwardedFor = "X-Forwarded-For" xForwardedFor = "X-Forwarded-For"
) )
// Strategy a strategy for IP selection // Strategy a strategy for IP selection.
type Strategy interface { type Strategy interface {
GetIP(req *http.Request) string GetIP(req *http.Request) string
} }
// RemoteAddrStrategy a strategy that always return the remote address // RemoteAddrStrategy a strategy that always return the remote address.
type RemoteAddrStrategy struct{} type RemoteAddrStrategy struct{}
// GetIP returns the selected IP // GetIP returns the selected IP.
func (s *RemoteAddrStrategy) GetIP(req *http.Request) string { func (s *RemoteAddrStrategy) GetIP(req *http.Request) string {
ip, _, err := net.SplitHostPort(req.RemoteAddr) ip, _, err := net.SplitHostPort(req.RemoteAddr)
if err != nil { if err != nil {
@ -27,12 +27,12 @@ func (s *RemoteAddrStrategy) GetIP(req *http.Request) string {
return ip return ip
} }
// DepthStrategy a strategy based on the depth inside the X-Forwarded-For from right to left // DepthStrategy a strategy based on the depth inside the X-Forwarded-For from right to left.
type DepthStrategy struct { type DepthStrategy struct {
Depth int Depth int
} }
// GetIP return the selected IP // GetIP return the selected IP.
func (s *DepthStrategy) GetIP(req *http.Request) string { func (s *DepthStrategy) GetIP(req *http.Request) string {
xff := req.Header.Get(xForwardedFor) xff := req.Header.Get(xForwardedFor)
xffs := strings.Split(xff, ",") xffs := strings.Split(xff, ",")
@ -44,12 +44,12 @@ func (s *DepthStrategy) GetIP(req *http.Request) string {
} }
// CheckerStrategy a strategy based on an IP Checker // CheckerStrategy a strategy based on an IP Checker
// allows to check that addresses are in a trusted IPs // allows to check that addresses are in a trusted IPs.
type CheckerStrategy struct { type CheckerStrategy struct {
Checker *Checker Checker *Checker
} }
// GetIP return the selected IP // GetIP return the selected IP.
func (s *CheckerStrategy) GetIP(req *http.Request) string { func (s *CheckerStrategy) GetIP(req *http.Request) string {
if s.Checker == nil { if s.Checker == nil {
return "" return ""

View file

@ -80,7 +80,7 @@ func AddHook(hook logrus.Hook) {
} }
// CustomWriterLevel logs writer for a specific level. (with a custom scanner buffer size.) // CustomWriterLevel logs writer for a specific level. (with a custom scanner buffer size.)
// adapted from github.com/Sirupsen/logrus/writer.go // adapted from github.com/Sirupsen/logrus/writer.go.
func CustomWriterLevel(level logrus.Level, maxScanTokenSize int) *io.PipeWriter { func CustomWriterLevel(level logrus.Level, maxScanTokenSize int) *io.PipeWriter {
reader, writer := io.Pipe() reader, writer := io.Pipe()
@ -110,7 +110,7 @@ func CustomWriterLevel(level logrus.Level, maxScanTokenSize int) *io.PipeWriter
} }
// extract from github.com/Sirupsen/logrus/writer.go // extract from github.com/Sirupsen/logrus/writer.go
// Hack the buffer size // Hack the buffer size.
func writerScanner(reader io.ReadCloser, scanTokenSize int, printFunc func(args ...interface{})) { func writerScanner(reader io.ReadCloser, scanTokenSize int, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader) scanner := bufio.NewScanner(reader)

View file

@ -1,6 +1,6 @@
package log package log
// Log entry name // Log entry names.
const ( const (
EntryPointName = "entryPointName" EntryPointName = "entryPointName"
RouterName = "routerName" RouterName = "routerName"

View file

@ -15,7 +15,7 @@ const (
loggerKey contextKey = iota loggerKey contextKey = iota
) )
// Logger the Traefik logger // Logger the Traefik logger.
type Logger interface { type Logger interface {
logrus.FieldLogger logrus.FieldLogger
WriterLevel(logrus.Level) *io.PipeWriter WriterLevel(logrus.Level) *io.PipeWriter
@ -57,14 +57,14 @@ func GetLevel() logrus.Level {
return logrus.GetLevel() return logrus.GetLevel()
} }
// Str adds a string field // Str adds a string field.
func Str(key, value string) func(logrus.Fields) { func Str(key, value string) func(logrus.Fields) {
return func(fields logrus.Fields) { return func(fields logrus.Fields) {
fields[key] = value fields[key] = value
} }
} }
// With Adds fields // With Adds fields.
func With(ctx context.Context, opts ...func(logrus.Fields)) context.Context { func With(ctx context.Context, opts ...func(logrus.Fields)) context.Context {
logger := FromContext(ctx) logger := FromContext(ctx)
@ -77,7 +77,7 @@ func With(ctx context.Context, opts ...func(logrus.Fields)) context.Context {
return context.WithValue(ctx, loggerKey, logger) return context.WithValue(ctx, loggerKey, logger)
} }
// FromContext Gets the logger from context // FromContext Gets the logger from context.
func FromContext(ctx context.Context) Logger { func FromContext(ctx context.Context) Logger {
if ctx == nil { if ctx == nil {
panic("nil context") panic("nil context")
@ -91,12 +91,12 @@ func FromContext(ctx context.Context) Logger {
return logger return logger
} }
// WithoutContext Gets the main logger // WithoutContext Gets the main logger.
func WithoutContext() Logger { func WithoutContext() Logger {
return mainLogger return mainLogger
} }
// OpenFile opens the log file using the specified path // OpenFile opens the log file using the specified path.
func OpenFile(path string) error { func OpenFile(path string) error {
logFilePath = path logFilePath = path
@ -110,7 +110,7 @@ func OpenFile(path string) error {
return nil return nil
} }
// CloseFile closes the log and sets the Output to stdout // CloseFile closes the log and sets the Output to stdout.
func CloseFile() error { func CloseFile() error {
logrus.SetOutput(os.Stdout) logrus.SetOutput(os.Stdout)
@ -120,9 +120,8 @@ func CloseFile() error {
return nil return nil
} }
// RotateFile closes and reopens the log file to allow for rotation // RotateFile closes and reopens the log file to allow for rotation by an external source.
// by an external source. If the log isn't backed by a file then // If the log isn't backed by a file then it does nothing.
// it does nothing.
func RotateFile() error { func RotateFile() error {
logger := FromContext(context.Background()) logger := FromContext(context.Background())

View file

@ -80,7 +80,7 @@ func RegisterInfluxDB(ctx context.Context, config *types.InfluxDB) Registry {
return registry return registry
} }
// initInfluxDBTicker creates a influxDBClient // initInfluxDBTicker creates a influxDBClient.
func initInfluxDBClient(ctx context.Context, config *types.InfluxDB) *influx.Influx { func initInfluxDBClient(ctx context.Context, config *types.InfluxDB) *influx.Influx {
logger := log.FromContext(ctx) logger := log.FromContext(ctx)
@ -123,7 +123,7 @@ func initInfluxDBClient(ctx context.Context, config *types.InfluxDB) *influx.Inf
})) }))
} }
// initInfluxDBTicker initializes metrics pusher // initInfluxDBTicker initializes metrics pusher.
func initInfluxDBTicker(ctx context.Context, config *types.InfluxDB) *time.Ticker { func initInfluxDBTicker(ctx context.Context, config *types.InfluxDB) *time.Ticker {
report := time.NewTicker(time.Duration(config.PushInterval)) report := time.NewTicker(time.Duration(config.PushInterval))
@ -135,7 +135,7 @@ func initInfluxDBTicker(ctx context.Context, config *types.InfluxDB) *time.Ticke
return report return report
} }
// StopInfluxDB stops internal influxDBTicker which controls the pushing of metrics to InfluxDB Agent and resets it to `nil` // StopInfluxDB stops internal influxDBTicker which controls the pushing of metrics to InfluxDB Agent and resets it to `nil`.
func StopInfluxDB() { func StopInfluxDB() {
if influxDBTicker != nil { if influxDBTicker != nil {
influxDBTicker.Stop() influxDBTicker.Stop()

View file

@ -71,7 +71,7 @@ func RegisterStatsd(ctx context.Context, config *types.Statsd) Registry {
return registry return registry
} }
// initStatsdTicker initializes metrics pusher and creates a statsdClient if not created already // initStatsdTicker initializes metrics pusher and creates a statsdClient if not created already.
func initStatsdTicker(ctx context.Context, config *types.Statsd) *time.Ticker { func initStatsdTicker(ctx context.Context, config *types.Statsd) *time.Ticker {
address := config.Address address := config.Address
if len(address) == 0 { if len(address) == 0 {
@ -87,7 +87,7 @@ func initStatsdTicker(ctx context.Context, config *types.Statsd) *time.Ticker {
return report return report
} }
// StopStatsd stops internal statsdTicker which controls the pushing of metrics to StatsD Agent and resets it to `nil` // StopStatsd stops internal statsdTicker which controls the pushing of metrics to StatsD Agent and resets it to `nil`.
func StopStatsd() { func StopStatsd() {
if statsdTicker != nil { if statsdTicker != nil {
statsdTicker.Stop() statsdTicker.Stop()

View file

@ -28,7 +28,7 @@ func newCaptureResponseWriter(rw http.ResponseWriter) capturer {
} }
// captureResponseWriter is a wrapper of type http.ResponseWriter // captureResponseWriter is a wrapper of type http.ResponseWriter
// that tracks request status and size // that tracks request status and size.
type captureResponseWriter struct { type captureResponseWriter struct {
rw http.ResponseWriter rw http.ResponseWriter
status int status int

View file

@ -7,7 +7,7 @@ import (
"github.com/vulcand/oxy/utils" "github.com/vulcand/oxy/utils"
) )
// FieldApply function hook to add data in accesslog // FieldApply function hook to add data in accesslog.
type FieldApply func(rw http.ResponseWriter, r *http.Request, next http.Handler, data *LogData) type FieldApply func(rw http.ResponseWriter, r *http.Request, next http.Handler, data *LogData)
// FieldHandler sends a new field to the logger. // FieldHandler sends a new field to the logger.
@ -39,7 +39,7 @@ func (f *FieldHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
} }
} }
// AddServiceFields add service fields // AddServiceFields add service fields.
func AddServiceFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) { func AddServiceFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) {
data.Core[ServiceURL] = req.URL // note that this is *not* the original incoming URL data.Core[ServiceURL] = req.URL // note that this is *not* the original incoming URL
data.Core[ServiceAddr] = req.URL.Host data.Core[ServiceAddr] = req.URL.Host
@ -47,7 +47,7 @@ func AddServiceFields(rw http.ResponseWriter, req *http.Request, next http.Handl
next.ServeHTTP(rw, req) next.ServeHTTP(rw, req)
} }
// AddOriginFields add origin fields // AddOriginFields add origin fields.
func AddOriginFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) { func AddOriginFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) {
crw := newCaptureResponseWriter(rw) crw := newCaptureResponseWriter(rw)
start := time.Now().UTC() start := time.Now().UTC()

View file

@ -75,7 +75,7 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
if len(config.FilePath) > 0 { if len(config.FilePath) > 0 {
f, err := openAccessLogFile(config.FilePath) f, err := openAccessLogFile(config.FilePath)
if err != nil { if err != nil {
return nil, fmt.Errorf("error opening access log file: %s", err) return nil, fmt.Errorf("error opening access log file: %w", err)
} }
file = f file = f
} }
@ -132,12 +132,12 @@ func openAccessLogFile(filePath string) (*os.File, error) {
dir := filepath.Dir(filePath) dir := filepath.Dir(filePath)
if err := os.MkdirAll(dir, 0755); err != nil { if err := os.MkdirAll(dir, 0755); err != nil {
return nil, fmt.Errorf("failed to create log path %s: %s", dir, err) return nil, fmt.Errorf("failed to create log path %s: %w", dir, err)
} }
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664) file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0664)
if err != nil { if err != nil {
return nil, fmt.Errorf("error opening file %s: %s", filePath, err) return nil, fmt.Errorf("error opening file %s: %w", filePath, err)
} }
return file, nil return file, nil

View file

@ -5,7 +5,7 @@ import (
"regexp" "regexp"
) )
// ParseAccessLog parse line of access log and return a map with each fields // ParseAccessLog parse line of access log and return a map with each fields.
func ParseAccessLog(data string) (map[string]string, error) { func ParseAccessLog(data string) (map[string]string, error) {
var buffer bytes.Buffer var buffer bytes.Buffer
buffer.WriteString(`(\S+)`) // 1 - ClientHost buffer.WriteString(`(\S+)`) // 1 - ClientHost

View file

@ -20,7 +20,7 @@ const (
wwwAuthenticate = "Www-Authenticate" wwwAuthenticate = "Www-Authenticate"
) )
// DigestRequest is a client for digest authentication requests // DigestRequest is a client for digest authentication requests.
type digestRequest struct { type digestRequest struct {
client *http.Client client *http.Client
username, password string username, password string
@ -35,7 +35,7 @@ func (nc nonceCount) String() string {
var wanted = []string{algorithm, nonce, opaque, qop, realm} var wanted = []string{algorithm, nonce, opaque, qop, realm}
// New makes a DigestRequest instance // New makes a DigestRequest instance.
func newDigestRequest(username, password string, client *http.Client) *digestRequest { func newDigestRequest(username, password string, client *http.Client) *digestRequest {
return &digestRequest{ return &digestRequest{
client: client, client: client,
@ -44,7 +44,7 @@ func newDigestRequest(username, password string, client *http.Client) *digestReq
} }
} }
// Do does requests as http.Do does // Do does requests as http.Do does.
func (r *digestRequest) Do(req *http.Request) (*http.Response, error) { func (r *digestRequest) Do(req *http.Request) (*http.Response, error) {
parts, err := r.makeParts(req) parts, err := r.makeParts(req)
if err != nil { if err != nil {
@ -133,7 +133,7 @@ func (r *digestRequest) makeAuthorization(req *http.Request, parts map[string]st
) )
} }
// GenerateRandom generates random string // GenerateRandom generates random string.
func generateRandom(n int) string { func generateRandom(n int) string {
b := make([]byte, 8) b := make([]byte, 8)
_, _ = io.ReadFull(rand.Reader, b) _, _ = io.ReadFull(rand.Reader, b)

View file

@ -18,7 +18,7 @@ type chainBuilder interface {
BuildChain(ctx context.Context, middlewares []string) *alice.Chain BuildChain(ctx context.Context, middlewares []string) *alice.Chain
} }
// New creates a chain middleware // New creates a chain middleware.
func New(ctx context.Context, next http.Handler, config dynamic.Chain, builder chainBuilder, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.Chain, builder chainBuilder, name string) (http.Handler, error) {
log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")

View file

@ -39,7 +39,7 @@ func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.Circ
}, nil }, nil
} }
// NewCircuitBreakerOptions returns a new CircuitBreakerOption // NewCircuitBreakerOptions returns a new CircuitBreakerOption.
func createCircuitBreakerOptions(expression string) cbreaker.CircuitBreakerOption { func createCircuitBreakerOptions(expression string) cbreaker.CircuitBreakerOption {
return cbreaker.Fallback(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { return cbreaker.Fallback(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
tracing.SetErrorWithEvent(req, "blocked by circuit-breaker (%q)", expression) tracing.SetErrorWithEvent(req, "blocked by circuit-breaker (%q)", expression)

View file

@ -131,12 +131,12 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
func newRequest(baseURL string) (*http.Request, error) { func newRequest(baseURL string) (*http.Request, error) {
u, err := url.Parse(baseURL) u, err := url.Parse(baseURL)
if err != nil { if err != nil {
return nil, fmt.Errorf("error pages: error when parse URL: %v", err) return nil, fmt.Errorf("error pages: error when parse URL: %w", err)
} }
req, err := http.NewRequest(http.MethodGet, u.String(), nil) req, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error pages: error when create query: %v", err) return nil, fmt.Errorf("error pages: error when create query: %w", err)
} }
req.RequestURI = u.RequestURI() req.RequestURI = u.RequestURI()
@ -250,7 +250,7 @@ func (cc *codeCatcher) WriteHeader(code int) {
cc.headersSent = true cc.headersSent = true
} }
// Hijack hijacks the connection // Hijack hijacks the connection.
func (cc *codeCatcher) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (cc *codeCatcher) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if hj, ok := cc.responseWriter.(http.Hijacker); ok { if hj, ok := cc.responseWriter.(http.Hijacker); ok {
return hj.Hijack() return hj.Hijack()
@ -349,7 +349,7 @@ func (r *responseRecorderWithoutCloseNotify) WriteHeader(code int) {
r.Code = code r.Code = code
} }
// Hijack hijacks the connection // Hijack hijacks the connection.
func (r *responseRecorderWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (r *responseRecorderWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return r.responseWriter.(http.Hijacker).Hijack() return r.responseWriter.(http.Hijacker).Hijack()
} }

View file

@ -37,9 +37,10 @@ var xHeaders = []string{
xRealIP, xRealIP,
} }
// XForwarded is an HTTP handler wrapper that sets the X-Forwarded headers, and other relevant headers for a // XForwarded is an HTTP handler wrapper that sets the X-Forwarded headers,
// reverse-proxy. Unless insecure is set, it first removes all the existing values for those headers if the remote // and other relevant headers for a reverse-proxy.
// address is not one of the trusted ones. // Unless insecure is set,
// it first removes all the existing values for those headers if the remote address is not one of the trusted ones.
type XForwarded struct { type XForwarded struct {
insecure bool insecure bool
trustedIps []string trustedIps []string
@ -80,15 +81,13 @@ func (x *XForwarded) isTrustedIP(ip string) bool {
return x.ipChecker.IsAuthorized(ip) == nil return x.ipChecker.IsAuthorized(ip) == nil
} }
// removeIPv6Zone removes the zone if the given IP is an ipv6 address and it has // removeIPv6Zone removes the zone if the given IP is an ipv6 address and it has {zone} information in it,
// {zone} information in it, like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3 // like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3 Ethernet Adapter - Virtual Switch)]:64692".
// Ethernet Adapter - Virtual Switch)]:64692"
func removeIPv6Zone(clientIP string) string { func removeIPv6Zone(clientIP string) string {
return strings.Split(clientIP, "%")[0] return strings.Split(clientIP, "%")[0]
} }
// isWebsocketRequest returns whether the specified HTTP request is a // isWebsocketRequest returns whether the specified HTTP request is a websocket handshake request.
// websocket handshake request
func isWebsocketRequest(req *http.Request) bool { func isWebsocketRequest(req *http.Request) bool {
containsHeader := func(name, value string) bool { containsHeader := func(name, value string) bool {
items := strings.Split(req.Header.Get(name), ",") items := strings.Split(req.Header.Get(name), ",")
@ -141,7 +140,7 @@ func (x *XForwarded) rewrite(outreq *http.Request) {
} }
if isWebsocketRequest(outreq) { if isWebsocketRequest(outreq) {
if outreq.Header.Get(xForwardedProto) == "https" { if outreq.Header.Get(xForwardedProto) == "https" || outreq.Header.Get(xForwardedProto) == "wss" {
outreq.Header.Set(xForwardedProto, "wss") outreq.Header.Set(xForwardedProto, "wss")
} else { } else {
outreq.Header.Set(xForwardedProto, "ws") outreq.Header.Set(xForwardedProto, "ws")
@ -161,7 +160,7 @@ func (x *XForwarded) rewrite(outreq *http.Request) {
} }
} }
// ServeHTTP implements http.Handler // ServeHTTP implements http.Handler.
func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !x.insecure && !x.isTrustedIP(r.RemoteAddr) { if !x.insecure && !x.isTrustedIP(r.RemoteAddr) {
for _, h := range xHeaders { for _, h := range xHeaders {

View file

@ -203,6 +203,17 @@ func TestServeHTTP(t *testing.T) {
xForwardedProto: "wss", xForwardedProto: "wss",
}, },
}, },
{
desc: "xForwardedProto with websocket and tls and already x-forwarded-proto with wss",
tls: true,
websocket: true,
incomingHeaders: map[string]string{
xForwardedProto: "wss",
},
expectedHeaders: map[string]string{
xForwardedProto: "wss",
},
},
{ {
desc: "xForwardedPort with explicit port", desc: "xForwardedPort with explicit port",
host: "foo.com:8080", host: "foo.com:8080",

View file

@ -6,12 +6,12 @@ import (
"github.com/containous/traefik/v2/pkg/safe" "github.com/containous/traefik/v2/pkg/safe"
) )
// HTTPHandlerSwitcher allows hot switching of http.ServeMux // HTTPHandlerSwitcher allows hot switching of http.ServeMux.
type HTTPHandlerSwitcher struct { type HTTPHandlerSwitcher struct {
handler *safe.Safe handler *safe.Safe
} }
// NewHandlerSwitcher builds a new instance of HTTPHandlerSwitcher // NewHandlerSwitcher builds a new instance of HTTPHandlerSwitcher.
func NewHandlerSwitcher(newHandler http.Handler) (hs *HTTPHandlerSwitcher) { func NewHandlerSwitcher(newHandler http.Handler) (hs *HTTPHandlerSwitcher) {
return &HTTPHandlerSwitcher{ return &HTTPHandlerSwitcher{
handler: safe.New(newHandler), handler: safe.New(newHandler),
@ -23,13 +23,13 @@ func (h *HTTPHandlerSwitcher) ServeHTTP(rw http.ResponseWriter, req *http.Reques
handlerBackup.ServeHTTP(rw, req) handlerBackup.ServeHTTP(rw, req)
} }
// GetHandler returns the current http.ServeMux // GetHandler returns the current http.ServeMux.
func (h *HTTPHandlerSwitcher) GetHandler() (newHandler http.Handler) { func (h *HTTPHandlerSwitcher) GetHandler() (newHandler http.Handler) {
handler := h.handler.Get().(http.Handler) handler := h.handler.Get().(http.Handler)
return handler return handler
} }
// UpdateHandler safely updates the current http.ServeMux with a new one // UpdateHandler safely updates the current http.ServeMux with a new one.
func (h *HTTPHandlerSwitcher) UpdateHandler(newHandler http.Handler) { func (h *HTTPHandlerSwitcher) UpdateHandler(newHandler http.Handler) {
h.handler.Set(newHandler) h.handler.Set(newHandler)
} }

View file

@ -38,12 +38,12 @@ func New(ctx context.Context, next http.Handler, config dynamic.InFlightReq, nam
sourceMatcher, err := middlewares.GetSourceExtractor(ctxLog, config.SourceCriterion) sourceMatcher, err := middlewares.GetSourceExtractor(ctxLog, config.SourceCriterion)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating requests limiter: %v", err) return nil, fmt.Errorf("error creating requests limiter: %w", err)
} }
handler, err := connlimit.New(next, sourceMatcher, config.Amount) handler, err := connlimit.New(next, sourceMatcher, config.Amount)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating connection limit: %v", err) return nil, fmt.Errorf("error creating connection limit: %w", err)
} }
return &inFlightReq{handler: handler, name: name}, nil return &inFlightReq{handler: handler, name: name}, nil

View file

@ -18,7 +18,7 @@ const (
typeName = "IPWhiteLister" typeName = "IPWhiteLister"
) )
// ipWhiteLister is a middleware that provides Checks of the Requesting IP against a set of Whitelists // ipWhiteLister is a middleware that provides Checks of the Requesting IP against a set of Whitelists.
type ipWhiteLister struct { type ipWhiteLister struct {
next http.Handler next http.Handler
whiteLister *ip.Checker whiteLister *ip.Checker
@ -26,7 +26,7 @@ type ipWhiteLister struct {
name string name string
} }
// New builds a new IPWhiteLister given a list of CIDR-Strings to whitelist // New builds a new IPWhiteLister given a list of CIDR-Strings to whitelist.
func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, name string) (http.Handler, error) { func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, name string) (http.Handler, error) {
logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)) logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
logger.Debug("Creating middleware") logger.Debug("Creating middleware")
@ -37,7 +37,7 @@ func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, nam
checker, err := ip.NewChecker(config.SourceRange) checker, err := ip.NewChecker(config.SourceRange)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot parse CIDR whitelist %s: %v", config.SourceRange, err) return nil, fmt.Errorf("cannot parse CIDR whitelist %s: %w", config.SourceRange, err)
} }
strategy, err := config.IPStrategy.Get() strategy, err := config.IPStrategy.Get()

View file

@ -50,7 +50,7 @@ func (r *responseRecorder) WriteHeader(status int) {
r.statusCode = status r.statusCode = status
} }
// Hijack hijacks the connection // Hijack hijacks the connection.
func (r *responseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (r *responseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return r.ResponseWriter.(http.Hijacker).Hijack() return r.ResponseWriter.(http.Hijacker).Hijack()
} }

View file

@ -139,7 +139,7 @@ func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request)
// - the `,` is used to separate certificates // - the `,` is used to separate certificates
// - the `;` is used to separate root fields // - the `;` is used to separate root fields
// - the value of root fields is always wrapped by double quote // - the value of root fields is always wrapped by double quote
// - if a field is empty, the field is ignored // - if a field is empty, the field is ignored.
func (p *passTLSClientCert) getCertInfo(ctx context.Context, certs []*x509.Certificate) string { func (p *passTLSClientCert) getCertInfo(ctx context.Context, certs []*x509.Certificate) string {
var headerValues []string var headerValues []string

View file

@ -14,12 +14,12 @@ const (
typeName = "Pipelining" typeName = "Pipelining"
) )
// pipelining returns a middleware // pipelining returns a middleware.
type pipelining struct { type pipelining struct {
next http.Handler next http.Handler
} }
// New returns a new pipelining instance // New returns a new pipelining instance.
func New(ctx context.Context, next http.Handler, name string) http.Handler { func New(ctx context.Context, next http.Handler, name string) http.Handler {
log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
@ -37,7 +37,7 @@ func (p *pipelining) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
} }
} }
// writerWithoutCloseNotify helps to disable closeNotify // writerWithoutCloseNotify helps to disable closeNotify.
type writerWithoutCloseNotify struct { type writerWithoutCloseNotify struct {
W http.ResponseWriter W http.ResponseWriter
} }
@ -52,8 +52,7 @@ func (w *writerWithoutCloseNotify) Write(buf []byte) (int, error) {
return w.W.Write(buf) return w.W.Write(buf)
} }
// WriteHeader sends an HTTP response header with the provided // WriteHeader sends an HTTP response header with the provided status code.
// status code.
func (w *writerWithoutCloseNotify) WriteHeader(code int) { func (w *writerWithoutCloseNotify) WriteHeader(code int) {
w.W.WriteHeader(code) w.W.WriteHeader(code)
} }

View file

@ -34,7 +34,7 @@ func New(ctx context.Context, next http.Handler, config dynamic.ReplacePathRegex
exp, err := regexp.Compile(strings.TrimSpace(config.Regex)) exp, err := regexp.Compile(strings.TrimSpace(config.Regex))
if err != nil { if err != nil {
return nil, fmt.Errorf("error compiling regular expression %s: %s", config.Regex, err) return nil, fmt.Errorf("error compiling regular expression %s: %w", config.Regex, err)
} }
return &replacePathRegex{ return &replacePathRegex{

View file

@ -105,7 +105,7 @@ func cnameResolve(ctx context.Context, host string, resolvPath string) (*cnameRe
func getRecord(client *dns.Client, msg *dns.Msg, server string, port string) (*cnameResolv, error) { func getRecord(client *dns.Client, msg *dns.Msg, server string, port string) (*cnameResolv, error) {
resp, _, err := client.Exchange(msg, net.JoinHostPort(server, port)) resp, _, err := client.Exchange(msg, net.JoinHostPort(server, port))
if err != nil { if err != nil {
return nil, fmt.Errorf("exchange error for server %s: %v", server, err) return nil, fmt.Errorf("exchange error for server %s: %w", server, err)
} }
if resp == nil || len(resp.Answer) == 0 { if resp == nil || len(resp.Answer) == 0 {

View file

@ -3,7 +3,7 @@ package middlewares
import "net/http" import "net/http"
// Stateful interface groups all http interfaces that must be // Stateful interface groups all http interfaces that must be
// implemented by a stateful middleware (ie: recorders) // implemented by a stateful middleware (ie: recorders).
type Stateful interface { type Stateful interface {
http.ResponseWriter http.ResponseWriter
http.Hijacker http.Hijacker

View file

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

View file

@ -22,12 +22,12 @@ func (s *statusCodeWithoutCloseNotify) WriteHeader(status int) {
s.ResponseWriter.WriteHeader(status) s.ResponseWriter.WriteHeader(status)
} }
// Status get response status // Status get response status.
func (s *statusCodeWithoutCloseNotify) Status() int { func (s *statusCodeWithoutCloseNotify) Status() int {
return s.status return s.status
} }
// Hijack hijacks the connection // Hijack hijacks the connection.
func (s *statusCodeWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (s *statusCodeWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return s.ResponseWriter.(http.Hijacker).Hijack() return s.ResponseWriter.(http.Hijacker).Hijack()
} }

View file

@ -35,7 +35,7 @@ func Wrap(ctx context.Context, constructor alice.Constructor) alice.Constructor
} }
} }
// NewWrapper returns a http.Handler struct // NewWrapper returns a http.Handler struct.
func NewWrapper(next http.Handler, name string, spanKind ext.SpanKindEnum) http.Handler { func NewWrapper(next http.Handler, name string, spanKind ext.SpanKindEnum) http.Handler {
return &Wrapper{ return &Wrapper{
next: next, next: next,

View file

@ -12,7 +12,7 @@ import (
"github.com/go-acme/lego/v3/registration" "github.com/go-acme/lego/v3/registration"
) )
// Account is used to store lets encrypt registration info // Account is used to store lets encrypt registration info.
type Account struct { type Account struct {
Email string Email string
Registration *registration.Resource Registration *registration.Resource
@ -21,11 +21,11 @@ type Account struct {
} }
const ( const (
// RegistrationURLPathV1Regexp is a regexp which match ACME registration URL in the V1 format // RegistrationURLPathV1Regexp is a regexp which match ACME registration URL in the V1 format.
RegistrationURLPathV1Regexp = `^.*/acme/reg/\d+$` RegistrationURLPathV1Regexp = `^.*/acme/reg/\d+$`
) )
// NewAccount creates an account // NewAccount creates an account.
func NewAccount(ctx context.Context, email string, keyTypeValue string) (*Account, error) { func NewAccount(ctx context.Context, email string, keyTypeValue string) (*Account, error) {
keyType := GetKeyType(ctx, keyTypeValue) keyType := GetKeyType(ctx, keyTypeValue)
@ -42,17 +42,17 @@ func NewAccount(ctx context.Context, email string, keyTypeValue string) (*Accoun
}, nil }, nil
} }
// GetEmail returns email // GetEmail returns email.
func (a *Account) GetEmail() string { func (a *Account) GetEmail() string {
return a.Email return a.Email
} }
// GetRegistration returns lets encrypt registration resource // GetRegistration returns lets encrypt registration resource.
func (a *Account) GetRegistration() *registration.Resource { func (a *Account) GetRegistration() *registration.Resource {
return a.Registration return a.Registration
} }
// GetPrivateKey returns private key // GetPrivateKey returns private key.
func (a *Account) GetPrivateKey() crypto.PrivateKey { func (a *Account) GetPrivateKey() crypto.PrivateKey {
privateKey, err := x509.ParsePKCS1PrivateKey(a.PrivateKey) privateKey, err := x509.ParsePKCS1PrivateKey(a.PrivateKey)
if err != nil { if err != nil {
@ -64,7 +64,7 @@ func (a *Account) GetPrivateKey() crypto.PrivateKey {
return privateKey return privateKey
} }
// GetKeyType used to determine which algo to used // GetKeyType used to determine which algo to used.
func GetKeyType(ctx context.Context, value string) certcrypto.KeyType { func GetKeyType(ctx context.Context, value string) certcrypto.KeyType {
logger := log.FromContext(ctx) logger := log.FromContext(ctx)

View file

@ -13,7 +13,7 @@ import (
var _ Store = (*LocalStore)(nil) var _ Store = (*LocalStore)(nil)
// LocalStore Stores implementation for local file // LocalStore Stores implementation for local file.
type LocalStore struct { type LocalStore struct {
saveDataChan chan map[string]*StoredData saveDataChan chan map[string]*StoredData
filename string filename string
@ -22,7 +22,7 @@ type LocalStore struct {
storedData map[string]*StoredData storedData map[string]*StoredData
} }
// NewLocalStore initializes a new LocalStore with a file name // NewLocalStore initializes a new LocalStore with a file name.
func NewLocalStore(filename string) *LocalStore { func NewLocalStore(filename string) *LocalStore {
store := &LocalStore{filename: filename, saveDataChan: make(chan map[string]*StoredData)} store := &LocalStore{filename: filename, saveDataChan: make(chan map[string]*StoredData)}
store.listenSaveAction() store.listenSaveAction()
@ -93,7 +93,7 @@ func (s *LocalStore) get(resolverName string) (*StoredData, error) {
return s.storedData[resolverName], nil return s.storedData[resolverName], nil
} }
// listenSaveAction listens to a chan to store ACME data in json format into LocalStore.filename // listenSaveAction listens to a chan to store ACME data in json format into `LocalStore.filename`.
func (s *LocalStore) listenSaveAction() { func (s *LocalStore) listenSaveAction() {
safe.Go(func() { safe.Go(func() {
logger := log.WithoutContext().WithField(log.ProviderName, "acme") logger := log.WithoutContext().WithField(log.ProviderName, "acme")
@ -111,7 +111,7 @@ func (s *LocalStore) listenSaveAction() {
}) })
} }
// GetAccount returns ACME Account // GetAccount returns ACME Account.
func (s *LocalStore) GetAccount(resolverName string) (*Account, error) { func (s *LocalStore) GetAccount(resolverName string) (*Account, error) {
storedData, err := s.get(resolverName) storedData, err := s.get(resolverName)
if err != nil { if err != nil {
@ -121,7 +121,7 @@ func (s *LocalStore) GetAccount(resolverName string) (*Account, error) {
return storedData.Account, nil return storedData.Account, nil
} }
// SaveAccount stores ACME Account // SaveAccount stores ACME Account.
func (s *LocalStore) SaveAccount(resolverName string, account *Account) error { func (s *LocalStore) SaveAccount(resolverName string, account *Account) error {
storedData, err := s.get(resolverName) storedData, err := s.get(resolverName)
if err != nil { if err != nil {
@ -134,7 +134,7 @@ func (s *LocalStore) SaveAccount(resolverName string, account *Account) error {
return nil return nil
} }
// GetCertificates returns ACME Certificates list // GetCertificates returns ACME Certificates list.
func (s *LocalStore) GetCertificates(resolverName string) ([]*CertAndStore, error) { func (s *LocalStore) GetCertificates(resolverName string) ([]*CertAndStore, error) {
storedData, err := s.get(resolverName) storedData, err := s.get(resolverName)
if err != nil { if err != nil {
@ -144,7 +144,7 @@ func (s *LocalStore) GetCertificates(resolverName string) ([]*CertAndStore, erro
return storedData.Certificates, nil return storedData.Certificates, nil
} }
// SaveCertificates stores ACME Certificates list // SaveCertificates stores ACME Certificates list.
func (s *LocalStore) SaveCertificates(resolverName string, certificates []*CertAndStore) error { func (s *LocalStore) SaveCertificates(resolverName string, certificates []*CertAndStore) error {
storedData, err := s.get(resolverName) storedData, err := s.get(resolverName)
if err != nil { if err != nil {
@ -173,7 +173,7 @@ func NewLocalChallengeStore() *LocalChallengeStore {
} }
} }
// GetHTTPChallengeToken Get the http challenge token from the store // GetHTTPChallengeToken Get the http challenge token from the store.
func (s *LocalChallengeStore) GetHTTPChallengeToken(token, domain string) ([]byte, error) { func (s *LocalChallengeStore) GetHTTPChallengeToken(token, domain string) ([]byte, error) {
s.lock.RLock() s.lock.RLock()
defer s.lock.RUnlock() defer s.lock.RUnlock()
@ -193,7 +193,7 @@ func (s *LocalChallengeStore) GetHTTPChallengeToken(token, domain string) ([]byt
return result, nil return result, nil
} }
// SetHTTPChallengeToken Set the http challenge token in the store // SetHTTPChallengeToken Set the http challenge token in the store.
func (s *LocalChallengeStore) SetHTTPChallengeToken(token, domain string, keyAuth []byte) error { func (s *LocalChallengeStore) SetHTTPChallengeToken(token, domain string, keyAuth []byte) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
@ -210,7 +210,7 @@ func (s *LocalChallengeStore) SetHTTPChallengeToken(token, domain string, keyAut
return nil return nil
} }
// RemoveHTTPChallengeToken Remove the http challenge token in the store // RemoveHTTPChallengeToken Remove the http challenge token in the store.
func (s *LocalChallengeStore) RemoveHTTPChallengeToken(token, domain string) error { func (s *LocalChallengeStore) RemoveHTTPChallengeToken(token, domain string) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
@ -228,7 +228,7 @@ func (s *LocalChallengeStore) RemoveHTTPChallengeToken(token, domain string) err
return nil return nil
} }
// AddTLSChallenge Add a certificate to the ACME TLS-ALPN-01 certificates storage // AddTLSChallenge Add a certificate to the ACME TLS-ALPN-01 certificates storage.
func (s *LocalChallengeStore) AddTLSChallenge(domain string, cert *Certificate) error { func (s *LocalChallengeStore) AddTLSChallenge(domain string, cert *Certificate) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
@ -241,7 +241,7 @@ func (s *LocalChallengeStore) AddTLSChallenge(domain string, cert *Certificate)
return nil return nil
} }
// GetTLSChallenge Get a certificate from the ACME TLS-ALPN-01 certificates storage // GetTLSChallenge Get a certificate from the ACME TLS-ALPN-01 certificates storage.
func (s *LocalChallengeStore) GetTLSChallenge(domain string) (*Certificate, error) { func (s *LocalChallengeStore) GetTLSChallenge(domain string) (*Certificate, error) {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
@ -253,7 +253,7 @@ func (s *LocalChallengeStore) GetTLSChallenge(domain string) (*Certificate, erro
return s.storedData.TLSChallenges[domain], nil return s.storedData.TLSChallenges[domain], nil
} }
// RemoveTLSChallenge Remove a certificate from the ACME TLS-ALPN-01 certificates storage // RemoveTLSChallenge Remove a certificate from the ACME TLS-ALPN-01 certificates storage.
func (s *LocalChallengeStore) RemoveTLSChallenge(domain string) error { func (s *LocalChallengeStore) RemoveTLSChallenge(domain string) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()

View file

@ -7,7 +7,7 @@ import (
"os" "os"
) )
// CheckFile checks file permissions and content size // CheckFile checks file permissions and content size.
func CheckFile(name string) (bool, error) { func CheckFile(name string) (bool, error) {
f, err := os.Open(name) f, err := os.Open(name)
if err != nil { if err != nil {

View file

@ -28,11 +28,11 @@ import (
) )
var ( var (
// oscpMustStaple enables OSCP stapling as from https://github.com/go-acme/lego/issues/270 // oscpMustStaple enables OSCP stapling as from https://github.com/go-acme/lego/issues/270.
oscpMustStaple = false oscpMustStaple = false
) )
// Configuration holds ACME configuration provided by users // Configuration holds ACME configuration provided by users.
type Configuration struct { type Configuration struct {
Email string `description:"Email address used for registration." json:"email,omitempty" toml:"email,omitempty" yaml:"email,omitempty"` Email string `description:"Email address used for registration." json:"email,omitempty" toml:"email,omitempty" yaml:"email,omitempty"`
CAServer string `description:"CA server to use." json:"caServer,omitempty" toml:"caServer,omitempty" yaml:"caServer,omitempty"` CAServer string `description:"CA server to use." json:"caServer,omitempty" toml:"caServer,omitempty" yaml:"caServer,omitempty"`
@ -56,14 +56,14 @@ type CertAndStore struct {
Store string Store string
} }
// Certificate is a struct which contains all data needed from an ACME certificate // Certificate is a struct which contains all data needed from an ACME certificate.
type Certificate struct { type Certificate struct {
Domain types.Domain `json:"domain,omitempty" toml:"domain,omitempty" yaml:"domain,omitempty"` Domain types.Domain `json:"domain,omitempty" toml:"domain,omitempty" yaml:"domain,omitempty"`
Certificate []byte `json:"certificate,omitempty" toml:"certificate,omitempty" yaml:"certificate,omitempty"` Certificate []byte `json:"certificate,omitempty" toml:"certificate,omitempty" yaml:"certificate,omitempty"`
Key []byte `json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty"` Key []byte `json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty"`
} }
// DNSChallenge contains DNS challenge Configuration // DNSChallenge contains DNS challenge Configuration.
type DNSChallenge struct { type DNSChallenge struct {
Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS." json:"provider,omitempty" toml:"provider,omitempty" yaml:"provider,omitempty"` Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS." json:"provider,omitempty" toml:"provider,omitempty" yaml:"provider,omitempty"`
DelayBeforeCheck types.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers." json:"delayBeforeCheck,omitempty" toml:"delayBeforeCheck,omitempty" yaml:"delayBeforeCheck,omitempty"` DelayBeforeCheck types.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers." json:"delayBeforeCheck,omitempty" toml:"delayBeforeCheck,omitempty" yaml:"delayBeforeCheck,omitempty"`
@ -71,12 +71,12 @@ type DNSChallenge struct {
DisablePropagationCheck bool `description:"Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]" json:"disablePropagationCheck,omitempty" toml:"disablePropagationCheck,omitempty" yaml:"disablePropagationCheck,omitempty"` DisablePropagationCheck bool `description:"Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]" json:"disablePropagationCheck,omitempty" toml:"disablePropagationCheck,omitempty" yaml:"disablePropagationCheck,omitempty"`
} }
// HTTPChallenge contains HTTP challenge Configuration // HTTPChallenge contains HTTP challenge Configuration.
type HTTPChallenge struct { type HTTPChallenge struct {
EntryPoint string `description:"HTTP challenge EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"` EntryPoint string `description:"HTTP challenge EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
} }
// TLSChallenge contains TLS challenge Configuration // TLSChallenge contains TLS challenge Configuration.
type TLSChallenge struct{} type TLSChallenge struct{}
// Provider holds configurations of the provider. // Provider holds configurations of the provider.
@ -98,22 +98,22 @@ type Provider struct {
resolvingDomainsMutex sync.RWMutex resolvingDomainsMutex sync.RWMutex
} }
// SetTLSManager sets the tls manager to use // SetTLSManager sets the tls manager to use.
func (p *Provider) SetTLSManager(tlsManager *traefiktls.Manager) { func (p *Provider) SetTLSManager(tlsManager *traefiktls.Manager) {
p.tlsManager = tlsManager p.tlsManager = tlsManager
} }
// SetConfigListenerChan initializes the configFromListenerChan // SetConfigListenerChan initializes the configFromListenerChan.
func (p *Provider) SetConfigListenerChan(configFromListenerChan chan dynamic.Configuration) { func (p *Provider) SetConfigListenerChan(configFromListenerChan chan dynamic.Configuration) {
p.configFromListenerChan = configFromListenerChan p.configFromListenerChan = configFromListenerChan
} }
// ListenConfiguration sets a new Configuration into the configFromListenerChan // ListenConfiguration sets a new Configuration into the configFromListenerChan.
func (p *Provider) ListenConfiguration(config dynamic.Configuration) { func (p *Provider) ListenConfiguration(config dynamic.Configuration) {
p.configFromListenerChan <- config p.configFromListenerChan <- config
} }
// Init for compatibility reason the BaseProvider implements an empty Init // Init for compatibility reason the BaseProvider implements an empty Init.
func (p *Provider) Init() error { func (p *Provider) Init() error {
ctx := log.With(context.Background(), log.Str(log.ProviderName, p.ResolverName+".acme")) ctx := log.With(context.Background(), log.Str(log.ProviderName, p.ResolverName+".acme"))
logger := log.FromContext(ctx) logger := log.FromContext(ctx)
@ -125,7 +125,7 @@ func (p *Provider) Init() error {
var err error var err error
p.account, err = p.Store.GetAccount(p.ResolverName) p.account, err = p.Store.GetAccount(p.ResolverName)
if err != nil { if err != nil {
return fmt.Errorf("unable to get ACME account: %v", err) return fmt.Errorf("unable to get ACME account: %w", err)
} }
// Reset Account if caServer changed, thus registration URI can be updated // Reset Account if caServer changed, thus registration URI can be updated
@ -136,7 +136,7 @@ func (p *Provider) Init() error {
p.certificates, err = p.Store.GetCertificates(p.ResolverName) p.certificates, err = p.Store.GetCertificates(p.ResolverName)
if err != nil { if err != nil {
return fmt.Errorf("unable to get ACME certificates : %v", err) return fmt.Errorf("unable to get ACME certificates : %w", err)
} }
// Init the currently resolved domain map // Init the currently resolved domain map
@ -442,7 +442,7 @@ func (p *Provider) resolveCertificate(ctx context.Context, domain types.Domain,
client, err := p.getClient() client, err := p.getClient()
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot get ACME client %v", err) return nil, fmt.Errorf("cannot get ACME client %w", err)
} }
request := certificate.ObtainRequest{ request := certificate.ObtainRequest{
@ -453,7 +453,7 @@ func (p *Provider) resolveCertificate(ctx context.Context, domain types.Domain,
cert, err := client.Certificate.Obtain(request) cert, err := client.Certificate.Obtain(request)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to generate a certificate for the domains %v: %v", uncheckedDomains, err) return nil, fmt.Errorf("unable to generate a certificate for the domains %v: %w", uncheckedDomains, err)
} }
if cert == nil { if cert == nil {
return nil, fmt.Errorf("domains %v do not generate a certificate", uncheckedDomains) return nil, fmt.Errorf("domains %v do not generate a certificate", uncheckedDomains)
@ -498,7 +498,7 @@ func (p *Provider) addCertificateForDomain(domain types.Domain, certificate []by
// deleteUnnecessaryDomains deletes from the configuration : // deleteUnnecessaryDomains deletes from the configuration :
// - Duplicated domains // - Duplicated domains
// - Domains which are checked by wildcard domain // - Domains which are checked by wildcard domain.
func deleteUnnecessaryDomains(ctx context.Context, domains []types.Domain) []types.Domain { func deleteUnnecessaryDomains(ctx context.Context, domains []types.Domain) []types.Domain {
var newDomains []types.Domain var newDomains []types.Domain
@ -657,7 +657,7 @@ func (p *Provider) renewCertificates(ctx context.Context) {
} }
// Get provided certificate which check a domains list (Main and SANs) // Get provided certificate which check a domains list (Main and SANs)
// from static and dynamic provided certificates // from static and dynamic provided certificates.
func (p *Provider) getUncheckedDomains(ctx context.Context, domainsToCheck []string, tlsStore string) []string { func (p *Provider) getUncheckedDomains(ctx context.Context, domainsToCheck []string, tlsStore string) []string {
p.resolvingDomainsMutex.RLock() p.resolvingDomainsMutex.RLock()
defer p.resolvingDomainsMutex.RUnlock() defer p.resolvingDomainsMutex.RUnlock()
@ -716,7 +716,7 @@ func getX509Certificate(ctx context.Context, cert *Certificate) (*x509.Certifica
return crt, err return crt, err
} }
// getValidDomains checks if given domain is allowed to generate a ACME certificate and return it // getValidDomains checks if given domain is allowed to generate a ACME certificate and return it.
func (p *Provider) getValidDomains(ctx context.Context, domain types.Domain) ([]string, error) { func (p *Provider) getValidDomains(ctx context.Context, domain types.Domain) ([]string, error) {
domains := domain.ToStrArray() domains := domain.ToStrArray()
if len(domains) == 0 { if len(domains) == 0 {

View file

@ -94,12 +94,12 @@ func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
return nil return nil
} }
// Init the provider // Init the provider.
func (p ProviderAggregator) Init() error { func (p ProviderAggregator) Init() error {
return nil return nil
} }
// Provide calls the provide method of every providers // Provide calls the provide method of every providers.
func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error { func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
if p.fileProvider != nil { if p.fileProvider != nil {
launchProvider(configurationChan, pool, p.fileProvider) launchProvider(configurationChan, pool, p.fileProvider)

View file

@ -18,7 +18,7 @@ type constraintLabelFunc func(map[string]string) bool
// The expression must match any logical boolean combination of: // The expression must match any logical boolean combination of:
// - `Label(labelName, labelValue)` // - `Label(labelName, labelValue)`
// - `LabelRegex(labelName, regexValue)` // - `LabelRegex(labelName, regexValue)`
// - `MarathonConstraint(field:operator:value)` // - `MarathonConstraint(field:operator:value)`.
func MatchLabels(labels map[string]string, expr string) (bool, error) { func MatchLabels(labels map[string]string, expr string) (bool, error) {
if expr == "" { if expr == "" {
return true, nil return true, nil

View file

@ -12,7 +12,7 @@ type constraintTagFunc func([]string) bool
// MatchTags reports whether the expression matches with the given tags. // MatchTags reports whether the expression matches with the given tags.
// The expression must match any logical boolean combination of: // The expression must match any logical boolean combination of:
// - `Tag(tagValue)` // - `Tag(tagValue)`
// - `TagRegex(regexValue)` // - `TagRegex(regexValue)`.
func MatchTags(tags []string, expr string) (bool, error) { func MatchTags(tags []string, expr string) (bool, error) {
if expr == "" { if expr == "" {
return true, nil return true, nil

View file

@ -89,7 +89,7 @@ func (p *Provider) SetDefaults() {
func (p *Provider) Init() error { func (p *Provider) Init() error {
defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, nil) defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, nil)
if err != nil { if err != nil {
return fmt.Errorf("error while parsing default rule: %v", err) return fmt.Errorf("error while parsing default rule: %w", err)
} }
p.defaultRuleTpl = defaultRuleTpl p.defaultRuleTpl = defaultRuleTpl
@ -107,7 +107,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
p.client, err = createClient(p.Endpoint) p.client, err = createClient(p.Endpoint)
if err != nil { if err != nil {
return fmt.Errorf("error create consul client, %v", err) return fmt.Errorf("error create consul client, %w", err)
} }
ticker := time.NewTicker(time.Duration(p.RefreshInterval)) ticker := time.NewTicker(time.Duration(p.RefreshInterval))

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