mirror of
https://github.com/containous/traefik.git
synced 2024-12-23 17:34:13 +03:00
Merge branch 'v2.2' into master
This commit is contained in:
commit
7928e6d0cd
@ -49,6 +49,9 @@
|
||||
"wsl", # Too strict
|
||||
"gomnd", # Too strict
|
||||
"stylecheck", # skip because report issues related to some generated files.
|
||||
"testpackage", # Too strict
|
||||
"goerr113", # Too strict
|
||||
"nestif", # Too many false-positive.
|
||||
]
|
||||
|
||||
[issues]
|
||||
@ -62,7 +65,7 @@
|
||||
]
|
||||
[[issues.exclude-rules]]
|
||||
path = "(.+)_test.go"
|
||||
linters = ["goconst", "funlen"]
|
||||
linters = ["goconst", "funlen", "godot"]
|
||||
[[issues.exclude-rules]]
|
||||
path = "integration/.+_test.go"
|
||||
text = "Error return value of `cmd\\.Process\\.Kill` is not checked"
|
||||
@ -105,3 +108,6 @@
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/tracing/tracing.go"
|
||||
text = "printf-like formatting function 'SetErrorWithEvent' should be named 'SetErrorWithEventf'"
|
||||
[[issues.exclude-rules]]
|
||||
path = "pkg/log/deprecated.go"
|
||||
linters = ["godot"]
|
||||
|
2
Makefile
2
Makefile
@ -32,7 +32,7 @@ TRAEFIK_ENVS := \
|
||||
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_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)
|
||||
|
||||
PRE_TARGET ?= build-dev-image
|
||||
|
@ -19,7 +19,7 @@ RUN mkdir -p /usr/local/bin \
|
||||
&& chmod +x /usr/local/bin/go-bindata
|
||||
|
||||
# Download golangci-lint binary to bin folder in $GOPATH
|
||||
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.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
|
||||
RUN curl -sfL https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | bash -s -- -b $GOPATH/bin v0.3.4
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"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 {
|
||||
newCtx, cancel := context.WithCancel(ctx)
|
||||
signals := make(chan os.Signal)
|
||||
|
@ -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) {
|
||||
if staticConfiguration.Ping == nil {
|
||||
return nil, errors.New("please enable `ping` to use health check")
|
||||
|
@ -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 {
|
||||
challengeStore := acme.NewLocalChallengeStore()
|
||||
localStores := map[string]*acme.LocalStore{}
|
||||
|
@ -17,7 +17,7 @@ Go version: {{.GoVersion}}
|
||||
Built: {{.BuildTime}}
|
||||
OS/Arch: {{.Os}}/{{.Arch}}`
|
||||
|
||||
// NewCmd builds a new Version command
|
||||
// NewCmd builds a new Version command.
|
||||
func NewCmd() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "version",
|
||||
@ -33,7 +33,7 @@ func NewCmd() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// GetPrint write Printable version
|
||||
// GetPrint write Printable version.
|
||||
func GetPrint(wr io.Writer) error {
|
||||
tmpl, err := template.New("").Parse(versionTemplate)
|
||||
if err != nil {
|
||||
|
@ -83,7 +83,7 @@ helm install traefik traefik/traefik
|
||||
|
||||
```bash tab="Using Helm CLI"
|
||||
helm install --namespace=traefik-v2 \
|
||||
--set="additionalArguments={--logs.level=DEBUG}" \
|
||||
--set="additionalArguments={--log.level=DEBUG}" \
|
||||
traefik traefik/traefik
|
||||
```
|
||||
|
||||
|
@ -105,13 +105,13 @@ Please check the [configuration examples below](#configuration-examples) for mor
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.websecure.address=:443
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.email=your-email@example.com
|
||||
--certificatesResolvers.myresolver.acme.storage=acme.json
|
||||
--certificatesresolvers.myresolver.acme.email=your-email@example.com
|
||||
--certificatesresolvers.myresolver.acme.storage=acme.json
|
||||
# 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."
|
||||
@ -181,7 +181,7 @@ when using the `TLS-ALPN-01` challenge, Traefik must be reachable by Let's Encry
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.tlsChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.tlschallenge=true
|
||||
```
|
||||
|
||||
### `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.
|
||||
|
||||
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`"
|
||||
|
||||
@ -224,10 +224,10 @@ when using the `HTTP-01` challenge, `certificatesResolvers.myresolver.acme.httpC
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.websecure.address=:443
|
||||
--entrypoints.web.address=:80
|
||||
--entrypoints.websecure.address=:443
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
```
|
||||
|
||||
!!! info ""
|
||||
@ -261,8 +261,8 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
|
||||
|
||||
```bash tab="CLI"
|
||||
# ...
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.provider=digitalocean
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.delayBeforeCheck=0
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.provider=digitalocean
|
||||
--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) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
@ -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) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| 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) |
|
||||
@ -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 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) |
|
||||
| [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>. | |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
@ -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) |
|
||||
| [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) |
|
||||
| [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) |
|
||||
| [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"
|
||||
# ...
|
||||
--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
|
||||
@ -428,7 +434,7 @@ The CA server to use:
|
||||
|
||||
```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"
|
||||
# ...
|
||||
--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
|
||||
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
|
||||
|
||||
|
@ -4,13 +4,13 @@
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.email=test@example.com
|
||||
--certificatesresolvers.myresolver.acme.email=test@example.com
|
||||
|
||||
# File or key used for certificates storage.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.storage=acme.json
|
||||
--certificatesresolvers.myresolver.acme.storage=acme.json
|
||||
|
||||
# CA server to use.
|
||||
# Uncomment the line to use Let's Encrypt's staging server,
|
||||
@ -19,7 +19,7 @@
|
||||
# Optional
|
||||
# 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.
|
||||
#
|
||||
@ -28,38 +28,38 @@
|
||||
#
|
||||
# Available values : "EC256", "EC384", "RSA2048", "RSA4096", "RSA8192"
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.keyType=RSA4096
|
||||
--certificatesresolvers.myresolver.acme.keytype=RSA4096
|
||||
|
||||
# Use a TLS-ALPN-01 ACME challenge.
|
||||
#
|
||||
# Optional (but recommended)
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.tlsChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.tlschallenge=true
|
||||
|
||||
# Use a HTTP-01 ACME challenge.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.httpChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge=true
|
||||
|
||||
# EntryPoint to use for the HTTP-01 challenges.
|
||||
#
|
||||
# Required
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web
|
||||
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||
|
||||
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
|
||||
# Note: mandatory for wildcard certificate generation.
|
||||
#
|
||||
# Optional
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge=true
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge=true
|
||||
|
||||
# DNS provider used.
|
||||
#
|
||||
# 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.
|
||||
# If delayBeforeCheck is greater than zero, this check is delayed for the configured duration in seconds.
|
||||
@ -68,14 +68,14 @@
|
||||
# Optional
|
||||
# Default: 0
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.delayBeforeCheck=0
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
|
||||
|
||||
# Use following DNS servers to resolve the FQDN authority.
|
||||
#
|
||||
# Optional
|
||||
# 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.
|
||||
#
|
||||
@ -85,4 +85,4 @@
|
||||
# Optional
|
||||
# Default: false
|
||||
#
|
||||
--certificatesResolvers.myresolver.acme.dnsChallenge.disablePropagationCheck=true
|
||||
--certificatesresolvers.myresolver.acme.dnschallenge.disablepropagationcheck=true
|
||||
|
@ -208,7 +208,7 @@ metadata:
|
||||
spec:
|
||||
redirectScheme:
|
||||
# ...
|
||||
port: 443
|
||||
port: "443"
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
@ -247,5 +247,7 @@ http:
|
||||
test-redirectscheme:
|
||||
redirectScheme:
|
||||
# ...
|
||||
port: 443
|
||||
port: "443"
|
||||
```
|
||||
|
||||
!!! info "Port in this configuration is a string, not a numeric value."
|
||||
|
@ -358,17 +358,3 @@ providers:
|
||||
|
||||
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.
|
||||
|
||||
## 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).
|
||||
|
@ -26,7 +26,7 @@ theme:
|
||||
prev: 'Previous'
|
||||
next: 'Next'
|
||||
|
||||
copyright: "Copyright © 2016-2019 Containous"
|
||||
copyright: "Copyright © 2016-2020 Containous"
|
||||
|
||||
google_analytics:
|
||||
- 'UA-51880359-3'
|
||||
|
2
go.mod
2
go.mod
@ -36,7 +36,7 @@ require (
|
||||
github.com/fatih/structs v1.1.0
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
|
||||
github.com/go-acme/lego/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-kit/kit v0.9.0
|
||||
github.com/golang/protobuf v1.3.4
|
||||
|
17
go.sum
17
go.sum
@ -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/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.23.0 h1:ilfJN/vJtFo1XDFxB2YMBYGeOvGZl6Qow17oyD4+Z9A=
|
||||
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.30.20 h1:ktsy2vodSZxz/arYqo7DlpkIeNohHL+4Rmjdo7YGtrE=
|
||||
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 v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
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/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/dnsimple/dnsimple-go v0.30.0 h1:IBIrn9jMKRMwporIRwdFyKdnHXVmwy6obnguB+ZMDIY=
|
||||
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||
github.com/dnsimple/dnsimple-go v0.60.0 h1:N+q+ML1CZGf+5r4udu9Opy7WJNtOaFT9aM86Af9gLhk=
|
||||
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/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
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 v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
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.6.0/go.mod h1:sB/T7hfyz0HYIBvPmz/C8jIaxF6scbbiGKTzbQ22V6A=
|
||||
github.com/go-acme/lego/v3 v3.7.0 h1:qC5/8/CbltyAE8fGLE6bGlqucj7pXc/vBxiLwLOsmAQ=
|
||||
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-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
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.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
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/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
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/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.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/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||
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.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
@ -24,7 +24,7 @@ const (
|
||||
traefikTestAccessLogFile = "access.log"
|
||||
)
|
||||
|
||||
// AccessLogSuite
|
||||
// AccessLogSuite tests suite.
|
||||
type AccessLogSuite struct{ BaseSuite }
|
||||
|
||||
type accessLogValue struct {
|
||||
@ -562,7 +562,7 @@ func extractLines(c *check.C) []string {
|
||||
func checkStatsForLogFile(c *check.C) {
|
||||
err := try.Do(1*time.Second, func() error {
|
||||
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
|
||||
})
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// ACME test suites (using libcompose)
|
||||
// ACME test suites (using libcompose).
|
||||
type AcmeSuite struct {
|
||||
BaseSuite
|
||||
pebbleIP string
|
||||
@ -74,7 +74,7 @@ func setupPebbleRootCA() (*http.Transport, error) {
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
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{
|
||||
@ -394,7 +394,7 @@ func (s *AcmeSuite) TestTLSALPN01DomainsInSAN(c *check.C) {
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test Let's encrypt down
|
||||
// Test Let's encrypt down.
|
||||
func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
|
||||
file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{
|
||||
Acme: map[string]static.CertificateResolver{
|
||||
@ -417,7 +417,7 @@ func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
|
||||
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) {
|
||||
if len(testCase.template.PortHTTP) == 0 {
|
||||
testCase.template.PortHTTP = ":5002"
|
||||
|
@ -47,7 +47,7 @@ func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
|
||||
leader, err := s.consulClient.Status().Leader()
|
||||
|
||||
if err != nil || len(leader) == 0 {
|
||||
return fmt.Errorf("leader not found. %v", err)
|
||||
return fmt.Errorf("leader not found. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Consul test suites (using libcompose)
|
||||
// Consul test suites (using libcompose).
|
||||
type ConsulSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
|
@ -18,7 +18,7 @@ const (
|
||||
composeProject = "minimal"
|
||||
)
|
||||
|
||||
// Docker test suites
|
||||
// Docker tests suite.
|
||||
type DockerComposeSuite struct {
|
||||
BaseSuite
|
||||
}
|
||||
|
@ -17,14 +17,14 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Images to have or pull before the build in order to make it work
|
||||
// FIXME handle this offline but loading them before build
|
||||
// Images to have or pull before the build in order to make it work.
|
||||
// FIXME handle this offline but loading them before build.
|
||||
var RequiredImages = map[string]string{
|
||||
"swarm": "1.0.0",
|
||||
"containous/whoami": "latest",
|
||||
}
|
||||
|
||||
// Docker test suites
|
||||
// Docker tests suite.
|
||||
type DockerSuite struct {
|
||||
BaseSuite
|
||||
project *docker.Project
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// ErrorPagesSuite test suites (using libcompose)
|
||||
// ErrorPagesSuite test suites (using libcompose).
|
||||
type ErrorPagesSuite struct {
|
||||
BaseSuite
|
||||
ErrorPageIP string
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// etcd test suites (using libcompose)
|
||||
// etcd test suites (using libcompose).
|
||||
type EtcdSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// File test suites
|
||||
// File tests suite.
|
||||
type FileSuite struct{ BaseSuite }
|
||||
|
||||
func (s *FileSuite) SetUpSuite(c *check.C) {
|
||||
@ -32,7 +32,7 @@ func (s *FileSuite) TestSimpleConfiguration(c *check.C) {
|
||||
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) {
|
||||
cmd, display := s.traefikCmd(withConfigFile("fixtures/file/56-simple-panic.toml"))
|
||||
defer display(c)
|
||||
|
@ -24,7 +24,7 @@ var LocalhostKey []byte
|
||||
|
||||
const randCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
|
||||
// GRPCSuite
|
||||
// GRPCSuite tests suite.
|
||||
type GRPCSuite struct{ BaseSuite }
|
||||
|
||||
type myserver struct {
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Headers test suites
|
||||
// Headers tests suite.
|
||||
type HeadersSuite struct{ BaseSuite }
|
||||
|
||||
func (s *HeadersSuite) TestSimpleConfiguration(c *check.C) {
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// HealthCheck test suites (using libcompose)
|
||||
// HealthCheck test suites (using libcompose).
|
||||
type HealthCheckSuite struct {
|
||||
BaseSuite
|
||||
whoami1IP string
|
||||
@ -206,7 +206,7 @@ func (s *HealthCheckSuite) TestPortOverload(c *check.C) {
|
||||
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) {
|
||||
file := s.adaptFile(c, "fixtures/healthcheck/multiple-routers-one-same-service.toml", struct {
|
||||
Server1 string
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// HTTPSSuite
|
||||
// HTTPSSuite tests suite.
|
||||
type HTTPSSuite struct{ BaseSuite }
|
||||
|
||||
// TestWithSNIConfigHandshake involves a client sending a SNI hostname of
|
||||
@ -441,7 +441,7 @@ func (s *HTTPSSuite) TestWithOverlappingDynamicCertificate(c *check.C) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
file := s.adaptFile(c, "fixtures/https/clientca/https_1ca1config.toml", struct{}{})
|
||||
defer os.Remove(file)
|
||||
@ -499,7 +499,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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")) }))
|
||||
@ -596,7 +596,7 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipleCAs(c *check
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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")) }))
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
|
||||
var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata")
|
||||
|
||||
// K8sSuite
|
||||
// K8sSuite tests suite.
|
||||
type K8sSuite struct{ BaseSuite }
|
||||
|
||||
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 {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
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 {
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Log rotation integration test suite
|
||||
// Log rotation integration test suite.
|
||||
type LogRotationSuite struct{ BaseSuite }
|
||||
|
||||
func (s *LogRotationSuite) SetUpSuite(c *check.C) {
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Marathon test suites (using libcompose)
|
||||
// Marathon test suites (using libcompose).
|
||||
type MarathonSuite15 struct {
|
||||
BaseSuite
|
||||
marathonURL string
|
||||
|
@ -17,7 +17,7 @@ const (
|
||||
containerNameMarathon = "marathon"
|
||||
)
|
||||
|
||||
// Marathon test suites (using libcompose)
|
||||
// Marathon test suites (using libcompose).
|
||||
type MarathonSuite struct {
|
||||
BaseSuite
|
||||
marathonURL string
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Redis test suites (using libcompose)
|
||||
// Redis test suites (using libcompose).
|
||||
type RedisSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// SimpleSuite
|
||||
// SimpleSuite tests suite.
|
||||
type SimpleSuite struct{ BaseSuite }
|
||||
|
||||
func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) {
|
||||
|
@ -12,18 +12,16 @@ import (
|
||||
)
|
||||
|
||||
// ResponseCondition is a retry condition function.
|
||||
// It receives a response, and returns an error
|
||||
// if the response failed the condition.
|
||||
// It receives a response, and returns an error if the response failed the condition.
|
||||
type ResponseCondition func(*http.Response) error
|
||||
|
||||
// BodyContains returns a retry condition function.
|
||||
// The condition returns an error if the request body does not contain all the given
|
||||
// strings.
|
||||
// The condition returns an error if the request body does not contain all the given strings.
|
||||
func BodyContains(values ...string) ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
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 {
|
||||
@ -36,13 +34,12 @@ func BodyContains(values ...string) ResponseCondition {
|
||||
}
|
||||
|
||||
// BodyNotContains returns a retry condition function.
|
||||
// The condition returns an error if the request body contain one of the given
|
||||
// strings.
|
||||
// The condition returns an error if the request body contain one of the given strings.
|
||||
func BodyNotContains(values ...string) ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
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 {
|
||||
@ -55,13 +52,12 @@ func BodyNotContains(values ...string) ResponseCondition {
|
||||
}
|
||||
|
||||
// BodyContainsOr returns a retry condition function.
|
||||
// The condition returns an error if the request body does not contain one of the given
|
||||
// strings.
|
||||
// The condition returns an error if the request body does not contain one of the given strings.
|
||||
func BodyContainsOr(values ...string) ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
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 {
|
||||
@ -79,7 +75,7 @@ func HasBody() ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
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 {
|
||||
@ -182,11 +178,11 @@ func HasHeaderStruct(header http.Header) ResponseCondition {
|
||||
}
|
||||
|
||||
// DoCondition is a retry condition function.
|
||||
// It returns an error
|
||||
// It returns an error.
|
||||
type DoCondition func() error
|
||||
|
||||
// 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 {
|
||||
return func() error {
|
||||
_, err := kv.Exists(key, nil)
|
||||
|
@ -115,7 +115,7 @@ func Do(timeout time.Duration, operation DoCondition) error {
|
||||
select {
|
||||
case <-stopTimer.C:
|
||||
fmt.Println("-")
|
||||
return fmt.Errorf("try operation failed: %s", err)
|
||||
return fmt.Errorf("try operation failed: %w", err)
|
||||
case <-retryTick.C:
|
||||
fmt.Print("*")
|
||||
if err = operation(); err == nil {
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
// WebsocketSuite
|
||||
// WebsocketSuite tests suite.
|
||||
type WebsocketSuite struct{ BaseSuite }
|
||||
|
||||
func (s *WebsocketSuite) TestBase(c *check.C) {
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Zk test suites (using libcompose)
|
||||
// Zk test suites (using libcompose).
|
||||
type ZookeeperSuite struct {
|
||||
BaseSuite
|
||||
kvClient store.Store
|
||||
|
@ -15,7 +15,7 @@ const (
|
||||
maskLarge = maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort
|
||||
)
|
||||
|
||||
// Do configuration.
|
||||
// Do sends configuration.
|
||||
func Do(baseConfig interface{}, indent bool) (string, error) {
|
||||
anomConfig, err := copystructure.Copy(baseConfig)
|
||||
if err != nil {
|
||||
@ -120,7 +120,7 @@ func reset(field reflect.Value, name string) error {
|
||||
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 {
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
return false
|
||||
|
@ -8,12 +8,12 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// DashboardHandler expose dashboard routes
|
||||
// DashboardHandler expose dashboard routes.
|
||||
type DashboardHandler struct {
|
||||
Assets *assetfs.AssetFS
|
||||
}
|
||||
|
||||
// Append add dashboard routes on a router
|
||||
// Append add dashboard routes on a router.
|
||||
func (g DashboardHandler) Append(router *mux.Router) {
|
||||
if g.Assets == nil {
|
||||
log.WithoutContext().Error("No assets for dashboard")
|
||||
|
@ -19,10 +19,10 @@ func goroutines() interface{} {
|
||||
return runtime.NumGoroutine()
|
||||
}
|
||||
|
||||
// DebugHandler expose debug routes
|
||||
// DebugHandler expose debug routes.
|
||||
type DebugHandler struct{}
|
||||
|
||||
// Append add debug routes on a router
|
||||
// Append add debug routes on a router.
|
||||
func (g DebugHandler) Append(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).Path("/debug/vars").
|
||||
HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
|
@ -55,7 +55,7 @@ type Handler struct {
|
||||
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 {
|
||||
return func(configuration *runtime.Configuration) http.Handler {
|
||||
return New(staticConfig, configuration).createRouter()
|
||||
|
@ -55,7 +55,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
// Calls command without args.
|
||||
if len(args) == 1 {
|
||||
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
|
||||
}
|
||||
@ -65,7 +65,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
// then we run the top level command itself.
|
||||
if root && cmd.Name != args[1] && !contains(cmd.subCommands, args[1]) {
|
||||
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
|
||||
}
|
||||
@ -74,7 +74,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
if len(args) >= 2 && cmd.Name == args[1] {
|
||||
if len(args) < 3 || !contains(cmd.subCommands, args[2]) {
|
||||
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
|
||||
}
|
||||
@ -83,7 +83,7 @@ func execute(cmd *Command, args []string, root bool) error {
|
||||
// No sub-command, calls the current command.
|
||||
if len(cmd.subCommands) == 0 {
|
||||
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
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func (e *EnvLoader) Load(_ []string, cmd *Command) (bool, error) {
|
||||
|
||||
if err := env.Decode(vars, env.DefaultNamePrefix, cmd.Configuration); err != nil {
|
||||
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.")
|
||||
|
@ -17,7 +17,7 @@ func (*FlagLoader) Load(args []string, cmd *Command) (bool, error) {
|
||||
}
|
||||
|
||||
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.")
|
||||
|
@ -16,10 +16,10 @@ import (
|
||||
"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"
|
||||
|
||||
// Collected data
|
||||
// Collected data.
|
||||
type data struct {
|
||||
Version string
|
||||
Codename string
|
||||
|
@ -19,7 +19,7 @@ type Configurations map[string]*Configuration
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Configuration is the root of the dynamic configuration
|
||||
// Configuration is the root of the dynamic configuration.
|
||||
type Configuration struct {
|
||||
HTTP *HTTPConfiguration `json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty"`
|
||||
TCP *TCPConfiguration `json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty"`
|
||||
|
@ -47,7 +47,7 @@ type Router struct {
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// RouterTLSConfig holds the TLS configuration for a router
|
||||
// RouterTLSConfig holds the TLS configuration for a router.
|
||||
type RouterTLSConfig struct {
|
||||
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
|
||||
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`
|
||||
|
@ -95,7 +95,7 @@ type Buffering struct {
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Chain holds a chain of middlewares
|
||||
// Chain holds a chain of middlewares.
|
||||
type Chain struct {
|
||||
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"`
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return h != nil && (len(h.CustomResponseHeaders) != 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 {
|
||||
return h != nil && (h.AccessControlAllowCredentials ||
|
||||
len(h.AccessControlAllowHeaders) != 0 ||
|
||||
@ -208,7 +208,7 @@ func (h *Headers) HasCorsHeadersDefined() bool {
|
||||
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 {
|
||||
return h != nil && (len(h.AllowedHosts) != 0 ||
|
||||
len(h.HostsProxyHeaders) != 0 ||
|
||||
@ -245,7 +245,7 @@ type IPStrategy struct {
|
||||
// Get an IP selection strategy.
|
||||
// If nil return the RemoteAddr strategy
|
||||
// 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) {
|
||||
if s == nil {
|
||||
return &ip.RemoteAddrStrategy{}, nil
|
||||
@ -420,7 +420,7 @@ type TLSCLientCertificateDNInfo struct {
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// Users holds a list of users
|
||||
// Users holds a list of users.
|
||||
type Users []string
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
@ -449,7 +449,7 @@ func (c *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
|
||||
if _, errCA := os.Stat(c.CA); errCA == nil {
|
||||
ca, err = ioutil.ReadFile(c.CA)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read CA. %s", err)
|
||||
return nil, fmt.Errorf("failed to read CA. %w", err)
|
||||
}
|
||||
} else {
|
||||
ca = []byte(c.CA)
|
||||
@ -478,7 +478,7 @@ func (c *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
|
||||
if errKeyIsFile == nil {
|
||||
cert, err = tls.LoadX509KeyPair(c.Cert, c.Key)
|
||||
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 {
|
||||
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 {
|
||||
cert, err = tls.X509KeyPair([]byte(c.Cert), []byte(c.Key))
|
||||
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 {
|
||||
return nil, fmt.Errorf("TLS key is a file, but tls cert is not")
|
||||
|
@ -55,7 +55,7 @@ type TCPRouter struct {
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// RouterTCPTLSConfig holds the TLS configuration for a router
|
||||
// RouterTCPTLSConfig holds the TLS configuration for a router.
|
||||
type RouterTCPTLSConfig struct {
|
||||
Passthrough bool `json:"passthrough" toml:"passthrough" yaml:"passthrough"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// SetDefaults Default values for a TCPServersLoadBalancer
|
||||
// SetDefaults Default values for a TCPServersLoadBalancer.
|
||||
func (l *TCPServersLoadBalancer) SetDefaults() {
|
||||
defaultTerminationDelay := 100 // in milliseconds
|
||||
l.TerminationDelay = &defaultTerminationDelay
|
||||
@ -101,7 +101,7 @@ func (l *TCPServersLoadBalancer) Mergeable(loadBalancer *TCPServersLoadBalancer)
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TCPServer holds a TCP Server configuration
|
||||
// TCPServer holds a TCP Server configuration.
|
||||
type TCPServer struct {
|
||||
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty" label:"-"`
|
||||
Port string `toml:"-" json:"-" yaml:"-"`
|
||||
|
4
pkg/config/env/env.go
vendored
4
pkg/config/env/env.go
vendored
@ -17,7 +17,7 @@ const DefaultNamePrefix = "TRAEFIK_"
|
||||
// env vars -> map
|
||||
// map -> tree of untyped nodes
|
||||
// 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 {
|
||||
if err := checkPrefix(prefix); err != nil {
|
||||
return err
|
||||
@ -40,7 +40,7 @@ func Decode(environ []string, prefix string, element interface{}) error {
|
||||
// The operation goes through three stages roughly summarized as:
|
||||
// typed configuration in element -> tree of untyped nodes
|
||||
// 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) {
|
||||
if element == nil {
|
||||
return nil, nil
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
// The operation goes through three stages roughly summarized as:
|
||||
// file contents -> tree of untyped nodes
|
||||
// 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 {
|
||||
if element == nil {
|
||||
return nil
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
// flag arguments -> parsed map of flags
|
||||
// map -> tree of untyped nodes
|
||||
// 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 {
|
||||
ref, err := Parse(args, element)
|
||||
if err != nil {
|
||||
@ -24,7 +24,7 @@ func Decode(args []string, element interface{}) error {
|
||||
// The operation goes through three stages roughly summarized as:
|
||||
// typed configuration in element -> tree of untyped nodes
|
||||
// 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) {
|
||||
if element == nil {
|
||||
return nil, nil
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
// The operation goes through three stages roughly summarized as:
|
||||
// KV pairs -> tree of untyped nodes
|
||||
// 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 {
|
||||
if element == nil {
|
||||
return nil
|
||||
|
@ -28,7 +28,7 @@ func EncodeConfiguration(conf *dynamic.Configuration) (map[string]string, error)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return parser.Decode(labels, element, parser.DefaultRootName, filters...)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ type EncoderToNodeOpts struct {
|
||||
}
|
||||
|
||||
// EncodeToNode converts an element to a node.
|
||||
// element -> nodes
|
||||
// element -> nodes.
|
||||
func EncodeToNode(element interface{}, rootName string, opts EncoderToNodeOpts) (*Node, error) {
|
||||
rValue := reflect.ValueOf(element)
|
||||
node := &Node{Name: rootName}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package parser
|
||||
|
||||
// EncodeNode Converts a node to labels.
|
||||
// nodes -> labels
|
||||
// nodes -> labels.
|
||||
func EncodeNode(node *Node) map[string]string {
|
||||
labels := make(map[string]string)
|
||||
encodeNode(labels, node.Name, node)
|
||||
|
@ -6,7 +6,7 @@ package parser
|
||||
// The operation goes through three stages roughly summarized as:
|
||||
// labels -> tree of untyped nodes
|
||||
// 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 {
|
||||
node, err := DecodeToNode(labels, rootName, filters...)
|
||||
if err != nil {
|
||||
@ -28,7 +28,7 @@ func Decode(labels map[string]string, element interface{}, rootName string, filt
|
||||
}
|
||||
|
||||
// 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) {
|
||||
etnOpts := EncoderToNodeOpts{OmitEmpty: true, TagName: TagLabel, AllowSliceAsStruct: true}
|
||||
node, err := EncodeToNode(element, rootName, etnOpts)
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"github.com/containous/traefik/v2/pkg/log"
|
||||
)
|
||||
|
||||
// Status of the router/service
|
||||
// Status of the router/service.
|
||||
const (
|
||||
StatusEnabled = "enabled"
|
||||
StatusDisabled = "disabled"
|
||||
|
@ -179,7 +179,7 @@ func (s *ServiceInfo) UpdateServerStatus(server string, status string) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
s.serverStatusMu.RLock()
|
||||
defer s.serverStatusMu.RUnlock()
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"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) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -49,7 +49,7 @@ const (
|
||||
DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
)
|
||||
|
||||
// Configuration is the static configuration
|
||||
// Configuration is the static configuration.
|
||||
type Configuration struct {
|
||||
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"`
|
||||
}
|
||||
|
||||
// ServersTransport options to configure communication between Traefik and the servers
|
||||
// ServersTransport options to configure communication between Traefik and the servers.
|
||||
type ServersTransport struct {
|
||||
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"`
|
||||
@ -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"`
|
||||
}
|
||||
|
||||
// API holds the API configuration
|
||||
// API holds the API configuration.
|
||||
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"`
|
||||
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
|
||||
}
|
||||
|
||||
// Providers contains providers configuration
|
||||
// Providers contains providers configuration.
|
||||
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"`
|
||||
|
||||
@ -224,7 +224,7 @@ func (c *Configuration) initACMEProvider() {
|
||||
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 {
|
||||
var acmeEmail string
|
||||
for name, resolver := range c.CertificatesResolvers {
|
||||
|
@ -25,8 +25,7 @@ const (
|
||||
var singleton *HealthCheck
|
||||
var once sync.Once
|
||||
|
||||
// Balancer is the set of operations required to manage the list of servers in a
|
||||
// load-balancer.
|
||||
// Balancer is the set of operations required to manage the list of servers in a load-balancer.
|
||||
type Balancer interface {
|
||||
Servers() []*url.URL
|
||||
RemoveServer(u *url.URL) error
|
||||
@ -39,8 +38,9 @@ type BalancerHandler interface {
|
||||
Balancer
|
||||
}
|
||||
|
||||
// metricsRegistry is a local interface in the health check package, exposing only the required metrics
|
||||
// necessary for the health check package. This makes it easier for the tests.
|
||||
// metricsRegistry is a local interface in the health check package,
|
||||
// exposing only the required metrics necessary for the health check package.
|
||||
// This makes it easier for the tests.
|
||||
type metricsRegistry interface {
|
||||
BackendServerUpGauge() metrics.Gauge
|
||||
}
|
||||
@ -68,7 +68,7 @@ type backendURL struct {
|
||||
weight int
|
||||
}
|
||||
|
||||
// BackendConfig HealthCheck configuration for a backend
|
||||
// BackendConfig HealthCheck configuration for a backend.
|
||||
type BackendConfig struct {
|
||||
Options
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if b.Options.Hostname != "" {
|
||||
req.Host = b.Options.Hostname
|
||||
@ -104,14 +104,14 @@ func (b *BackendConfig) addHeadersAndHost(req *http.Request) *http.Request {
|
||||
return req
|
||||
}
|
||||
|
||||
// HealthCheck struct
|
||||
// HealthCheck struct.
|
||||
type HealthCheck struct {
|
||||
Backends map[string]*BackendConfig
|
||||
metrics metricsRegistry
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
// SetBackendsConfiguration set backends configuration
|
||||
// SetBackendsConfiguration set backends configuration.
|
||||
func (hc *HealthCheck) SetBackendsConfiguration(parentCtx context.Context, backends map[string]*BackendConfig) {
|
||||
hc.Backends = backends
|
||||
if hc.cancel != nil {
|
||||
@ -152,28 +152,21 @@ func (hc *HealthCheck) checkBackend(ctx context.Context, backend *BackendConfig)
|
||||
|
||||
enabledURLs := backend.LB.Servers()
|
||||
var newDisabledURLs []backendURL
|
||||
// FIXME re enable metrics
|
||||
for _, disabledURL := range backend.disabledURLs {
|
||||
// FIXME serverUpMetricValue := float64(0)
|
||||
if err := checkHealth(disabledURL.url, backend); err == nil {
|
||||
logger.Warnf("Health check up: Returning to server list. Backend: %q URL: %q Weight: %d",
|
||||
backend.name, disabledURL.url.String(), disabledURL.weight)
|
||||
if err = backend.LB.UpsertServer(disabledURL.url, roundrobin.Weight(disabledURL.weight)); err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
// FIXME serverUpMetricValue = 1
|
||||
} else {
|
||||
logger.Warnf("Health check still failing. Backend: %q URL: %q Reason: %s", backend.name, disabledURL.url.String(), err)
|
||||
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
|
||||
|
||||
// FIXME re enable metrics
|
||||
for _, enableURL := range enabledURLs {
|
||||
// FIXME serverUpMetricValue := float64(1)
|
||||
if err := checkHealth(enableURL, backend); err != nil {
|
||||
weight := 1
|
||||
rr, ok := backend.LB.(*roundrobin.RoundRobin)
|
||||
@ -189,35 +182,25 @@ func (hc *HealthCheck) checkBackend(ctx context.Context, backend *BackendConfig)
|
||||
logger.Error(err)
|
||||
}
|
||||
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.
|
||||
func GetHealthCheck() *HealthCheck {
|
||||
once.Do(func() {
|
||||
singleton = newHealthCheck()
|
||||
//singleton = newHealthCheck(metrics)
|
||||
})
|
||||
return singleton
|
||||
}
|
||||
|
||||
// FIXME re add metrics
|
||||
//func newHealthCheck(metrics metricsRegistry) *HealthCheck {
|
||||
func newHealthCheck() *HealthCheck {
|
||||
return &HealthCheck{
|
||||
Backends: make(map[string]*BackendConfig),
|
||||
//metrics: metrics,
|
||||
}
|
||||
}
|
||||
|
||||
// NewBackendConfig Instantiate a new BackendConfig
|
||||
// NewBackendConfig Instantiate a new BackendConfig.
|
||||
func NewBackendConfig(options Options, backendName string) *BackendConfig {
|
||||
return &BackendConfig{
|
||||
Options: options,
|
||||
@ -230,7 +213,7 @@ func NewBackendConfig(options Options, backendName string) *BackendConfig {
|
||||
func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
|
||||
req, err := backend.newRequest(serverURL)
|
||||
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)
|
||||
@ -248,7 +231,7 @@ func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTP request failed: %s", err)
|
||||
return fmt.Errorf("HTTP request failed: %w", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
@ -260,7 +243,7 @@ func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewLBStatusUpdater returns a new LbStatusUpdater
|
||||
// NewLBStatusUpdater returns a new LbStatusUpdater.
|
||||
func NewLBStatusUpdater(bh BalancerHandler, info *runtime.ServiceInfo) *LbStatusUpdater {
|
||||
return &LbStatusUpdater{
|
||||
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.
|
||||
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 {
|
||||
var servers []*url.URL
|
||||
for _, lb := range b {
|
||||
|
@ -7,13 +7,13 @@ import (
|
||||
"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 {
|
||||
authorizedIPs []*net.IP
|
||||
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) {
|
||||
if len(trustedIPs) == 0 {
|
||||
return nil, errors.New("no trusted IPs provided")
|
||||
@ -27,7 +27,7 @@ func NewChecker(trustedIPs []string) (*Checker, error) {
|
||||
} else {
|
||||
_, ipAddr, err := net.ParseCIDR(ipMask)
|
||||
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)
|
||||
}
|
||||
@ -36,7 +36,7 @@ func NewChecker(trustedIPs []string) (*Checker, error) {
|
||||
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 {
|
||||
var invalidMatches []string
|
||||
|
||||
@ -58,7 +58,7 @@ func (ip *Checker) IsAuthorized(addr string) error {
|
||||
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) {
|
||||
if len(addr) == 0 {
|
||||
return false, errors.New("empty IP address")
|
||||
@ -66,13 +66,13 @@ func (ip *Checker) Contains(addr string) (bool, error) {
|
||||
|
||||
ipAddr, err := parseIP(addr)
|
||||
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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
for _, authorizedIP := range ip.authorizedIPs {
|
||||
if authorizedIP.Equal(addr) {
|
||||
|
@ -10,15 +10,15 @@ const (
|
||||
xForwardedFor = "X-Forwarded-For"
|
||||
)
|
||||
|
||||
// Strategy a strategy for IP selection
|
||||
// Strategy a strategy for IP selection.
|
||||
type Strategy interface {
|
||||
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{}
|
||||
|
||||
// GetIP returns the selected IP
|
||||
// GetIP returns the selected IP.
|
||||
func (s *RemoteAddrStrategy) GetIP(req *http.Request) string {
|
||||
ip, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||
if err != nil {
|
||||
@ -27,12 +27,12 @@ func (s *RemoteAddrStrategy) GetIP(req *http.Request) string {
|
||||
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 {
|
||||
Depth int
|
||||
}
|
||||
|
||||
// GetIP return the selected IP
|
||||
// GetIP return the selected IP.
|
||||
func (s *DepthStrategy) GetIP(req *http.Request) string {
|
||||
xff := req.Header.Get(xForwardedFor)
|
||||
xffs := strings.Split(xff, ",")
|
||||
@ -44,12 +44,12 @@ func (s *DepthStrategy) GetIP(req *http.Request) string {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Checker *Checker
|
||||
}
|
||||
|
||||
// GetIP return the selected IP
|
||||
// GetIP return the selected IP.
|
||||
func (s *CheckerStrategy) GetIP(req *http.Request) string {
|
||||
if s.Checker == nil {
|
||||
return ""
|
||||
|
@ -80,7 +80,7 @@ func AddHook(hook logrus.Hook) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
// Hack the buffer size
|
||||
// Hack the buffer size.
|
||||
func writerScanner(reader io.ReadCloser, scanTokenSize int, printFunc func(args ...interface{})) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package log
|
||||
|
||||
// Log entry name
|
||||
// Log entry names.
|
||||
const (
|
||||
EntryPointName = "entryPointName"
|
||||
RouterName = "routerName"
|
||||
|
@ -15,7 +15,7 @@ const (
|
||||
loggerKey contextKey = iota
|
||||
)
|
||||
|
||||
// Logger the Traefik logger
|
||||
// Logger the Traefik logger.
|
||||
type Logger interface {
|
||||
logrus.FieldLogger
|
||||
WriterLevel(logrus.Level) *io.PipeWriter
|
||||
@ -57,14 +57,14 @@ func GetLevel() logrus.Level {
|
||||
return logrus.GetLevel()
|
||||
}
|
||||
|
||||
// Str adds a string field
|
||||
// Str adds a string field.
|
||||
func Str(key, value string) func(logrus.Fields) {
|
||||
return func(fields logrus.Fields) {
|
||||
fields[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// With Adds fields
|
||||
// With Adds fields.
|
||||
func With(ctx context.Context, opts ...func(logrus.Fields)) context.Context {
|
||||
logger := FromContext(ctx)
|
||||
|
||||
@ -77,7 +77,7 @@ func With(ctx context.Context, opts ...func(logrus.Fields)) context.Context {
|
||||
return context.WithValue(ctx, loggerKey, logger)
|
||||
}
|
||||
|
||||
// FromContext Gets the logger from context
|
||||
// FromContext Gets the logger from context.
|
||||
func FromContext(ctx context.Context) Logger {
|
||||
if ctx == nil {
|
||||
panic("nil context")
|
||||
@ -91,12 +91,12 @@ func FromContext(ctx context.Context) Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// WithoutContext Gets the main logger
|
||||
// WithoutContext Gets the main logger.
|
||||
func WithoutContext() Logger {
|
||||
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 {
|
||||
logFilePath = path
|
||||
|
||||
@ -110,7 +110,7 @@ func OpenFile(path string) error {
|
||||
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 {
|
||||
logrus.SetOutput(os.Stdout)
|
||||
|
||||
@ -120,9 +120,8 @@ func CloseFile() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RotateFile closes and reopens the log file to allow for rotation
|
||||
// by an external source. If the log isn't backed by a file then
|
||||
// it does nothing.
|
||||
// RotateFile closes and reopens the log file to allow for rotation by an external source.
|
||||
// If the log isn't backed by a file then it does nothing.
|
||||
func RotateFile() error {
|
||||
logger := FromContext(context.Background())
|
||||
|
||||
|
@ -80,7 +80,7 @@ func RegisterInfluxDB(ctx context.Context, config *types.InfluxDB) Registry {
|
||||
return registry
|
||||
}
|
||||
|
||||
// initInfluxDBTicker creates a influxDBClient
|
||||
// initInfluxDBTicker creates a influxDBClient.
|
||||
func initInfluxDBClient(ctx context.Context, config *types.InfluxDB) *influx.Influx {
|
||||
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 {
|
||||
report := time.NewTicker(time.Duration(config.PushInterval))
|
||||
|
||||
@ -135,7 +135,7 @@ func initInfluxDBTicker(ctx context.Context, config *types.InfluxDB) *time.Ticke
|
||||
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() {
|
||||
if influxDBTicker != nil {
|
||||
influxDBTicker.Stop()
|
||||
|
@ -71,7 +71,7 @@ func RegisterStatsd(ctx context.Context, config *types.Statsd) 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 {
|
||||
address := config.Address
|
||||
if len(address) == 0 {
|
||||
@ -87,7 +87,7 @@ func initStatsdTicker(ctx context.Context, config *types.Statsd) *time.Ticker {
|
||||
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() {
|
||||
if statsdTicker != nil {
|
||||
statsdTicker.Stop()
|
||||
|
@ -28,7 +28,7 @@ func newCaptureResponseWriter(rw http.ResponseWriter) capturer {
|
||||
}
|
||||
|
||||
// captureResponseWriter is a wrapper of type http.ResponseWriter
|
||||
// that tracks request status and size
|
||||
// that tracks request status and size.
|
||||
type captureResponseWriter struct {
|
||||
rw http.ResponseWriter
|
||||
status int
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"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)
|
||||
|
||||
// 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) {
|
||||
data.Core[ServiceURL] = req.URL // note that this is *not* the original incoming URL
|
||||
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)
|
||||
}
|
||||
|
||||
// AddOriginFields add origin fields
|
||||
// AddOriginFields add origin fields.
|
||||
func AddOriginFields(rw http.ResponseWriter, req *http.Request, next http.Handler, data *LogData) {
|
||||
crw := newCaptureResponseWriter(rw)
|
||||
start := time.Now().UTC()
|
||||
|
@ -75,7 +75,7 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
|
||||
if len(config.FilePath) > 0 {
|
||||
f, err := openAccessLogFile(config.FilePath)
|
||||
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
|
||||
}
|
||||
@ -132,12 +132,12 @@ func openAccessLogFile(filePath string) (*os.File, error) {
|
||||
dir := filepath.Dir(filePath)
|
||||
|
||||
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)
|
||||
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
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"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) {
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString(`(\S+)`) // 1 - ClientHost
|
||||
|
@ -20,7 +20,7 @@ const (
|
||||
wwwAuthenticate = "Www-Authenticate"
|
||||
)
|
||||
|
||||
// DigestRequest is a client for digest authentication requests
|
||||
// DigestRequest is a client for digest authentication requests.
|
||||
type digestRequest struct {
|
||||
client *http.Client
|
||||
username, password string
|
||||
@ -35,7 +35,7 @@ func (nc nonceCount) String() string {
|
||||
|
||||
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 {
|
||||
return &digestRequest{
|
||||
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) {
|
||||
parts, err := r.makeParts(req)
|
||||
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 {
|
||||
b := make([]byte, 8)
|
||||
_, _ = io.ReadFull(rand.Reader, b)
|
||||
|
@ -18,7 +18,7 @@ type chainBuilder interface {
|
||||
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) {
|
||||
log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")
|
||||
|
||||
|
@ -39,7 +39,7 @@ func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.Circ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewCircuitBreakerOptions returns a new CircuitBreakerOption
|
||||
// NewCircuitBreakerOptions returns a new CircuitBreakerOption.
|
||||
func createCircuitBreakerOptions(expression string) cbreaker.CircuitBreakerOption {
|
||||
return cbreaker.Fallback(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
tracing.SetErrorWithEvent(req, "blocked by circuit-breaker (%q)", expression)
|
||||
|
@ -131,12 +131,12 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
func newRequest(baseURL string) (*http.Request, error) {
|
||||
u, err := url.Parse(baseURL)
|
||||
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)
|
||||
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()
|
||||
@ -250,7 +250,7 @@ func (cc *codeCatcher) WriteHeader(code int) {
|
||||
cc.headersSent = true
|
||||
}
|
||||
|
||||
// Hijack hijacks the connection
|
||||
// Hijack hijacks the connection.
|
||||
func (cc *codeCatcher) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
if hj, ok := cc.responseWriter.(http.Hijacker); ok {
|
||||
return hj.Hijack()
|
||||
@ -349,7 +349,7 @@ func (r *responseRecorderWithoutCloseNotify) WriteHeader(code int) {
|
||||
r.Code = code
|
||||
}
|
||||
|
||||
// Hijack hijacks the connection
|
||||
// Hijack hijacks the connection.
|
||||
func (r *responseRecorderWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return r.responseWriter.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
@ -37,9 +37,10 @@ var xHeaders = []string{
|
||||
xRealIP,
|
||||
}
|
||||
|
||||
// XForwarded is an HTTP handler wrapper that sets the X-Forwarded headers, and other relevant headers for a
|
||||
// reverse-proxy. 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.
|
||||
// XForwarded is an HTTP handler wrapper that sets the X-Forwarded headers,
|
||||
// and other relevant headers for a reverse-proxy.
|
||||
// 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 {
|
||||
insecure bool
|
||||
trustedIps []string
|
||||
@ -80,15 +81,13 @@ func (x *XForwarded) isTrustedIP(ip string) bool {
|
||||
return x.ipChecker.IsAuthorized(ip) == nil
|
||||
}
|
||||
|
||||
// removeIPv6Zone removes the zone if the given IP is an ipv6 address and it has
|
||||
// {zone} information in it, like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3
|
||||
// Ethernet Adapter - Virtual Switch)]:64692"
|
||||
// removeIPv6Zone removes the zone if the given IP is an ipv6 address and it has {zone} information in it,
|
||||
// like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3 Ethernet Adapter - Virtual Switch)]:64692".
|
||||
func removeIPv6Zone(clientIP string) string {
|
||||
return strings.Split(clientIP, "%")[0]
|
||||
}
|
||||
|
||||
// isWebsocketRequest returns whether the specified HTTP request is a
|
||||
// websocket handshake request
|
||||
// isWebsocketRequest returns whether the specified HTTP request is a websocket handshake request.
|
||||
func isWebsocketRequest(req *http.Request) bool {
|
||||
containsHeader := func(name, value string) bool {
|
||||
items := strings.Split(req.Header.Get(name), ",")
|
||||
@ -141,7 +140,7 @@ func (x *XForwarded) rewrite(outreq *http.Request) {
|
||||
}
|
||||
|
||||
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")
|
||||
} else {
|
||||
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) {
|
||||
if !x.insecure && !x.isTrustedIP(r.RemoteAddr) {
|
||||
for _, h := range xHeaders {
|
||||
|
@ -203,6 +203,17 @@ func TestServeHTTP(t *testing.T) {
|
||||
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",
|
||||
host: "foo.com:8080",
|
||||
|
@ -6,12 +6,12 @@ import (
|
||||
"github.com/containous/traefik/v2/pkg/safe"
|
||||
)
|
||||
|
||||
// HTTPHandlerSwitcher allows hot switching of http.ServeMux
|
||||
// HTTPHandlerSwitcher allows hot switching of http.ServeMux.
|
||||
type HTTPHandlerSwitcher struct {
|
||||
handler *safe.Safe
|
||||
}
|
||||
|
||||
// NewHandlerSwitcher builds a new instance of HTTPHandlerSwitcher
|
||||
// NewHandlerSwitcher builds a new instance of HTTPHandlerSwitcher.
|
||||
func NewHandlerSwitcher(newHandler http.Handler) (hs *HTTPHandlerSwitcher) {
|
||||
return &HTTPHandlerSwitcher{
|
||||
handler: safe.New(newHandler),
|
||||
@ -23,13 +23,13 @@ func (h *HTTPHandlerSwitcher) ServeHTTP(rw http.ResponseWriter, req *http.Reques
|
||||
handlerBackup.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
// GetHandler returns the current http.ServeMux
|
||||
// GetHandler returns the current http.ServeMux.
|
||||
func (h *HTTPHandlerSwitcher) GetHandler() (newHandler http.Handler) {
|
||||
handler := h.handler.Get().(http.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) {
|
||||
h.handler.Set(newHandler)
|
||||
}
|
||||
|
@ -38,12 +38,12 @@ func New(ctx context.Context, next http.Handler, config dynamic.InFlightReq, nam
|
||||
|
||||
sourceMatcher, err := middlewares.GetSourceExtractor(ctxLog, config.SourceCriterion)
|
||||
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)
|
||||
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
|
||||
|
@ -18,7 +18,7 @@ const (
|
||||
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 {
|
||||
next http.Handler
|
||||
whiteLister *ip.Checker
|
||||
@ -26,7 +26,7 @@ type ipWhiteLister struct {
|
||||
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) {
|
||||
logger := log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName))
|
||||
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)
|
||||
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()
|
||||
|
@ -50,7 +50,7 @@ func (r *responseRecorder) WriteHeader(status int) {
|
||||
r.statusCode = status
|
||||
}
|
||||
|
||||
// Hijack hijacks the connection
|
||||
// Hijack hijacks the connection.
|
||||
func (r *responseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return r.ResponseWriter.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
@ -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 root fields
|
||||
// - 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 {
|
||||
var headerValues []string
|
||||
|
||||
|
@ -14,12 +14,12 @@ const (
|
||||
typeName = "Pipelining"
|
||||
)
|
||||
|
||||
// pipelining returns a middleware
|
||||
// pipelining returns a middleware.
|
||||
type pipelining struct {
|
||||
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 {
|
||||
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 {
|
||||
W http.ResponseWriter
|
||||
}
|
||||
@ -52,8 +52,7 @@ func (w *writerWithoutCloseNotify) Write(buf []byte) (int, error) {
|
||||
return w.W.Write(buf)
|
||||
}
|
||||
|
||||
// WriteHeader sends an HTTP response header with the provided
|
||||
// status code.
|
||||
// WriteHeader sends an HTTP response header with the provided status code.
|
||||
func (w *writerWithoutCloseNotify) WriteHeader(code int) {
|
||||
w.W.WriteHeader(code)
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ func New(ctx context.Context, next http.Handler, config dynamic.ReplacePathRegex
|
||||
|
||||
exp, err := regexp.Compile(strings.TrimSpace(config.Regex))
|
||||
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{
|
||||
|
@ -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) {
|
||||
resp, _, err := client.Exchange(msg, net.JoinHostPort(server, port))
|
||||
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 {
|
||||
|
@ -3,7 +3,7 @@ package middlewares
|
||||
import "net/http"
|
||||
|
||||
// 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 {
|
||||
http.ResponseWriter
|
||||
http.Hijacker
|
||||
|
@ -27,12 +27,12 @@ func (n MockTracer) Extract(format interface{}, carrier interface{}) (opentracin
|
||||
return nil, opentracing.ErrSpanContextNotFound
|
||||
}
|
||||
|
||||
// MockSpanContext
|
||||
// MockSpanContext.
|
||||
type MockSpanContext struct{}
|
||||
|
||||
func (n MockSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {}
|
||||
|
||||
// MockSpan
|
||||
// MockSpan.
|
||||
type MockSpan struct {
|
||||
OpName string
|
||||
Tags map[string]interface{}
|
||||
|
@ -22,12 +22,12 @@ func (s *statusCodeWithoutCloseNotify) WriteHeader(status int) {
|
||||
s.ResponseWriter.WriteHeader(status)
|
||||
}
|
||||
|
||||
// Status get response status
|
||||
// Status get response status.
|
||||
func (s *statusCodeWithoutCloseNotify) Status() int {
|
||||
return s.status
|
||||
}
|
||||
|
||||
// Hijack hijacks the connection
|
||||
// Hijack hijacks the connection.
|
||||
func (s *statusCodeWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return s.ResponseWriter.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
@ -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 {
|
||||
return &Wrapper{
|
||||
next: next,
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"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 {
|
||||
Email string
|
||||
Registration *registration.Resource
|
||||
@ -21,11 +21,11 @@ type Account struct {
|
||||
}
|
||||
|
||||
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+$`
|
||||
)
|
||||
|
||||
// NewAccount creates an account
|
||||
// NewAccount creates an account.
|
||||
func NewAccount(ctx context.Context, email string, keyTypeValue string) (*Account, error) {
|
||||
keyType := GetKeyType(ctx, keyTypeValue)
|
||||
|
||||
@ -42,17 +42,17 @@ func NewAccount(ctx context.Context, email string, keyTypeValue string) (*Accoun
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetEmail returns email
|
||||
// GetEmail returns email.
|
||||
func (a *Account) GetEmail() string {
|
||||
return a.Email
|
||||
}
|
||||
|
||||
// GetRegistration returns lets encrypt registration resource
|
||||
// GetRegistration returns lets encrypt registration resource.
|
||||
func (a *Account) GetRegistration() *registration.Resource {
|
||||
return a.Registration
|
||||
}
|
||||
|
||||
// GetPrivateKey returns private key
|
||||
// GetPrivateKey returns private key.
|
||||
func (a *Account) GetPrivateKey() crypto.PrivateKey {
|
||||
privateKey, err := x509.ParsePKCS1PrivateKey(a.PrivateKey)
|
||||
if err != nil {
|
||||
@ -64,7 +64,7 @@ func (a *Account) GetPrivateKey() crypto.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 {
|
||||
logger := log.FromContext(ctx)
|
||||
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
var _ Store = (*LocalStore)(nil)
|
||||
|
||||
// LocalStore Stores implementation for local file
|
||||
// LocalStore Stores implementation for local file.
|
||||
type LocalStore struct {
|
||||
saveDataChan chan map[string]*StoredData
|
||||
filename string
|
||||
@ -22,7 +22,7 @@ type LocalStore struct {
|
||||
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 {
|
||||
store := &LocalStore{filename: filename, saveDataChan: make(chan map[string]*StoredData)}
|
||||
store.listenSaveAction()
|
||||
@ -93,7 +93,7 @@ func (s *LocalStore) get(resolverName string) (*StoredData, error) {
|
||||
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() {
|
||||
safe.Go(func() {
|
||||
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) {
|
||||
storedData, err := s.get(resolverName)
|
||||
if err != nil {
|
||||
@ -121,7 +121,7 @@ func (s *LocalStore) GetAccount(resolverName string) (*Account, error) {
|
||||
return storedData.Account, nil
|
||||
}
|
||||
|
||||
// SaveAccount stores ACME Account
|
||||
// SaveAccount stores ACME Account.
|
||||
func (s *LocalStore) SaveAccount(resolverName string, account *Account) error {
|
||||
storedData, err := s.get(resolverName)
|
||||
if err != nil {
|
||||
@ -134,7 +134,7 @@ func (s *LocalStore) SaveAccount(resolverName string, account *Account) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCertificates returns ACME Certificates list
|
||||
// GetCertificates returns ACME Certificates list.
|
||||
func (s *LocalStore) GetCertificates(resolverName string) ([]*CertAndStore, error) {
|
||||
storedData, err := s.get(resolverName)
|
||||
if err != nil {
|
||||
@ -144,7 +144,7 @@ func (s *LocalStore) GetCertificates(resolverName string) ([]*CertAndStore, erro
|
||||
return storedData.Certificates, nil
|
||||
}
|
||||
|
||||
// SaveCertificates stores ACME Certificates list
|
||||
// SaveCertificates stores ACME Certificates list.
|
||||
func (s *LocalStore) SaveCertificates(resolverName string, certificates []*CertAndStore) error {
|
||||
storedData, err := s.get(resolverName)
|
||||
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) {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
@ -193,7 +193,7 @@ func (s *LocalChallengeStore) GetHTTPChallengeToken(token, domain string) ([]byt
|
||||
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 {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
@ -210,7 +210,7 @@ func (s *LocalChallengeStore) SetHTTPChallengeToken(token, domain string, keyAut
|
||||
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 {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
@ -228,7 +228,7 @@ func (s *LocalChallengeStore) RemoveHTTPChallengeToken(token, domain string) err
|
||||
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 {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
@ -241,7 +241,7 @@ func (s *LocalChallengeStore) AddTLSChallenge(domain string, cert *Certificate)
|
||||
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) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
@ -253,7 +253,7 @@ func (s *LocalChallengeStore) GetTLSChallenge(domain string) (*Certificate, erro
|
||||
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 {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// CheckFile checks file permissions and content size
|
||||
// CheckFile checks file permissions and content size.
|
||||
func CheckFile(name string) (bool, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
|
@ -28,11 +28,11 @@ import (
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
// Configuration holds ACME configuration provided by users
|
||||
// Configuration holds ACME configuration provided by users.
|
||||
type Configuration struct {
|
||||
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"`
|
||||
@ -56,14 +56,14 @@ type CertAndStore struct {
|
||||
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 {
|
||||
Domain types.Domain `json:"domain,omitempty" toml:"domain,omitempty" yaml:"domain,omitempty"`
|
||||
Certificate []byte `json:"certificate,omitempty" toml:"certificate,omitempty" yaml:"certificate,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 {
|
||||
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"`
|
||||
@ -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"`
|
||||
}
|
||||
|
||||
// HTTPChallenge contains HTTP challenge Configuration
|
||||
// HTTPChallenge contains HTTP challenge Configuration.
|
||||
type HTTPChallenge struct {
|
||||
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{}
|
||||
|
||||
// Provider holds configurations of the provider.
|
||||
@ -98,22 +98,22 @@ type Provider struct {
|
||||
resolvingDomainsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
// SetTLSManager sets the tls manager to use
|
||||
// SetTLSManager sets the tls manager to use.
|
||||
func (p *Provider) SetTLSManager(tlsManager *traefiktls.Manager) {
|
||||
p.tlsManager = tlsManager
|
||||
}
|
||||
|
||||
// SetConfigListenerChan initializes the configFromListenerChan
|
||||
// SetConfigListenerChan initializes the configFromListenerChan.
|
||||
func (p *Provider) SetConfigListenerChan(configFromListenerChan chan dynamic.Configuration) {
|
||||
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) {
|
||||
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 {
|
||||
ctx := log.With(context.Background(), log.Str(log.ProviderName, p.ResolverName+".acme"))
|
||||
logger := log.FromContext(ctx)
|
||||
@ -125,7 +125,7 @@ func (p *Provider) Init() error {
|
||||
var err error
|
||||
p.account, err = p.Store.GetAccount(p.ResolverName)
|
||||
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
|
||||
@ -136,7 +136,7 @@ func (p *Provider) Init() error {
|
||||
|
||||
p.certificates, err = p.Store.GetCertificates(p.ResolverName)
|
||||
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
|
||||
@ -442,7 +442,7 @@ func (p *Provider) resolveCertificate(ctx context.Context, domain types.Domain,
|
||||
|
||||
client, err := p.getClient()
|
||||
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{
|
||||
@ -453,7 +453,7 @@ func (p *Provider) resolveCertificate(ctx context.Context, domain types.Domain,
|
||||
|
||||
cert, err := client.Certificate.Obtain(request)
|
||||
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 {
|
||||
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 :
|
||||
// - 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 {
|
||||
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)
|
||||
// from static and dynamic provided certificates
|
||||
// from static and dynamic provided certificates.
|
||||
func (p *Provider) getUncheckedDomains(ctx context.Context, domainsToCheck []string, tlsStore string) []string {
|
||||
p.resolvingDomainsMutex.RLock()
|
||||
defer p.resolvingDomainsMutex.RUnlock()
|
||||
@ -716,7 +716,7 @@ func getX509Certificate(ctx context.Context, cert *Certificate) (*x509.Certifica
|
||||
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) {
|
||||
domains := domain.ToStrArray()
|
||||
if len(domains) == 0 {
|
||||
|
@ -94,12 +94,12 @@ func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Init the provider
|
||||
// Init the provider.
|
||||
func (p ProviderAggregator) Init() error {
|
||||
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 {
|
||||
if p.fileProvider != nil {
|
||||
launchProvider(configurationChan, pool, p.fileProvider)
|
||||
|
@ -18,7 +18,7 @@ type constraintLabelFunc func(map[string]string) bool
|
||||
// The expression must match any logical boolean combination of:
|
||||
// - `Label(labelName, labelValue)`
|
||||
// - `LabelRegex(labelName, regexValue)`
|
||||
// - `MarathonConstraint(field:operator:value)`
|
||||
// - `MarathonConstraint(field:operator:value)`.
|
||||
func MatchLabels(labels map[string]string, expr string) (bool, error) {
|
||||
if expr == "" {
|
||||
return true, nil
|
||||
|
@ -12,7 +12,7 @@ type constraintTagFunc func([]string) bool
|
||||
// MatchTags reports whether the expression matches with the given tags.
|
||||
// The expression must match any logical boolean combination of:
|
||||
// - `Tag(tagValue)`
|
||||
// - `TagRegex(regexValue)`
|
||||
// - `TagRegex(regexValue)`.
|
||||
func MatchTags(tags []string, expr string) (bool, error) {
|
||||
if expr == "" {
|
||||
return true, nil
|
||||
|
@ -89,7 +89,7 @@ func (p *Provider) SetDefaults() {
|
||||
func (p *Provider) Init() error {
|
||||
defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, 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
|
||||
@ -107,7 +107,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
||||
|
||||
p.client, err = createClient(p.Endpoint)
|
||||
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))
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user