diff --git a/.golangci.toml b/.golangci.toml
index 9e939601c..64e06b670 100644
--- a/.golangci.toml
+++ b/.golangci.toml
@@ -54,7 +54,10 @@
"nestif", # Too many false-positive.
"noctx", # Too strict
"exhaustive", # Too strict
- "nlreturn", # Too strict
+ "nlreturn", # Not relevant
+ "wrapcheck", # Too strict
+ "tparallel", # Not relevant
+ "exhaustivestruct", # Not relevant
]
[issues]
diff --git a/build.Dockerfile b/build.Dockerfile
index e1a0537a8..6df51c544 100644
--- a/build.Dockerfile
+++ b/build.Dockerfile
@@ -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.31.0
+RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.32.2
# 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
diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md
index 266663b8e..d71283c46 100644
--- a/docs/content/https/acme.md
+++ b/docs/content/https/acme.md
@@ -322,8 +322,9 @@ For complete details, refer to your provider's _Additional configuration_ link.
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) |
| [HyperOne](https://www.hyperone.com) | `hyperone` | `HYPERONE_PASSPORT_LOCATION`, `HYPERONE_LOCATION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/hyperone) |
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iij) |
+| [Infomaniak](https://www.infomaniak.com) | `infomaniak` | `INFOMANIAK_ACCESS_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/infomaniak) |
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/inwx) |
-| [Joker.com](https://joker.com) | `joker` | `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) |
+| [Joker.com](https://joker.com) | `joker` | `JOKER_API_MODE` with `JOKER_API_KEY` or `JOKER_USERNAME`, `JOKER_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/joker) |
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/lightsail) |
| [Linode v4](https://www.linode.com) | `linode` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
| [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) |
diff --git a/docs/content/routing/providers/ecs.md b/docs/content/routing/providers/ecs.md
index 23a6ae1a9..62feefa95 100644
--- a/docs/content/routing/providers/ecs.md
+++ b/docs/content/routing/providers/ecs.md
@@ -10,7 +10,7 @@ Attach labels to your containers and let Traefik do the rest!
!!! info "labels"
- labels are case insensitive.
- - The complete list of labels can be found [the reference page](../../reference/dynamic-configuration/ecs.md)
+ - The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/ecs.md).
### General
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index e869b5583..294170787 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -191,6 +191,7 @@ nav:
- 'Docker': 'reference/dynamic-configuration/docker.md'
- 'Kubernetes CRD': 'reference/dynamic-configuration/kubernetes-crd.md'
- 'Consul Catalog': 'reference/dynamic-configuration/consul-catalog.md'
+ - 'ECS': 'reference/dynamic-configuration/ecs.md'
+ - 'KV': 'reference/dynamic-configuration/kv.md'
- 'Marathon': 'reference/dynamic-configuration/marathon.md'
- 'Rancher': 'reference/dynamic-configuration/rancher.md'
- - 'KV': 'reference/dynamic-configuration/kv.md'
diff --git a/docs/theme/partials/company-header.html b/docs/theme/partials/company-header.html
index a32909c32..3ab683788 100644
--- a/docs/theme/partials/company-header.html
+++ b/docs/theme/partials/company-header.html
@@ -37,7 +37,7 @@
Traefik Proxy
Expose, Secure and Monitor your modern applications
diff --git a/go.mod b/go.mod
index b755aee81..8d1dfacdc 100644
--- a/go.mod
+++ b/go.mod
@@ -34,7 +34,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/v4 v4.0.1
+ github.com/go-acme/lego/v4 v4.1.0
github.com/go-check/check v0.0.0-00010101000000-000000000000
github.com/go-kit/kit v0.10.1-0.20200915143503-439c4d2ed3ea
github.com/golang/protobuf v1.4.2
@@ -72,7 +72,7 @@ require (
github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154
github.com/tinylib/msgp v1.0.2 // indirect
github.com/traefik/paerser v0.1.0
- github.com/traefik/yaegi v0.9.4
+ github.com/traefik/yaegi v0.9.5
github.com/uber/jaeger-client-go v2.25.0+incompatible
github.com/uber/jaeger-lib v2.2.0+incompatible
github.com/unrolled/render v1.0.2
diff --git a/go.sum b/go.sum
index a7469ab2d..91d54bece 100644
--- a/go.sum
+++ b/go.sum
@@ -286,8 +286,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/v4 v4.0.1 h1:vPwbTYfw5+fOaON9rWCN43iNrPw5cdJBhNMnA8oxBTM=
-github.com/go-acme/lego/v4 v4.0.1/go.mod h1:pIFm5tWkXSgiAEfJ/XQCQIvX1cEvHFwbgLZyx8OVSUE=
+github.com/go-acme/lego/v4 v4.1.0 h1:/9pMjaeaLq6m0n+io+kv2ySs2ZfrmH6eazuMoN18GHo=
+github.com/go-acme/lego/v4 v4.1.0/go.mod h1:pIFm5tWkXSgiAEfJ/XQCQIvX1cEvHFwbgLZyx8OVSUE=
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=
@@ -788,8 +788,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/traefik/paerser v0.1.0 h1:B4v1tbvd8YnHsA7spwHKEWJoGrRP+2jYpIozsCMHhl0=
github.com/traefik/paerser v0.1.0/go.mod h1:yYnAgdEC2wJH5CgG75qGWC8SsFDEapg09o9RrA6FfrE=
-github.com/traefik/yaegi v0.9.4 h1:ZyxSsvpzZTTTbvE2ODjRkOvq6kYT3dIZDqUfCZJYDtw=
-github.com/traefik/yaegi v0.9.4/go.mod h1:FAYnRlZyuVlEkvnkHq3bvJ1lW5be6XuwgLdkYgYG6Lk=
+github.com/traefik/yaegi v0.9.5 h1:mRJtmV6t/wecIq6Gfs0DpdSC2AjFpPRjoiBXP03OIz0=
+github.com/traefik/yaegi v0.9.5/go.mod h1:FAYnRlZyuVlEkvnkHq3bvJ1lW5be6XuwgLdkYgYG6Lk=
github.com/transip/gotransip/v6 v6.2.0 h1:0Z+qVsyeiQdWfcAUeJyF0IEKAPvhJwwpwPi2WGtBIiE=
github.com/transip/gotransip/v6 v6.2.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
@@ -1146,6 +1146,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
diff --git a/integration/resources/compose/pebble.yml b/integration/resources/compose/pebble.yml
index 66c358f47..1fef90abe 100644
--- a/integration/resources/compose/pebble.yml
+++ b/integration/resources/compose/pebble.yml
@@ -1,5 +1,5 @@
pebble:
- image: letsencrypt/pebble:2018-11-02
+ image: letsencrypt/pebble:v2.3.1
command: pebble --dnsserver ${DOCKER_HOST_IP}:5053
ports:
- 14000:14000
diff --git a/integration/resources/compose/proxy-protocol.yml b/integration/resources/compose/proxy-protocol.yml
index cc83205d1..7146079fb 100644
--- a/integration/resources/compose/proxy-protocol.yml
+++ b/integration/resources/compose/proxy-protocol.yml
@@ -1,5 +1,5 @@
haproxy:
- image: haproxy
+ image: haproxy:2.2
volumes:
- ../haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
diff --git a/pkg/anonymize/anonymize.go b/pkg/anonymize/anonymize.go
index 8b2191d52..00602b1fe 100644
--- a/pkg/anonymize/anonymize.go
+++ b/pkg/anonymize/anonymize.go
@@ -80,6 +80,7 @@ func doOnStruct(field reflect.Value) error {
}
}
}
+
return nil
}
@@ -107,7 +108,16 @@ func reset(field reflect.Value, name string) error {
}
case reflect.Slice:
if field.Len() > 0 {
- field.Set(reflect.MakeSlice(field.Type(), 0, 0))
+ switch field.Type().Elem().Kind() {
+ case reflect.String:
+ slice := reflect.MakeSlice(field.Type(), field.Len(), field.Len())
+ for j := 0; j < field.Len(); j++ {
+ slice.Index(j).SetString(maskShort)
+ }
+ field.Set(slice)
+ default:
+ field.Set(reflect.MakeSlice(field.Type(), 0, 0))
+ }
}
case reflect.Interface:
if !field.IsNil() {
@@ -130,7 +140,7 @@ func isExported(f reflect.StructField) bool {
func marshal(anomConfig interface{}, indent bool) ([]byte, error) {
if indent {
- return json.MarshalIndent(anomConfig, "", " ")
+ return json.MarshalIndent(anomConfig, "", " ")
}
return json.Marshal(anomConfig)
}
diff --git a/pkg/anonymize/anonymize_config_test.go b/pkg/anonymize/anonymize_config_test.go
index 826b1c7d8..cf2feb9aa 100644
--- a/pkg/anonymize/anonymize_config_test.go
+++ b/pkg/anonymize/anonymize_config_test.go
@@ -1,21 +1,39 @@
package anonymize
import (
+ "flag"
+ "io/ioutil"
"os"
+ "strings"
"testing"
"time"
assetfs "github.com/elazarl/go-bindata-assetfs"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/ping"
+ "github.com/traefik/traefik/v2/pkg/plugins"
"github.com/traefik/traefik/v2/pkg/provider/acme"
+ "github.com/traefik/traefik/v2/pkg/provider/consulcatalog"
"github.com/traefik/traefik/v2/pkg/provider/docker"
+ "github.com/traefik/traefik/v2/pkg/provider/ecs"
"github.com/traefik/traefik/v2/pkg/provider/file"
+ "github.com/traefik/traefik/v2/pkg/provider/http"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/ingress"
+ "github.com/traefik/traefik/v2/pkg/provider/kv"
+ "github.com/traefik/traefik/v2/pkg/provider/kv/consul"
+ "github.com/traefik/traefik/v2/pkg/provider/kv/etcd"
+ "github.com/traefik/traefik/v2/pkg/provider/kv/redis"
+ "github.com/traefik/traefik/v2/pkg/provider/kv/zk"
+ "github.com/traefik/traefik/v2/pkg/provider/marathon"
+ "github.com/traefik/traefik/v2/pkg/provider/rancher"
+ "github.com/traefik/traefik/v2/pkg/provider/rest"
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
"github.com/traefik/traefik/v2/pkg/tracing/datadog"
+ "github.com/traefik/traefik/v2/pkg/tracing/elastic"
"github.com/traefik/traefik/v2/pkg/tracing/haystack"
"github.com/traefik/traefik/v2/pkg/tracing/instana"
"github.com/traefik/traefik/v2/pkg/tracing/jaeger"
@@ -23,6 +41,8 @@ import (
"github.com/traefik/traefik/v2/pkg/types"
)
+var updateExpected = flag.Bool("update_expected", false, "Update expected files in fixtures")
+
func TestDo_globalConfiguration(t *testing.T) {
config := &static.Configuration{}
@@ -31,39 +51,25 @@ func TestDo_globalConfiguration(t *testing.T) {
SendAnonymousUsage: true,
}
- config.AccessLog = &types.AccessLog{
- FilePath: "AccessLog FilePath",
- Format: "AccessLog Format",
- Filters: &types.AccessLogFilters{
- StatusCodes: []string{"200", "500"},
- RetryAttempts: true,
- MinDuration: 10,
+ config.ServersTransport = &static.ServersTransport{
+ InsecureSkipVerify: true,
+ RootCAs: []traefiktls.FileOrContent{"root.ca"},
+ MaxIdleConnsPerHost: 42,
+ ForwardingTimeouts: &static.ForwardingTimeouts{
+ DialTimeout: 42,
+ ResponseHeaderTimeout: 42,
+ IdleConnTimeout: 42,
},
- Fields: &types.AccessLogFields{
- DefaultMode: "drop",
- Names: map[string]string{
- "RequestHost": "keep",
- },
- Headers: &types.FieldHeaders{
- DefaultMode: "drop",
- Names: map[string]string{
- "Referer": "keep",
- },
- },
- },
- BufferingSize: 4,
- }
-
- config.Log = &types.TraefikLog{
- Level: "Level",
- FilePath: "/foo/path",
- Format: "json",
}
config.EntryPoints = static.EntryPoints{
- "foo": {
+ "foobar": {
Address: "foo Address",
Transport: &static.EntryPointsTransport{
+ LifeCycle: &static.LifeCycle{
+ RequestAcceptGraceTimeout: ptypes.Duration(111 * time.Second),
+ GraceTimeOut: ptypes.Duration(111 * time.Second),
+ },
RespondingTimeouts: &static.RespondingTimeouts{
ReadTimeout: ptypes.Duration(111 * time.Second),
WriteTimeout: ptypes.Duration(111 * time.Second),
@@ -71,38 +77,34 @@ func TestDo_globalConfiguration(t *testing.T) {
},
},
ProxyProtocol: &static.ProxyProtocol{
+ Insecure: true,
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
},
- },
- "fii": {
- Address: "fii Address",
- Transport: &static.EntryPointsTransport{
- RespondingTimeouts: &static.RespondingTimeouts{
- ReadTimeout: ptypes.Duration(111 * time.Second),
- WriteTimeout: ptypes.Duration(111 * time.Second),
- IdleTimeout: ptypes.Duration(111 * time.Second),
+ ForwardedHeaders: &static.ForwardedHeaders{
+ Insecure: true,
+ TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
+ },
+ HTTP: static.HTTPConfig{
+ Redirections: &static.Redirections{
+ EntryPoint: &static.RedirectEntryPoint{
+ To: "foobar",
+ Scheme: "foobar",
+ Permanent: true,
+ Priority: 42,
+ },
+ },
+ Middlewares: []string{"foobar", "foobar"},
+ TLS: &static.TLSConfig{
+ Options: "foobar",
+ CertResolver: "foobar",
+ Domains: []types.Domain{
+ {Main: "foobar", SANs: []string{"foobar", "foobar"}},
+ },
},
- },
- ProxyProtocol: &static.ProxyProtocol{
- TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
- },
- },
- }
- config.CertificatesResolvers = map[string]static.CertificateResolver{
- "default": {
- ACME: &acme.Configuration{
- Email: "acme Email",
- CAServer: "CAServer",
- Storage: "Storage",
- KeyType: "MyKeyType",
- DNSChallenge: &acme.DNSChallenge{Provider: "DNSProvider"},
- HTTPChallenge: &acme.HTTPChallenge{
- EntryPoint: "MyEntryPoint",
- },
- TLSChallenge: &acme.TLSChallenge{},
},
},
}
+
config.Providers = &static.Providers{
ProvidersThrottleDuration: ptypes.Duration(111 * time.Second),
}
@@ -114,22 +116,7 @@ func TestDo_globalConfiguration(t *testing.T) {
ForwardingTimeouts: &static.ForwardingTimeouts{
DialTimeout: ptypes.Duration(111 * time.Second),
ResponseHeaderTimeout: ptypes.Duration(111 * time.Second),
- },
- }
-
- config.API = &static.API{
- Dashboard: true,
- DashboardAssets: &assetfs.AssetFS{
- Asset: func(path string) ([]byte, error) {
- return nil, nil
- },
- AssetDir: func(path string) ([]string, error) {
- return nil, nil
- },
- AssetInfo: func(path string) (os.FileInfo, error) {
- return nil, nil
- },
- Prefix: "fii",
+ IdleConnTimeout: ptypes.Duration(111 * time.Second),
},
}
@@ -160,6 +147,33 @@ func TestDo_globalConfiguration(t *testing.T) {
HTTPClientTimeout: 42,
}
+ config.Providers.Marathon = &marathon.Provider{
+ Constraints: `Label("foo", "bar")`,
+ Trace: true,
+ Watch: true,
+ Endpoint: "foobar",
+ DefaultRule: "PathPrefix(`/`)",
+ ExposedByDefault: true,
+ DCOSToken: "foobar",
+ TLS: &types.ClientTLS{
+ CA: "myCa",
+ CAOptional: true,
+ Cert: "mycert.pem",
+ Key: "mycert.key",
+ InsecureSkipVerify: true,
+ },
+ DialerTimeout: 42,
+ ResponseHeaderTimeout: 42,
+ TLSHandshakeTimeout: 42,
+ KeepAlive: 42,
+ ForceTaskHostname: true,
+ Basic: &marathon.Basic{
+ HTTPBasicAuthUser: "user",
+ HTTPBasicPassword: "password",
+ },
+ RespectReadinessChecks: true,
+ }
+
config.Providers.KubernetesIngress = &ingress.Provider{
Endpoint: "MyEndpoint",
Token: "MyToken",
@@ -168,6 +182,12 @@ func TestDo_globalConfiguration(t *testing.T) {
Namespaces: []string{"a", "b"},
LabelSelector: "myLabelSelector",
IngressClass: "MyIngressClass",
+ IngressEndpoint: &ingress.EndpointIngress{
+ IP: "IP",
+ Hostname: "Hostname",
+ PublishedService: "PublishedService",
+ },
+ ThrottleDuration: ptypes.Duration(111 * time.Second),
}
config.Providers.KubernetesCRD = &crd.Provider{
@@ -178,83 +198,343 @@ func TestDo_globalConfiguration(t *testing.T) {
Namespaces: []string{"a", "b"},
LabelSelector: "myLabelSelector",
IngressClass: "MyIngressClass",
+ ThrottleDuration: ptypes.Duration(111 * time.Second),
}
- // FIXME Test the other providers once they are migrated
+ config.Providers.Rest = &rest.Provider{
+ Insecure: true,
+ }
+
+ config.Providers.Rancher = &rancher.Provider{
+ Constraints: `Label("foo", "bar")`,
+ Watch: true,
+ DefaultRule: "PathPrefix(`/`)",
+ ExposedByDefault: true,
+ EnableServiceHealthFilter: true,
+ RefreshSeconds: 42,
+ IntervalPoll: true,
+ Prefix: "MyPrefix",
+ }
+
+ config.Providers.ConsulCatalog = &consulcatalog.Provider{
+ Constraints: `Label("foo", "bar")`,
+ Endpoint: &consulcatalog.EndpointConfig{
+ Address: "MyAddress",
+ Scheme: "MyScheme",
+ DataCenter: "MyDatacenter",
+ Token: "MyToken",
+ TLS: &types.ClientTLS{
+ CA: "myCa",
+ CAOptional: true,
+ Cert: "mycert.pem",
+ Key: "mycert.key",
+ InsecureSkipVerify: true,
+ },
+ HTTPAuth: &consulcatalog.EndpointHTTPAuthConfig{
+ Username: "MyUsername",
+ Password: "MyPassword",
+ },
+ EndpointWaitTime: 42,
+ },
+ Prefix: "MyPrefix",
+ RefreshInterval: 42,
+ RequireConsistent: true,
+ Stale: true,
+ Cache: true,
+ ExposedByDefault: true,
+ DefaultRule: "PathPrefix(`/`)",
+ }
+
+ config.Providers.Ecs = &ecs.Provider{
+ Constraints: `Label("foo", "bar")`,
+ ExposedByDefault: true,
+ RefreshSeconds: 42,
+ DefaultRule: "PathPrefix(`/`)",
+ Clusters: []string{"Cluster1", "Cluster2"},
+ AutoDiscoverClusters: true,
+ Region: "Awsregion",
+ AccessKeyID: "AwsAccessKeyID",
+ SecretAccessKey: "AwsSecretAccessKey",
+ }
+
+ config.Providers.Consul = &consul.Provider{
+ Provider: kv.Provider{
+ RootKey: "RootKey",
+ Endpoints: nil,
+ Username: "username",
+ Password: "password",
+ TLS: &types.ClientTLS{
+ CA: "myCa",
+ CAOptional: true,
+ Cert: "mycert.pem",
+ Key: "mycert.key",
+ InsecureSkipVerify: true,
+ },
+ },
+ }
+
+ config.Providers.Etcd = &etcd.Provider{
+ Provider: kv.Provider{
+ RootKey: "RootKey",
+ Endpoints: nil,
+ Username: "username",
+ Password: "password",
+ TLS: &types.ClientTLS{
+ CA: "myCa",
+ CAOptional: true,
+ Cert: "mycert.pem",
+ Key: "mycert.key",
+ InsecureSkipVerify: true,
+ },
+ },
+ }
+
+ config.Providers.ZooKeeper = &zk.Provider{
+ Provider: kv.Provider{
+ RootKey: "RootKey",
+ Endpoints: nil,
+ Username: "username",
+ Password: "password",
+ TLS: &types.ClientTLS{
+ CA: "myCa",
+ CAOptional: true,
+ Cert: "mycert.pem",
+ Key: "mycert.key",
+ InsecureSkipVerify: true,
+ },
+ },
+ }
+
+ config.Providers.Redis = &redis.Provider{
+ Provider: kv.Provider{
+ RootKey: "RootKey",
+ Endpoints: nil,
+ Username: "username",
+ Password: "password",
+ TLS: &types.ClientTLS{
+ CA: "myCa",
+ CAOptional: true,
+ Cert: "mycert.pem",
+ Key: "mycert.key",
+ InsecureSkipVerify: true,
+ },
+ },
+ }
+
+ config.Providers.HTTP = &http.Provider{
+ Endpoint: "Myenpoint",
+ PollInterval: 42,
+ PollTimeout: 42,
+ TLS: &types.ClientTLS{
+ CA: "myCa",
+ CAOptional: true,
+ Cert: "mycert.pem",
+ Key: "mycert.key",
+ InsecureSkipVerify: true,
+ },
+ }
+
+ config.API = &static.API{
+ Insecure: true,
+ Dashboard: true,
+ Debug: true,
+ DashboardAssets: &assetfs.AssetFS{
+ Asset: func(path string) ([]byte, error) {
+ return nil, nil
+ },
+ AssetDir: func(path string) ([]string, error) {
+ return nil, nil
+ },
+ AssetInfo: func(path string) (os.FileInfo, error) {
+ return nil, nil
+ },
+ Prefix: "fii",
+ },
+ }
config.Metrics = &types.Metrics{
Prometheus: &types.Prometheus{
- Buckets: []float64{0.1, 0.3, 1.2, 5},
+ Buckets: []float64{0.1, 0.3, 1.2, 5},
+ AddEntryPointsLabels: true,
+ AddServicesLabels: true,
+ EntryPoint: "MyEntryPoint",
+ ManualRouting: true,
},
Datadog: &types.Datadog{
- Address: "localhost:8181",
- PushInterval: 12,
+ Address: "localhost:8181",
+ PushInterval: 42,
+ AddEntryPointsLabels: true,
+ AddServicesLabels: true,
},
StatsD: &types.Statsd{
- Address: "localhost:8182",
- PushInterval: 42,
+ Address: "localhost:8182",
+ PushInterval: 42,
+ AddEntryPointsLabels: true,
+ AddServicesLabels: true,
+ Prefix: "MyPrefix",
},
InfluxDB: &types.InfluxDB{
- Address: "localhost:8183",
- Protocol: "http",
- PushInterval: 22,
- Database: "myDB",
- RetentionPolicy: "12",
- Username: "a",
- Password: "aaaa",
+ Address: "localhost:8183",
+ Protocol: "http",
+ PushInterval: 42,
+ Database: "myDB",
+ RetentionPolicy: "12",
+ Username: "a",
+ Password: "aaaa",
+ AddEntryPointsLabels: true,
+ AddServicesLabels: true,
},
}
- config.Ping = &ping.Handler{}
+ config.Ping = &ping.Handler{
+ EntryPoint: "MyEntryPoint",
+ ManualRouting: true,
+ TerminatingStatusCode: 42,
+ }
+
+ config.Log = &types.TraefikLog{
+ Level: "Level",
+ FilePath: "/foo/path",
+ Format: "json",
+ }
+
+ config.AccessLog = &types.AccessLog{
+ FilePath: "AccessLog FilePath",
+ Format: "AccessLog Format",
+ Filters: &types.AccessLogFilters{
+ StatusCodes: []string{"200", "500"},
+ RetryAttempts: true,
+ MinDuration: 42,
+ },
+ Fields: &types.AccessLogFields{
+ DefaultMode: "drop",
+ Names: map[string]string{
+ "RequestHost": "keep",
+ },
+ Headers: &types.FieldHeaders{
+ DefaultMode: "drop",
+ Names: map[string]string{
+ "Referer": "keep",
+ },
+ },
+ },
+ BufferingSize: 42,
+ }
config.Tracing = &static.Tracing{
ServiceName: "myServiceName",
- SpanNameLimit: 3,
+ SpanNameLimit: 42,
Jaeger: &jaeger.Config{
- SamplingServerURL: "aaa",
- SamplingType: "bbb",
- SamplingParam: 43,
- LocalAgentHostPort: "ccc",
+ SamplingServerURL: "foobar",
+ SamplingType: "foobar",
+ SamplingParam: 42,
+ LocalAgentHostPort: "foobar",
Gen128Bit: true,
- Propagation: "ddd",
- TraceContextHeaderName: "eee",
+ Propagation: "foobar",
+ TraceContextHeaderName: "foobar",
+ Collector: &jaeger.Collector{
+ Endpoint: "foobar",
+ User: "foobar",
+ Password: "foobar",
+ },
+ DisableAttemptReconnecting: true,
},
Zipkin: &zipkin.Config{
- HTTPEndpoint: "fff",
+ HTTPEndpoint: "foobar",
SameSpan: true,
ID128Bit: true,
- SampleRate: 53,
+ SampleRate: 42,
},
Datadog: &datadog.Config{
- LocalAgentHostPort: "ggg",
- GlobalTag: "eee",
- Debug: true,
- PrioritySampling: true,
+ LocalAgentHostPort: "foobar",
+ GlobalTag: "foobar",
+ Debug: true,
+ PrioritySampling: true,
+ TraceIDHeaderName: "foobar",
+ ParentIDHeaderName: "foobar",
+ SamplingPriorityHeaderName: "foobar",
+ BagagePrefixHeaderName: "foobar",
},
Instana: &instana.Config{
- LocalAgentHost: "fff",
- LocalAgentPort: 32,
- LogLevel: "ggg",
+ LocalAgentHost: "foobar",
+ LocalAgentPort: 4242,
+ LogLevel: "foobar",
},
Haystack: &haystack.Config{
- LocalAgentHost: "fff",
- LocalAgentPort: 32,
- GlobalTag: "eee",
- TraceIDHeaderName: "fff",
- ParentIDHeaderName: "ggg",
- SpanIDHeaderName: "hhh",
- BaggagePrefixHeaderName: "iii",
+ LocalAgentHost: "foobar",
+ LocalAgentPort: 42,
+ GlobalTag: "foobar",
+ TraceIDHeaderName: "foobar",
+ ParentIDHeaderName: "foobar",
+ SpanIDHeaderName: "foobar",
+ BaggagePrefixHeaderName: "foobar",
+ },
+ Elastic: &elastic.Config{
+ ServerURL: "foobar",
+ SecretToken: "foobar",
+ ServiceEnvironment: "foobar",
},
}
config.HostResolver = &types.HostResolverConfig{
CnameFlattening: true,
- ResolvConfig: "aaa",
- ResolvDepth: 3,
+ ResolvConfig: "foobar",
+ ResolvDepth: 42,
}
- cleanJSON, err := Do(config, true)
- if err != nil {
- t.Fatal(err, cleanJSON)
+ config.CertificatesResolvers = map[string]static.CertificateResolver{
+ "CertificateResolver0": {
+ ACME: &acme.Configuration{
+ Email: "acme Email",
+ CAServer: "CAServer",
+ PreferredChain: "foobar",
+ Storage: "Storage",
+ KeyType: "MyKeyType",
+ DNSChallenge: &acme.DNSChallenge{
+ Provider: "DNSProvider",
+ DelayBeforeCheck: 42,
+ Resolvers: []string{"resolver1", "resolver2"},
+ DisablePropagationCheck: true,
+ },
+ HTTPChallenge: &acme.HTTPChallenge{
+ EntryPoint: "MyEntryPoint",
+ },
+ TLSChallenge: &acme.TLSChallenge{},
+ },
+ },
}
+
+ config.Pilot = &static.Pilot{
+ Token: "token",
+ }
+
+ config.Experimental = &static.Experimental{
+ Plugins: map[string]plugins.Descriptor{
+ "Descriptor0": {
+ ModuleName: "foobar",
+ Version: "foobar",
+ },
+ "Descriptor1": {
+ ModuleName: "foobar",
+ Version: "foobar",
+ },
+ },
+ DevPlugin: &plugins.DevPlugin{
+ GoPath: "foobar",
+ ModuleName: "foobar",
+ },
+ }
+
+ expectedConfiguration, err := ioutil.ReadFile("./testdata/anonymized-static-config.json")
+ require.NoError(t, err)
+
+ cleanJSON, err := Do(config, true)
+ require.NoError(t, err)
+
+ if *updateExpected {
+ require.NoError(t, ioutil.WriteFile("testdata/anonymized-static-config.json", []byte(cleanJSON), 0666))
+ }
+
+ expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
+ assert.Equal(t, expected, cleanJSON)
}
diff --git a/pkg/anonymize/anonymize_doOnJSON_test.go b/pkg/anonymize/anonymize_doOnJSON_test.go
index a005b8170..1ff7b9d4b 100644
--- a/pkg/anonymize/anonymize_doOnJSON_test.go
+++ b/pkg/anonymize/anonymize_doOnJSON_test.go
@@ -1,185 +1,23 @@
package anonymize
import (
+ "io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func Test_doOnJSON(t *testing.T) {
- baseConfiguration := `
-{
- "GraceTimeOut": 10000000000,
- "Debug": false,
- "CheckNewVersion": true,
- "AccessLogsFile": "",
- "TraefikLogsFile": "",
- "Level": "ERROR",
- "EntryPoints": {
- "http": {
- "Network": "",
- "Address": ":80",
- "TLS": null,
- "Auth": null,
- "Compress": false
- },
- "https": {
- "Address": ":443",
- "TLS": {
- "MinVersion": "",
- "CipherSuites": null,
- "Certificates": null,
- "ClientCAFiles": null
- },
- "Auth": null,
- "Compress": false
- }
- },
- "Cluster": null,
- "Constraints": [],
- "ACME": {
- "Email": "foo@bar.com",
- "Domains": [
- {
- "Main": "foo@bar.com",
- "SANs": null
- },
- {
- "Main": "foo@bar.com",
- "SANs": null
- }
- ],
- "Storage": "",
- "StorageFile": "/acme/acme.json",
- "OnDemand": true,
- "OnHostRule": true,
- "CAServer": "",
- "EntryPoint": "https",
- "DNSProvider": "",
- "DelayDontCheckDNS": 0,
- "ACMELogging": false,
- "Options": null
- },
- "DefaultEntryPoints": [
- "https",
- "http"
- ],
- "ProvidersThrottleDuration": 2000000000,
- "MaxIdleConnsPerHost": 200,
- "IdleTimeout": 180000000000,
- "InsecureSkipVerify": false,
- "Retry": null,
- "HealthCheck": {
- "Interval": 30000000000
- },
- "Docker": null,
- "File": null,
- "Web": null,
- "Marathon": null,
- "Consul": null,
- "ConsulCatalog": null,
- "Etcd": null,
- "Zookeeper": null,
- "Boltdb": null,
- "KubernetesIngress": null,
- "KubernetesCRD": null,
- "Mesos": null,
- "Eureka": null,
- "ECS": null,
- "Rancher": null,
- "DynamoDB": null,
- "ConfigFile": "/etc/traefik/traefik.toml"
-}
-`
- expectedConfiguration := `
-{
- "GraceTimeOut": 10000000000,
- "Debug": false,
- "CheckNewVersion": true,
- "AccessLogsFile": "",
- "TraefikLogsFile": "",
- "Level": "ERROR",
- "EntryPoints": {
- "http": {
- "Network": "",
- "Address": ":80",
- "TLS": null,
- "Auth": null,
- "Compress": false
- },
- "https": {
- "Address": ":443",
- "TLS": {
- "MinVersion": "",
- "CipherSuites": null,
- "Certificates": null,
- "ClientCAFiles": null
- },
- "Auth": null,
- "Compress": false
- }
- },
- "Cluster": null,
- "Constraints": [],
- "ACME": {
- "Email": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
- "Domains": [
- {
- "Main": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
- "SANs": null
- },
- {
- "Main": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
- "SANs": null
- }
- ],
- "Storage": "",
- "StorageFile": "/acme/acme.json",
- "OnDemand": true,
- "OnHostRule": true,
- "CAServer": "",
- "EntryPoint": "https",
- "DNSProvider": "",
- "DelayDontCheckDNS": 0,
- "ACMELogging": false,
- "Options": null
- },
- "DefaultEntryPoints": [
- "https",
- "http"
- ],
- "ProvidersThrottleDuration": 2000000000,
- "MaxIdleConnsPerHost": 200,
- "IdleTimeout": 180000000000,
- "InsecureSkipVerify": false,
- "Retry": null,
- "HealthCheck": {
- "Interval": 30000000000
- },
- "Docker": null,
- "File": null,
- "Web": null,
- "Marathon": null,
- "Consul": null,
- "ConsulCatalog": null,
- "Etcd": null,
- "Zookeeper": null,
- "Boltdb": null,
- "KubernetesIngress": null,
- "KubernetesCRD": null,
- "Mesos": null,
- "Eureka": null,
- "ECS": null,
- "Rancher": null,
- "DynamoDB": null,
- "ConfigFile": "/etc/traefik/traefik.toml"
-}
-`
- anomConfiguration := doOnJSON(baseConfiguration)
+ baseConfiguration, err := ioutil.ReadFile("./testdata/example.json")
+ require.NoError(t, err)
- if anomConfiguration != expectedConfiguration {
- t.Errorf("Got %s, want %s.", anomConfiguration, expectedConfiguration)
- }
+ anomConfiguration := doOnJSON(string(baseConfiguration))
+
+ expectedConfiguration, err := ioutil.ReadFile("./testdata/expected.json")
+ require.NoError(t, err)
+
+ assert.JSONEq(t, string(expectedConfiguration), anomConfiguration)
}
func Test_doOnJSON_simple(t *testing.T) {
diff --git a/pkg/anonymize/anonymize_doOnStruct_test.go b/pkg/anonymize/anonymize_doOnStruct_test.go
index 676f3bfa3..19f1089e6 100644
--- a/pkg/anonymize/anonymize_doOnStruct_test.go
+++ b/pkg/anonymize/anonymize_doOnStruct_test.go
@@ -20,6 +20,8 @@ type Tomate struct {
type Carotte struct {
Name string
Value int
+ List []string
+ EList []string `export:"true"`
Courgette Courgette
ECourgette Courgette `export:"true"`
Pourgette *Courgette
@@ -44,9 +46,13 @@ func Test_doOnStruct(t *testing.T) {
base: &Carotte{
Name: "koko",
Value: 666,
+ List: []string{"test"},
+ EList: []string{"test"},
},
expected: &Carotte{
- Name: "xxxx",
+ Name: "xxxx",
+ List: []string{"xxxx"},
+ EList: []string{"test"},
},
},
{
diff --git a/pkg/anonymize/testdata/anonymized-static-config.json b/pkg/anonymize/testdata/anonymized-static-config.json
new file mode 100644
index 000000000..adc729042
--- /dev/null
+++ b/pkg/anonymize/testdata/anonymized-static-config.json
@@ -0,0 +1,455 @@
+{
+ "global": {
+ "checkNewVersion": true,
+ "sendAnonymousUsage": true
+ },
+ "serversTransport": {
+ "insecureSkipVerify": true,
+ "rootCAs": [
+ "xxxx",
+ "xxxx",
+ "xxxx"
+ ],
+ "maxIdleConnsPerHost": 111,
+ "forwardingTimeouts": {
+ "dialTimeout": 111000000000,
+ "responseHeaderTimeout": 111000000000,
+ "idleConnTimeout": 111000000000
+ }
+ },
+ "entryPoints": {
+ "foobar": {
+ "address": "xxxx",
+ "transport": {
+ "lifeCycle": {
+ "requestAcceptGraceTimeout": 111000000000,
+ "graceTimeOut": 111000000000
+ },
+ "respondingTimeouts": {
+ "readTimeout": 111000000000,
+ "writeTimeout": 111000000000,
+ "idleTimeout": 111000000000
+ }
+ },
+ "proxyProtocol": {
+ "insecure": true,
+ "trustedIPs": [
+ "xxxx",
+ "xxxx"
+ ]
+ },
+ "forwardedHeaders": {
+ "insecure": true,
+ "trustedIPs": [
+ "xxxx",
+ "xxxx"
+ ]
+ },
+ "http": {
+ "redirections": {
+ "entryPoint": {
+ "to": "foobar",
+ "scheme": "foobar",
+ "permanent": true,
+ "priority": 42
+ }
+ },
+ "middlewares": [
+ "foobar",
+ "foobar"
+ ],
+ "tls": {
+ "options": "foobar",
+ "certResolver": "foobar",
+ "domains": [
+ {
+ "main": "xxxx",
+ "sans": [
+ "xxxx",
+ "xxxx"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ },
+ "providers": {
+ "providersThrottleDuration": 111000000000,
+ "docker": {
+ "constraints": "Label(\"foo\", \"bar\")",
+ "watch": true,
+ "endpoint": "xxxx",
+ "defaultRule": "xxxx",
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ },
+ "exposedByDefault": true,
+ "useBindPortIP": true,
+ "swarmMode": true,
+ "network": "MyNetwork",
+ "swarmModeRefreshSeconds": 42,
+ "httpClientTimeout": 42
+ },
+ "file": {
+ "directory": "file Directory",
+ "watch": true,
+ "filename": "file Filename",
+ "debugLogGeneratedTemplate": true
+ },
+ "marathon": {
+ "constraints": "Label(\"foo\", \"bar\")",
+ "trace": true,
+ "watch": true,
+ "endpoint": "xxxx",
+ "defaultRule": "xxxx",
+ "exposedByDefault": true,
+ "dcosToken": "xxxx",
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ },
+ "dialerTimeout": 42,
+ "responseHeaderTimeout": 42,
+ "tlsHandshakeTimeout": 42,
+ "keepAlive": 42,
+ "forceTaskHostname": true,
+ "basic": {
+ "httpBasicAuthUser": "xxxx",
+ "httpBasicPassword": "xxxx"
+ },
+ "respectReadinessChecks": true
+ },
+ "kubernetesIngress": {
+ "endpoint": "xxxx",
+ "token": "xxxx",
+ "certAuthFilePath": "xxxx",
+ "disablePassHostHeaders": true,
+ "namespaces": [
+ "a",
+ "b"
+ ],
+ "labelSelector": "myLabelSelector",
+ "ingressClass": "MyIngressClass",
+ "ingressEndpoint": {
+ "ip": "xxxx",
+ "hostname": "xxxx",
+ "publishedService": "xxxx"
+ },
+ "throttleDuration": 111000000000
+ },
+ "kubernetesCRD": {
+ "endpoint": "xxxx",
+ "token": "xxxx",
+ "certAuthFilePath": "xxxx",
+ "disablePassHostHeaders": true,
+ "namespaces": [
+ "a",
+ "b"
+ ],
+ "labelSelector": "myLabelSelector",
+ "ingressClass": "MyIngressClass",
+ "throttleDuration": 111000000000
+ },
+ "rest": {
+ "insecure": true
+ },
+ "rancher": {
+ "constraints": "Label(\"foo\", \"bar\")",
+ "watch": true,
+ "defaultRule": "xxxx",
+ "exposedByDefault": true,
+ "enableServiceHealthFilter": true,
+ "refreshSeconds": 42,
+ "intervalPoll": true,
+ "prefix": "xxxx"
+ },
+ "consulCatalog": {
+ "constraints": "Label(\"foo\", \"bar\")",
+ "endpoint": {
+ "address": "xxxx",
+ "scheme": "xxxx",
+ "datacenter": "xxxx",
+ "token": "xxxx",
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ },
+ "httpAuth": {
+ "username": "xxxx",
+ "password": "xxxx"
+ },
+ "endpointWaitTime": 42
+ },
+ "prefix": "MyPrefix",
+ "refreshInterval": 42,
+ "requireConsistent": true,
+ "stale": true,
+ "cache": true,
+ "exposedByDefault": true,
+ "defaultRule": "xxxx"
+ },
+ "ecs": {
+ "constraints": "Label(\"foo\", \"bar\")",
+ "exposedByDefault": true,
+ "refreshSeconds": 42,
+ "defaultRule": "xxxx",
+ "clusters": [
+ "Cluster1",
+ "Cluster2"
+ ],
+ "autoDiscoverClusters": true,
+ "region": "Awsregion",
+ "accessKeyID": "xxxx",
+ "secretAccessKey": "xxxx"
+ },
+ "consul": {
+ "rootKey": "RootKey",
+ "username": "xxxx",
+ "password": "xxxx",
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ }
+ },
+ "etcd": {
+ "rootKey": "RootKey",
+ "username": "xxxx",
+ "password": "xxxx",
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ }
+ },
+ "zooKeeper": {
+ "rootKey": "RootKey",
+ "username": "xxxx",
+ "password": "xxxx",
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ }
+ },
+ "redis": {
+ "rootKey": "RootKey",
+ "username": "xxxx",
+ "password": "xxxx",
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ }
+ },
+ "http": {
+ "endpoint": "xxxx",
+ "pollInterval": 42,
+ "pollTimeout": 42,
+ "tls": {
+ "ca": "xxxx",
+ "caOptional": true,
+ "cert": "xxxx",
+ "key": "xxxx",
+ "insecureSkipVerify": true
+ }
+ }
+ },
+ "api": {
+ "insecure": true,
+ "dashboard": true,
+ "debug": true
+ },
+ "metrics": {
+ "prometheus": {
+ "buckets": [
+ 0.1,
+ 0.3,
+ 1.2,
+ 5
+ ],
+ "addEntryPointsLabels": true,
+ "addServicesLabels": true,
+ "entryPoint": "MyEntryPoint",
+ "manualRouting": true
+ },
+ "datadog": {
+ "address": "xxxx",
+ "pushInterval": 42,
+ "addEntryPointsLabels": true,
+ "addServicesLabels": true
+ },
+ "statsD": {
+ "address": "xxxx",
+ "pushInterval": 42,
+ "addEntryPointsLabels": true,
+ "addServicesLabels": true,
+ "prefix": "MyPrefix"
+ },
+ "influxDB": {
+ "address": "xxxx",
+ "protocol": "xxxx",
+ "pushInterval": 42,
+ "database": "myDB",
+ "retentionPolicy": "12",
+ "username": "xxxx",
+ "password": "xxxx",
+ "addEntryPointsLabels": true,
+ "addServicesLabels": true
+ }
+ },
+ "ping": {
+ "entryPoint": "MyEntryPoint",
+ "manualRouting": true,
+ "terminatingStatusCode": 42
+ },
+ "log": {
+ "level": "Level",
+ "filePath": "xxxx",
+ "format": "json"
+ },
+ "accessLog": {
+ "filePath": "xxxx",
+ "format": "AccessLog Format",
+ "filters": {
+ "statusCodes": [
+ "200",
+ "500"
+ ],
+ "retryAttempts": true,
+ "minDuration": 42
+ },
+ "fields": {
+ "defaultMode": "drop",
+ "names": {
+ "RequestHost": "keep"
+ },
+ "headers": {
+ "defaultMode": "drop",
+ "names": {
+ "Referer": "keep"
+ }
+ }
+ },
+ "bufferingSize": 42
+ },
+ "tracing": {
+ "serviceName": "myServiceName",
+ "spanNameLimit": 42,
+ "jaeger": {
+ "samplingServerURL": "xxxx",
+ "samplingType": "foobar",
+ "samplingParam": 42,
+ "localAgentHostPort": "xxxx",
+ "gen128Bit": true,
+ "propagation": "foobar",
+ "traceContextHeaderName": "foobar",
+ "collector": {
+ "endpoint": "xxxx",
+ "user": "xxxx",
+ "password": "xxxx"
+ },
+ "disableAttemptReconnecting": true
+ },
+ "zipkin": {
+ "httpEndpoint": "xxxx",
+ "sameSpan": true,
+ "id128Bit": true,
+ "sampleRate": 42
+ },
+ "datadog": {
+ "localAgentHostPort": "xxxx",
+ "globalTag": "foobar",
+ "debug": true,
+ "prioritySampling": true,
+ "traceIDHeaderName": "foobar",
+ "parentIDHeaderName": "foobar",
+ "samplingPriorityHeaderName": "foobar",
+ "bagagePrefixHeaderName": "foobar"
+ },
+ "instana": {
+ "localAgentHost": "xxxx",
+ "logLevel": "foobar"
+ },
+ "haystack": {
+ "localAgentHost": "xxxx",
+ "globalTag": "foobar",
+ "traceIDHeaderName": "foobar",
+ "parentIDHeaderName": "foobar",
+ "spanIDHeaderName": "foobar",
+ "baggagePrefixHeaderName": "foobar"
+ },
+ "elastic": {
+ "serverURL": "xxxx",
+ "secretToken": "xxxx",
+ "serviceEnvironment": "foobar"
+ }
+ },
+ "hostResolver": {
+ "cnameFlattening": true,
+ "resolvConfig": "foobar",
+ "resolvDepth": 42
+ },
+ "certificatesResolvers": {
+ "CertificateResolver0": {
+ "acme": {
+ "email": "xxxx",
+ "caServer": "xxxx",
+ "preferredChain": "foobar",
+ "storage": "Storage",
+ "keyType": "MyKeyType",
+ "dnsChallenge": {
+ "provider": "DNSProvider",
+ "delayBeforeCheck": 42,
+ "resolvers": [
+ "xxxx",
+ "xxxx"
+ ],
+ "disablePropagationCheck": true
+ },
+ "httpChallenge": {
+ "entryPoint": "MyEntryPoint"
+ },
+ "tlsChallenge": {}
+ }
+ }
+ },
+ "pilot": {
+ "token": "xxxx"
+ },
+ "experimental": {
+ "plugins": {
+ "Descriptor0": {
+ "moduleName": "foobar",
+ "version": "foobar"
+ },
+ "Descriptor1": {
+ "moduleName": "foobar",
+ "version": "foobar"
+ }
+ },
+ "devPlugin": {
+ "goPath": "foobar",
+ "moduleName": "foobar"
+ }
+ }
+}
\ No newline at end of file
diff --git a/pkg/anonymize/testdata/example.json b/pkg/anonymize/testdata/example.json
new file mode 100644
index 000000000..0d12d63d9
--- /dev/null
+++ b/pkg/anonymize/testdata/example.json
@@ -0,0 +1,82 @@
+{
+ "GraceTimeOut": 10000000000,
+ "Debug": false,
+ "CheckNewVersion": true,
+ "AccessLogsFile": "",
+ "TraefikLogsFile": "",
+ "Level": "ERROR",
+ "EntryPoints": {
+ "http": {
+ "Network": "",
+ "Address": ":80",
+ "TLS": null,
+ "Auth": null,
+ "Compress": false
+ },
+ "https": {
+ "Address": ":443",
+ "TLS": {
+ "MinVersion": "",
+ "CipherSuites": null,
+ "Certificates": null,
+ "ClientCAFiles": null
+ },
+ "Auth": null,
+ "Compress": false
+ }
+ },
+ "Cluster": null,
+ "Constraints": [],
+ "ACME": {
+ "Email": "foo@bar.com",
+ "Domains": [
+ {
+ "Main": "foo@bar.com",
+ "SANs": null
+ },
+ {
+ "Main": "foo@bar.com",
+ "SANs": null
+ }
+ ],
+ "Storage": "",
+ "StorageFile": "/acme/acme.json",
+ "OnDemand": true,
+ "OnHostRule": true,
+ "CAServer": "",
+ "EntryPoint": "https",
+ "DNSProvider": "",
+ "DelayDontCheckDNS": 0,
+ "ACMELogging": false,
+ "Options": null
+ },
+ "DefaultEntryPoints": [
+ "https",
+ "http"
+ ],
+ "ProvidersThrottleDuration": 2000000000,
+ "MaxIdleConnsPerHost": 200,
+ "IdleTimeout": 180000000000,
+ "InsecureSkipVerify": false,
+ "Retry": null,
+ "HealthCheck": {
+ "Interval": 30000000000
+ },
+ "Docker": null,
+ "File": null,
+ "Web": null,
+ "Marathon": null,
+ "Consul": null,
+ "ConsulCatalog": null,
+ "Etcd": null,
+ "Zookeeper": null,
+ "Boltdb": null,
+ "KubernetesIngress": null,
+ "KubernetesCRD": null,
+ "Mesos": null,
+ "Eureka": null,
+ "ECS": null,
+ "Rancher": null,
+ "DynamoDB": null,
+ "ConfigFile": "/etc/traefik/traefik.toml"
+}
diff --git a/pkg/anonymize/testdata/expected.json b/pkg/anonymize/testdata/expected.json
new file mode 100644
index 000000000..7319a7f1a
--- /dev/null
+++ b/pkg/anonymize/testdata/expected.json
@@ -0,0 +1,82 @@
+{
+ "GraceTimeOut": 10000000000,
+ "Debug": false,
+ "CheckNewVersion": true,
+ "AccessLogsFile": "",
+ "TraefikLogsFile": "",
+ "Level": "ERROR",
+ "EntryPoints": {
+ "http": {
+ "Network": "",
+ "Address": ":80",
+ "TLS": null,
+ "Auth": null,
+ "Compress": false
+ },
+ "https": {
+ "Address": ":443",
+ "TLS": {
+ "MinVersion": "",
+ "CipherSuites": null,
+ "Certificates": null,
+ "ClientCAFiles": null
+ },
+ "Auth": null,
+ "Compress": false
+ }
+ },
+ "Cluster": null,
+ "Constraints": [],
+ "ACME": {
+ "Email": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "Domains": [
+ {
+ "Main": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "SANs": null
+ },
+ {
+ "Main": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "SANs": null
+ }
+ ],
+ "Storage": "",
+ "StorageFile": "/acme/acme.json",
+ "OnDemand": true,
+ "OnHostRule": true,
+ "CAServer": "",
+ "EntryPoint": "https",
+ "DNSProvider": "",
+ "DelayDontCheckDNS": 0,
+ "ACMELogging": false,
+ "Options": null
+ },
+ "DefaultEntryPoints": [
+ "https",
+ "http"
+ ],
+ "ProvidersThrottleDuration": 2000000000,
+ "MaxIdleConnsPerHost": 200,
+ "IdleTimeout": 180000000000,
+ "InsecureSkipVerify": false,
+ "Retry": null,
+ "HealthCheck": {
+ "Interval": 30000000000
+ },
+ "Docker": null,
+ "File": null,
+ "Web": null,
+ "Marathon": null,
+ "Consul": null,
+ "ConsulCatalog": null,
+ "Etcd": null,
+ "Zookeeper": null,
+ "Boltdb": null,
+ "KubernetesIngress": null,
+ "KubernetesCRD": null,
+ "Mesos": null,
+ "Eureka": null,
+ "ECS": null,
+ "Rancher": null,
+ "DynamoDB": null,
+ "ConfigFile": "/etc/traefik/traefik.toml"
+}
diff --git a/pkg/config/static/entrypoints.go b/pkg/config/static/entrypoints.go
index 20d67c5f8..f55bfc3dc 100644
--- a/pkg/config/static/entrypoints.go
+++ b/pkg/config/static/entrypoints.go
@@ -11,10 +11,10 @@ import (
// EntryPoint holds the entry point configuration.
type EntryPoint struct {
Address string `description:"Entry point address." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
- Transport *EntryPointsTransport `description:"Configures communication between clients and Traefik." json:"transport,omitempty" toml:"transport,omitempty" yaml:"transport,omitempty"`
- ProxyProtocol *ProxyProtocol `description:"Proxy-Protocol configuration." json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty"`
- ForwardedHeaders *ForwardedHeaders `description:"Trust client forwarding headers." json:"forwardedHeaders,omitempty" toml:"forwardedHeaders,omitempty" yaml:"forwardedHeaders,omitempty"`
- HTTP HTTPConfig `description:"HTTP configuration." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty"`
+ Transport *EntryPointsTransport `description:"Configures communication between clients and Traefik." json:"transport,omitempty" toml:"transport,omitempty" yaml:"transport,omitempty" export:"true"`
+ ProxyProtocol *ProxyProtocol `description:"Proxy-Protocol configuration." json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ ForwardedHeaders *ForwardedHeaders `description:"Trust client forwarding headers." json:"forwardedHeaders,omitempty" toml:"forwardedHeaders,omitempty" yaml:"forwardedHeaders,omitempty" export:"true"`
+ HTTP HTTPConfig `description:"HTTP configuration." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true"`
}
// GetAddress strips any potential protocol part of the address field of the
@@ -49,22 +49,22 @@ func (ep *EntryPoint) SetDefaults() {
// HTTPConfig is the HTTP configuration of an entry point.
type HTTPConfig struct {
- Redirections *Redirections `description:"Set of redirection" json:"redirections,omitempty" toml:"redirections,omitempty" yaml:"redirections,omitempty"`
- Middlewares []string `description:"Default middlewares for the routers linked to the entry point." json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
- TLS *TLSConfig `description:"Default TLS configuration for the routers linked to the entry point." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty"`
+ Redirections *Redirections `description:"Set of redirection" json:"redirections,omitempty" toml:"redirections,omitempty" yaml:"redirections,omitempty" export:"true"`
+ Middlewares []string `description:"Default middlewares for the routers linked to the entry point." json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
+ TLS *TLSConfig `description:"Default TLS configuration for the routers linked to the entry point." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// Redirections is a set of redirection for an entry point.
type Redirections struct {
- EntryPoint *RedirectEntryPoint `description:"Set of redirection for an entry point." json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
+ EntryPoint *RedirectEntryPoint `description:"Set of redirection for an entry point." json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"`
}
// RedirectEntryPoint is the definition of an entry point redirection.
type RedirectEntryPoint struct {
- To string `description:"Targeted entry point of the redirection." json:"to,omitempty" toml:"to,omitempty" yaml:"to,omitempty"`
- Scheme string `description:"Scheme used for the redirection." json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty"`
- Permanent bool `description:"Applies a permanent redirection." json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty"`
- Priority int `description:"Priority of the generated router." json:"priority,omitempty" toml:"priority,omitempty" yaml:"priority,omitempty"`
+ To string `description:"Targeted entry point of the redirection." json:"to,omitempty" toml:"to,omitempty" yaml:"to,omitempty" export:"true"`
+ Scheme string `description:"Scheme used for the redirection." json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
+ Permanent bool `description:"Applies a permanent redirection." json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
+ Priority int `description:"Priority of the generated router." json:"priority,omitempty" toml:"priority,omitempty" yaml:"priority,omitempty" export:"true"`
}
// SetDefaults sets the default values.
@@ -76,9 +76,9 @@ func (r *RedirectEntryPoint) SetDefaults() {
// TLSConfig is the default TLS configuration for all the routers associated to the concerned entry point.
type TLSConfig struct {
- Options string `description:"Default TLS options for the routers linked to the entry point." json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
- CertResolver string `description:"Default certificate resolver for the routers linked to the entry point." json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`
- Domains []types.Domain `description:"Default TLS domains for the routers linked to the entry point." json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty"`
+ Options string `description:"Default TLS options for the routers linked to the entry point." json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
+ CertResolver string `description:"Default certificate resolver for the routers linked to the entry point." json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty" export:"true"`
+ Domains []types.Domain `description:"Default TLS domains for the routers linked to the entry point." json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty" export:"true"`
}
// ForwardedHeaders Trust client forwarding headers.
diff --git a/pkg/config/static/experimental.go b/pkg/config/static/experimental.go
index f10fb7cef..5715f1e91 100644
--- a/pkg/config/static/experimental.go
+++ b/pkg/config/static/experimental.go
@@ -4,6 +4,6 @@ import "github.com/traefik/traefik/v2/pkg/plugins"
// Experimental experimental Traefik features.
type Experimental struct {
- Plugins map[string]plugins.Descriptor `description:"Plugins configuration." json:"plugins,omitempty" toml:"plugins,omitempty" yaml:"plugins,omitempty"`
- DevPlugin *plugins.DevPlugin `description:"Dev plugin configuration." json:"devPlugin,omitempty" toml:"devPlugin,omitempty" yaml:"devPlugin,omitempty"`
+ Plugins map[string]plugins.Descriptor `description:"Plugins configuration." json:"plugins,omitempty" toml:"plugins,omitempty" yaml:"plugins,omitempty" export:"true"`
+ DevPlugin *plugins.DevPlugin `description:"Dev plugin configuration." json:"devPlugin,omitempty" toml:"devPlugin,omitempty" yaml:"devPlugin,omitempty" export:"true"`
}
diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go
index ddd91613c..905d0c639 100644
--- a/pkg/config/static/static_config.go
+++ b/pkg/config/static/static_config.go
@@ -72,9 +72,9 @@ type Configuration struct {
CertificatesResolvers map[string]CertificateResolver `description:"Certificates resolvers configuration." json:"certificatesResolvers,omitempty" toml:"certificatesResolvers,omitempty" yaml:"certificatesResolvers,omitempty" export:"true"`
- Pilot *Pilot `description:"Traefik Pilot configuration." json:"pilot,omitempty" toml:"pilot,omitempty" yaml:"pilot,omitempty"`
+ Pilot *Pilot `description:"Traefik Pilot configuration." json:"pilot,omitempty" toml:"pilot,omitempty" yaml:"pilot,omitempty" export:"true"`
- Experimental *Experimental `description:"experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty"`
+ Experimental *Experimental `description:"experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" export:"true"`
}
// CertificateResolver contains the configuration for the different types of certificates resolver.
@@ -176,14 +176,14 @@ type Providers struct {
KubernetesCRD *crd.Provider `description:"Enable Kubernetes backend with default settings." json:"kubernetesCRD,omitempty" toml:"kubernetesCRD,omitempty" yaml:"kubernetesCRD,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
Rest *rest.Provider `description:"Enable Rest backend with default settings." json:"rest,omitempty" toml:"rest,omitempty" yaml:"rest,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
Rancher *rancher.Provider `description:"Enable Rancher backend with default settings." json:"rancher,omitempty" toml:"rancher,omitempty" yaml:"rancher,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- ConsulCatalog *consulcatalog.Provider `description:"Enable ConsulCatalog backend with default settings." json:"consulCatalog,omitempty" toml:"consulCatalog,omitempty" yaml:"consulCatalog,omitempty"`
- Ecs *ecs.Provider `description:"Enable AWS ECS backend with default settings." json:"ecs,omitempty" toml:"ecs,omitempty" yaml:"ecs,omitempty"`
+ ConsulCatalog *consulcatalog.Provider `description:"Enable ConsulCatalog backend with default settings." json:"consulCatalog,omitempty" toml:"consulCatalog,omitempty" yaml:"consulCatalog,omitempty" export:"true"`
+ Ecs *ecs.Provider `description:"Enable AWS ECS backend with default settings." json:"ecs,omitempty" toml:"ecs,omitempty" yaml:"ecs,omitempty" export:"true"`
- Consul *consul.Provider `description:"Enable Consul backend with default settings." json:"consul,omitempty" toml:"consul,omitempty" yaml:"consul,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- Etcd *etcd.Provider `description:"Enable Etcd backend with default settings." json:"etcd,omitempty" toml:"etcd,omitempty" yaml:"etcd,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- ZooKeeper *zk.Provider `description:"Enable ZooKeeper backend with default settings." json:"zooKeeper,omitempty" toml:"zooKeeper,omitempty" yaml:"zooKeeper,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- Redis *redis.Provider `description:"Enable Redis backend with default settings." json:"redis,omitempty" toml:"redis,omitempty" yaml:"redis,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- HTTP *http.Provider `description:"Enable HTTP backend with default settings." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
+ Consul *consul.Provider `description:"Enable Consul backend with default settings." json:"consul,omitempty" toml:"consul,omitempty" yaml:"consul,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ Etcd *etcd.Provider `description:"Enable Etcd backend with default settings." json:"etcd,omitempty" toml:"etcd,omitempty" yaml:"etcd,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ ZooKeeper *zk.Provider `description:"Enable ZooKeeper backend with default settings." json:"zooKeeper,omitempty" toml:"zooKeeper,omitempty" yaml:"zooKeeper,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ Redis *redis.Provider `description:"Enable Redis backend with default settings." json:"redis,omitempty" toml:"redis,omitempty" yaml:"redis,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ HTTP *http.Provider `description:"Enable HTTP backend with default settings." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// SetEffectiveConfiguration adds missing configuration parameters derived from existing ones.
diff --git a/pkg/log/log.go b/pkg/log/log.go
index dddb80a99..999a5e1fd 100644
--- a/pkg/log/log.go
+++ b/pkg/log/log.go
@@ -137,7 +137,7 @@ func RotateFile() error {
}
if err := OpenFile(logFilePath); err != nil {
- return fmt.Errorf("error opening log file: %s", err)
+ return fmt.Errorf("error opening log file: %w", err)
}
return nil
diff --git a/pkg/metrics/prometheus.go b/pkg/metrics/prometheus.go
index 13f9a118c..b627b50b4 100644
--- a/pkg/metrics/prometheus.go
+++ b/pkg/metrics/prometheus.go
@@ -2,6 +2,7 @@ package metrics
import (
"context"
+ "errors"
"net/http"
"sort"
"strings"
@@ -74,12 +75,15 @@ func RegisterPrometheus(ctx context.Context, config *types.Prometheus) Registry
standardRegistry := initStandardRegistry(config)
if err := promRegistry.Register(stdprometheus.NewProcessCollector(stdprometheus.ProcessCollectorOpts{})); err != nil {
- if _, ok := err.(stdprometheus.AlreadyRegisteredError); !ok {
+ var arErr stdprometheus.AlreadyRegisteredError
+ if !errors.As(err, &arErr) {
log.FromContext(ctx).Warn("ProcessCollector is already registered")
}
}
+
if err := promRegistry.Register(stdprometheus.NewGoCollector()); err != nil {
- if _, ok := err.(stdprometheus.AlreadyRegisteredError); !ok {
+ var arErr stdprometheus.AlreadyRegisteredError
+ if !errors.As(err, &arErr) {
log.FromContext(ctx).Warn("GoCollector is already registered")
}
}
@@ -212,15 +216,21 @@ func initStandardRegistry(config *types.Prometheus) Registry {
}
func registerPromState(ctx context.Context) bool {
- if err := promRegistry.Register(promState); err != nil {
- logger := log.FromContext(ctx)
- if _, ok := err.(stdprometheus.AlreadyRegisteredError); !ok {
- logger.Errorf("Unable to register Traefik to Prometheus: %v", err)
- return false
- }
- logger.Debug("Prometheus collector already registered.")
+ err := promRegistry.Register(promState)
+ if err == nil {
+ return true
}
- return true
+
+ logger := log.FromContext(ctx)
+
+ var arErr stdprometheus.AlreadyRegisteredError
+ if errors.As(err, &arErr) {
+ logger.Debug("Prometheus collector already registered.")
+ return true
+ }
+
+ logger.Errorf("Unable to register Traefik to Prometheus: %v", err)
+ return false
}
// OnConfigurationUpdate receives the current configuration from Traefik.
diff --git a/pkg/middlewares/auth/forward.go b/pkg/middlewares/auth/forward.go
index 9ddd8d35f..381c687b4 100644
--- a/pkg/middlewares/auth/forward.go
+++ b/pkg/middlewares/auth/forward.go
@@ -2,6 +2,7 @@ package auth
import (
"context"
+ "errors"
"fmt"
"io/ioutil"
"net"
@@ -136,7 +137,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
redirectURL, err := forwardResponse.Location()
if err != nil {
- if err != http.ErrNoLocation {
+ if !errors.Is(err, http.ErrNoLocation) {
logMessage := fmt.Sprintf("Error reading response location header %s. Cause: %s", fa.address, err)
logger.Debug(logMessage)
tracing.SetErrorWithEvent(req, logMessage)
diff --git a/pkg/middlewares/recovery/recovery.go b/pkg/middlewares/recovery/recovery.go
index dc3fc2a68..7040c91c2 100644
--- a/pkg/middlewares/recovery/recovery.go
+++ b/pkg/middlewares/recovery/recovery.go
@@ -54,5 +54,6 @@ func recoverFunc(ctx context.Context, rw http.ResponseWriter, r *http.Request) {
// https://github.com/golang/go/blob/a0d6420d8be2ae7164797051ec74fa2a2df466a1/src/net/http/server.go#L1761-L1775
// https://github.com/golang/go/blob/c33153f7b416c03983324b3e8f869ce1116d84bc/src/net/http/httputil/reverseproxy.go#L284
func shouldLogPanic(panicValue interface{}) bool {
+ //nolint:errorlint // false-positive because panicValue is an interface.
return panicValue != nil && panicValue != http.ErrAbortHandler
}
diff --git a/pkg/ping/ping.go b/pkg/ping/ping.go
index ecf56a0df..a7a27a991 100644
--- a/pkg/ping/ping.go
+++ b/pkg/ping/ping.go
@@ -9,8 +9,8 @@ import (
// Handler expose ping routes.
type Handler struct {
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
- ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty"`
- TerminatingStatusCode int `description:"Terminating status code" json:"terminatingStatusCode,omitempty" toml:"terminatingStatusCode,omitempty" yaml:"terminatingStatusCode,omitempty"`
+ ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty" export:"true"`
+ TerminatingStatusCode int `description:"Terminating status code" json:"terminatingStatusCode,omitempty" toml:"terminatingStatusCode,omitempty" yaml:"terminatingStatusCode,omitempty" export:"true"`
terminating bool
}
diff --git a/pkg/plugins/types.go b/pkg/plugins/types.go
index 1737765a9..b93c972d4 100644
--- a/pkg/plugins/types.go
+++ b/pkg/plugins/types.go
@@ -3,19 +3,19 @@ package plugins
// Descriptor The static part of a plugin configuration (prod).
type Descriptor struct {
// ModuleName (required)
- ModuleName string `description:"plugin's module name." json:"moduleName,omitempty" toml:"moduleName,omitempty" yaml:"moduleName,omitempty"`
+ ModuleName string `description:"plugin's module name." json:"moduleName,omitempty" toml:"moduleName,omitempty" yaml:"moduleName,omitempty" export:"true"`
// Version (required)
- Version string `description:"plugin's version." json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty"`
+ Version string `description:"plugin's version." json:"version,omitempty" toml:"version,omitempty" yaml:"version,omitempty" export:"true"`
}
// DevPlugin The static part of a plugin configuration (only for dev).
type DevPlugin struct {
// GoPath plugin's GOPATH. (required)
- GoPath string `description:"plugin's GOPATH." json:"goPath,omitempty" toml:"goPath,omitempty" yaml:"goPath,omitempty"`
+ GoPath string `description:"plugin's GOPATH." json:"goPath,omitempty" toml:"goPath,omitempty" yaml:"goPath,omitempty" export:"true"`
// ModuleName (required)
- ModuleName string `description:"plugin's module name." json:"moduleName,omitempty" toml:"moduleName,omitempty" yaml:"moduleName,omitempty"`
+ ModuleName string `description:"plugin's module name." json:"moduleName,omitempty" toml:"moduleName,omitempty" yaml:"moduleName,omitempty" export:"true"`
}
// Manifest The plugin manifest.
diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go
index 8285413d1..b5674f373 100644
--- a/pkg/provider/acme/provider.go
+++ b/pkg/provider/acme/provider.go
@@ -35,12 +35,12 @@ var oscpMustStaple = false
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"`
- PreferredChain string `description:"Preferred chain to use." json:"preferredChain,omitempty" toml:"preferredChain,omitempty" yaml:"preferredChain,omitempty"`
- Storage string `description:"Storage to use." json:"storage,omitempty" toml:"storage,omitempty" yaml:"storage,omitempty"`
- KeyType string `description:"KeyType used for generating certificate private key. Allow value 'EC256', 'EC384', 'RSA2048', 'RSA4096', 'RSA8192'." json:"keyType,omitempty" toml:"keyType,omitempty" yaml:"keyType,omitempty"`
- DNSChallenge *DNSChallenge `description:"Activate DNS-01 Challenge." json:"dnsChallenge,omitempty" toml:"dnsChallenge,omitempty" yaml:"dnsChallenge,omitempty" label:"allowEmpty" file:"allowEmpty"`
- HTTPChallenge *HTTPChallenge `description:"Activate HTTP-01 Challenge." json:"httpChallenge,omitempty" toml:"httpChallenge,omitempty" yaml:"httpChallenge,omitempty" label:"allowEmpty" file:"allowEmpty"`
- TLSChallenge *TLSChallenge `description:"Activate TLS-ALPN-01 Challenge." json:"tlsChallenge,omitempty" toml:"tlsChallenge,omitempty" yaml:"tlsChallenge,omitempty" label:"allowEmpty" file:"allowEmpty"`
+ PreferredChain string `description:"Preferred chain to use." json:"preferredChain,omitempty" toml:"preferredChain,omitempty" yaml:"preferredChain,omitempty" export:"true"`
+ Storage string `description:"Storage to use." json:"storage,omitempty" toml:"storage,omitempty" yaml:"storage,omitempty" export:"true"`
+ KeyType string `description:"KeyType used for generating certificate private key. Allow value 'EC256', 'EC384', 'RSA2048', 'RSA4096', 'RSA8192'." json:"keyType,omitempty" toml:"keyType,omitempty" yaml:"keyType,omitempty" export:"true"`
+ DNSChallenge *DNSChallenge `description:"Activate DNS-01 Challenge." json:"dnsChallenge,omitempty" toml:"dnsChallenge,omitempty" yaml:"dnsChallenge,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ HTTPChallenge *HTTPChallenge `description:"Activate HTTP-01 Challenge." json:"httpChallenge,omitempty" toml:"httpChallenge,omitempty" yaml:"httpChallenge,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ TLSChallenge *TLSChallenge `description:"Activate TLS-ALPN-01 Challenge." json:"tlsChallenge,omitempty" toml:"tlsChallenge,omitempty" yaml:"tlsChallenge,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// SetDefaults sets the default values.
@@ -65,15 +65,15 @@ type Certificate struct {
// 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 ptypes.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"`
+ Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS." json:"provider,omitempty" toml:"provider,omitempty" yaml:"provider,omitempty" export:"true"`
+ DelayBeforeCheck ptypes.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" export:"true"`
Resolvers []string `description:"Use following DNS servers to resolve the FQDN authority." json:"resolvers,omitempty" toml:"resolvers,omitempty" yaml:"resolvers,omitempty"`
- DisablePropagationCheck bool `description:"Disable the DNS propagation checks before notifying ACME that the DNS challenge is ready. [not recommended]" json:"disablePropagationCheck,omitempty" toml:"disablePropagationCheck,omitempty" yaml:"disablePropagationCheck,omitempty"`
+ 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" export:"true"`
}
// HTTPChallenge contains HTTP challenge Configuration.
type HTTPChallenge struct {
- EntryPoint string `description:"HTTP challenge EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
+ EntryPoint string `description:"HTTP challenge EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"`
}
// TLSChallenge contains TLS challenge Configuration.
diff --git a/pkg/provider/consulcatalog/consul_catalog.go b/pkg/provider/consulcatalog/consul_catalog.go
index 6023d8486..acb3f9c8b 100644
--- a/pkg/provider/consulcatalog/consul_catalog.go
+++ b/pkg/provider/consulcatalog/consul_catalog.go
@@ -55,10 +55,10 @@ type Provider struct {
// EndpointConfig holds configurations of the endpoint.
type EndpointConfig struct {
- Address string `description:"The address of the Consul server" json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty" export:"true"`
- Scheme string `description:"The URI scheme for the Consul server" json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
- DataCenter string `description:"Data center to use. If not provided, the default agent data center is used" json:"datacenter,omitempty" toml:"datacenter,omitempty" yaml:"datacenter,omitempty" export:"true"`
- Token string `description:"Token is used to provide a per-request ACL token which overrides the agent's default token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" export:"true"`
+ Address string `description:"The address of the Consul server" json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
+ Scheme string `description:"The URI scheme for the Consul server" json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty"`
+ DataCenter string `description:"Data center to use. If not provided, the default agent data center is used" json:"datacenter,omitempty" toml:"datacenter,omitempty" yaml:"datacenter,omitempty"`
+ Token string `description:"Token is used to provide a per-request ACL token which overrides the agent's default token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
HTTPAuth *EndpointHTTPAuthConfig `description:"Auth info to use for http access" json:"httpAuth,omitempty" toml:"httpAuth,omitempty" yaml:"httpAuth,omitempty" export:"true"`
EndpointWaitTime ptypes.Duration `description:"WaitTime limits how long a Watch will block. If not provided, the agent default values will be used" json:"endpointWaitTime,omitempty" toml:"endpointWaitTime,omitempty" yaml:"endpointWaitTime,omitempty" export:"true"`
@@ -71,8 +71,8 @@ func (c *EndpointConfig) SetDefaults() {
// EndpointHTTPAuthConfig holds configurations of the authentication.
type EndpointHTTPAuthConfig struct {
- Username string `description:"Basic Auth username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty" export:"true"`
- Password string `description:"Basic Auth password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" export:"true"`
+ Username string `description:"Basic Auth username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"`
+ Password string `description:"Basic Auth password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
}
// SetDefaults sets the default values.
diff --git a/pkg/provider/docker/docker.go b/pkg/provider/docker/docker.go
index 5ed6a7708..10ba1709c 100644
--- a/pkg/provider/docker/docker.go
+++ b/pkg/provider/docker/docker.go
@@ -2,6 +2,7 @@ package docker
import (
"context"
+ "errors"
"fmt"
"io"
"net"
@@ -310,7 +311,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
startStopHandle(event)
}
case err := <-errc:
- if err == io.EOF {
+ if errors.Is(err, io.EOF) {
logger.Debug("Provider event stream closed")
}
return err
diff --git a/pkg/provider/http/http.go b/pkg/provider/http/http.go
index 56b87fe7a..37ef0b735 100644
--- a/pkg/provider/http/http.go
+++ b/pkg/provider/http/http.go
@@ -24,9 +24,9 @@ var _ provider.Provider = (*Provider)(nil)
// Provider is a provider.Provider implementation that queries an HTTP(s) endpoint for a configuration.
type Provider struct {
- Endpoint string `description:"Load configuration from this endpoint." json:"endpoint" toml:"endpoint" yaml:"endpoint" export:"true"`
- PollInterval ptypes.Duration `description:"Polling interval for endpoint." json:"pollInterval,omitempty" toml:"pollInterval,omitempty" yaml:"pollInterval,omitempty"`
- PollTimeout ptypes.Duration `description:"Polling timeout for endpoint." json:"pollTimeout,omitempty" toml:"pollTimeout,omitempty" yaml:"pollTimeout,omitempty"`
+ Endpoint string `description:"Load configuration from this endpoint." json:"endpoint" toml:"endpoint" yaml:"endpoint"`
+ PollInterval ptypes.Duration `description:"Polling interval for endpoint." json:"pollInterval,omitempty" toml:"pollInterval,omitempty" yaml:"pollInterval,omitempty" export:"true"`
+ PollTimeout ptypes.Duration `description:"Polling timeout for endpoint." json:"pollTimeout,omitempty" toml:"pollTimeout,omitempty" yaml:"pollTimeout,omitempty" export:"true"`
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
httpClient *http.Client
lastConfigurationHash uint64
diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go
index 811ef0bc0..32749b7be 100644
--- a/pkg/provider/kubernetes/crd/kubernetes.go
+++ b/pkg/provider/kubernetes/crd/kubernetes.go
@@ -45,7 +45,7 @@ type Provider struct {
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
LabelSelector string `description:"Kubernetes label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"`
- ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty"`
+ ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
lastConfiguration safe.Safe
}
diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go
index e039f7b04..db77c9d98 100644
--- a/pkg/provider/kubernetes/ingress/kubernetes.go
+++ b/pkg/provider/kubernetes/ingress/kubernetes.go
@@ -41,8 +41,8 @@ type Provider struct {
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
LabelSelector string `description:"Kubernetes Ingress label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"`
- IngressEndpoint *EndpointIngress `description:"Kubernetes Ingress Endpoint." json:"ingressEndpoint,omitempty" toml:"ingressEndpoint,omitempty" yaml:"ingressEndpoint,omitempty"`
- ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty"`
+ IngressEndpoint *EndpointIngress `description:"Kubernetes Ingress Endpoint." json:"ingressEndpoint,omitempty" toml:"ingressEndpoint,omitempty" yaml:"ingressEndpoint,omitempty" export:"true"`
+ ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
lastConfiguration safe.Safe
}
diff --git a/pkg/provider/kv/consul/consul.go b/pkg/provider/kv/consul/consul.go
index ecff63a62..80a9f3273 100644
--- a/pkg/provider/kv/consul/consul.go
+++ b/pkg/provider/kv/consul/consul.go
@@ -10,7 +10,7 @@ var _ provider.Provider = (*Provider)(nil)
// Provider holds configurations of the provider.
type Provider struct {
- kv.Provider
+ kv.Provider `export:"true"`
}
// SetDefaults sets the default values.
diff --git a/pkg/provider/kv/etcd/etcd.go b/pkg/provider/kv/etcd/etcd.go
index 57f5bc4e5..314ea2be9 100644
--- a/pkg/provider/kv/etcd/etcd.go
+++ b/pkg/provider/kv/etcd/etcd.go
@@ -10,7 +10,7 @@ var _ provider.Provider = (*Provider)(nil)
// Provider holds configurations of the provider.
type Provider struct {
- kv.Provider
+ kv.Provider `export:"true"`
}
// SetDefaults sets the default values.
diff --git a/pkg/provider/kv/redis/redis.go b/pkg/provider/kv/redis/redis.go
index ee3796985..07ce7bf78 100644
--- a/pkg/provider/kv/redis/redis.go
+++ b/pkg/provider/kv/redis/redis.go
@@ -10,7 +10,7 @@ var _ provider.Provider = (*Provider)(nil)
// Provider holds configurations of the provider.
type Provider struct {
- kv.Provider
+ kv.Provider `export:"true"`
}
// SetDefaults sets the default values.
diff --git a/pkg/provider/kv/zk/zk.go b/pkg/provider/kv/zk/zk.go
index f8af67748..665dcc00a 100644
--- a/pkg/provider/kv/zk/zk.go
+++ b/pkg/provider/kv/zk/zk.go
@@ -10,7 +10,7 @@ var _ provider.Provider = (*Provider)(nil)
// Provider holds configurations of the provider.
type Provider struct {
- kv.Provider
+ kv.Provider `export:"true"`
}
// SetDefaults sets the default values.
diff --git a/pkg/provider/marathon/marathon.go b/pkg/provider/marathon/marathon.go
index b4e2d877f..d0405b6db 100644
--- a/pkg/provider/marathon/marathon.go
+++ b/pkg/provider/marathon/marathon.go
@@ -49,10 +49,10 @@ type Provider struct {
Constraints string `description:"Constraints is an expression that Traefik matches against the application's labels to determine whether to create any route for that application." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
Trace bool `description:"Display additional provider logs." json:"trace,omitempty" toml:"trace,omitempty" yaml:"trace,omitempty" export:"true"`
Watch bool `description:"Watch provider." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
- Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
+ Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
ExposedByDefault bool `description:"Expose Marathon apps by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
- DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header." json:"dcosToken,omitempty" toml:"dcosToken,omitempty" yaml:"dcosToken,omitempty" export:"true"`
+ DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header." json:"dcosToken,omitempty" toml:"dcosToken,omitempty" yaml:"dcosToken,omitempty"`
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
DialerTimeout ptypes.Duration `description:"Set a dialer timeout for Marathon." json:"dialerTimeout,omitempty" toml:"dialerTimeout,omitempty" yaml:"dialerTimeout,omitempty" export:"true"`
ResponseHeaderTimeout ptypes.Duration `description:"Set a response header timeout for Marathon." json:"responseHeaderTimeout,omitempty" toml:"responseHeaderTimeout,omitempty" yaml:"responseHeaderTimeout,omitempty" export:"true"`
diff --git a/pkg/provider/rancher/rancher.go b/pkg/provider/rancher/rancher.go
index e11db7c9e..8de7ad862 100644
--- a/pkg/provider/rancher/rancher.go
+++ b/pkg/provider/rancher/rancher.go
@@ -46,7 +46,7 @@ type Provider struct {
ExposedByDefault bool `description:"Expose containers by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
EnableServiceHealthFilter bool `description:"Filter services with unhealthy states and inactive states." json:"enableServiceHealthFilter,omitempty" toml:"enableServiceHealthFilter,omitempty" yaml:"enableServiceHealthFilter,omitempty" export:"true"`
RefreshSeconds int `description:"Defines the polling interval in seconds." json:"refreshSeconds,omitempty" toml:"refreshSeconds,omitempty" yaml:"refreshSeconds,omitempty" export:"true"`
- IntervalPoll bool `description:"Poll the Rancher metadata service every 'rancher.refreshseconds' (less accurate)." json:"intervalPoll,omitempty" toml:"intervalPoll,omitempty" yaml:"intervalPoll,omitempty"`
+ IntervalPoll bool `description:"Poll the Rancher metadata service every 'rancher.refreshseconds' (less accurate)." json:"intervalPoll,omitempty" toml:"intervalPoll,omitempty" yaml:"intervalPoll,omitempty" export:"true"`
Prefix string `description:"Prefix used for accessing the Rancher metadata service." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty"`
defaultRuleTpl *template.Template
}
diff --git a/pkg/server/server.go b/pkg/server/server.go
index 0df1ba9b3..9c585b7a3 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -2,6 +2,7 @@ package server
import (
"context"
+ "errors"
"os"
"os/signal"
"time"
@@ -85,9 +86,9 @@ func (s *Server) Close() {
go func(ctx context.Context) {
<-ctx.Done()
- if ctx.Err() == context.Canceled {
+ if errors.Is(ctx.Err(), context.Canceled) {
return
- } else if ctx.Err() == context.DeadlineExceeded {
+ } else if errors.Is(ctx.Err(), context.DeadlineExceeded) {
panic("Timeout while stopping traefik, killing instance ✝")
}
}(ctx)
diff --git a/pkg/server/server_entrypoint_tcp.go b/pkg/server/server_entrypoint_tcp.go
index 4c3b756c1..a9f1fdf94 100644
--- a/pkg/server/server_entrypoint_tcp.go
+++ b/pkg/server/server_entrypoint_tcp.go
@@ -2,11 +2,13 @@ package server
import (
"context"
+ "errors"
"fmt"
stdlog "log"
"net"
"net/http"
"sync"
+ "syscall"
"time"
proxyprotocol "github.com/c0va23/go-proxyprotocol"
@@ -172,11 +174,15 @@ func (e *TCPEntryPoint) Start(ctx context.Context) {
conn, err := e.listener.Accept()
if err != nil {
logger.Error(err)
- if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
+
+ var netErr net.Error
+ if errors.As(err, &netErr) && netErr.Temporary() {
continue
}
+
e.httpServer.Forwarder.errChan <- err
e.httpsServer.Forwarder.errChan <- err
+
return
}
@@ -230,7 +236,7 @@ func (e *TCPEntryPoint) Shutdown(ctx context.Context) {
if err == nil {
return
}
- if ctx.Err() == context.DeadlineExceeded {
+ if errors.Is(ctx.Err(), context.DeadlineExceeded) {
logger.Debugf("Server failed to shutdown within deadline because: %s", err)
if err = server.Close(); err != nil {
logger.Error(err)
@@ -261,7 +267,7 @@ func (e *TCPEntryPoint) Shutdown(ctx context.Context) {
if err == nil {
return
}
- if ctx.Err() == context.DeadlineExceeded {
+ if errors.Is(ctx.Err(), context.DeadlineExceeded) {
logger.Debugf("Server failed to shutdown before deadline because: %s", err)
}
e.tracker.Close()
@@ -340,7 +346,11 @@ func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
}
if err = tc.SetKeepAlivePeriod(3 * time.Minute); err != nil {
- return nil, err
+ // Some systems, such as OpenBSD, have no user-settable per-socket TCP
+ // keepalive options.
+ if !errors.Is(err, syscall.ENOPROTOOPT) {
+ return nil, err
+ }
}
return tc, nil
diff --git a/pkg/server/server_entrypoint_tcp_test.go b/pkg/server/server_entrypoint_tcp_test.go
index 244703946..6c76c768d 100644
--- a/pkg/server/server_entrypoint_tcp_test.go
+++ b/pkg/server/server_entrypoint_tcp_test.go
@@ -46,7 +46,7 @@ func TestShutdownTCP(t *testing.T) {
for {
_, err := http.ReadRequest(bufio.NewReader(conn))
- if err == io.EOF || (err != nil && strings.HasSuffix(err.Error(), "use of closed network connection")) {
+ if errors.Is(err, io.EOF) || (err != nil && strings.HasSuffix(err.Error(), "use of closed network connection")) {
return
}
require.NoError(t, err)
diff --git a/pkg/server/service/loadbalancer/mirror/mirror.go b/pkg/server/service/loadbalancer/mirror/mirror.go
index d5a6ef1bc..00e2f06cb 100644
--- a/pkg/server/service/loadbalancer/mirror/mirror.go
+++ b/pkg/server/service/loadbalancer/mirror/mirror.go
@@ -81,13 +81,13 @@ func (m *Mirroring) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := log.FromContext(req.Context())
rr, bytesRead, err := newReusableRequest(req, m.maxBodySize)
- if err != nil && err != errBodyTooLarge {
+ if err != nil && !errors.Is(err, errBodyTooLarge) {
http.Error(rw, http.StatusText(http.StatusInternalServerError)+
fmt.Sprintf("error creating reusable request: %v", err), http.StatusInternalServerError)
return
}
- if err == errBodyTooLarge {
+ if errors.Is(err, errBodyTooLarge) {
req.Body = ioutil.NopCloser(io.MultiReader(bytes.NewReader(bytesRead), req.Body))
m.handler.ServeHTTP(rw, req)
logger.Debugf("no mirroring, request body larger than allowed size")
@@ -196,13 +196,13 @@ func newReusableRequest(req *http.Request, maxBodySize int64) (*reusableRequest,
// the request body is larger than what we allow for the mirrors.
body := make([]byte, maxBodySize+1)
n, err := io.ReadFull(req.Body, body)
- if err != nil && err != io.ErrUnexpectedEOF {
+ if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) {
return nil, nil, err
}
// we got an ErrUnexpectedEOF, which means there was less than maxBodySize data to read,
// which permits us sending also to all the mirrors later.
- if err == io.ErrUnexpectedEOF {
+ if errors.Is(err, io.ErrUnexpectedEOF) {
return &reusableRequest{
req: req,
body: body[:n],
diff --git a/pkg/server/service/loadbalancer/wrr/wrr.go b/pkg/server/service/loadbalancer/wrr/wrr.go
index a9ea42a4a..7558f6bca 100644
--- a/pkg/server/service/loadbalancer/wrr/wrr.go
+++ b/pkg/server/service/loadbalancer/wrr/wrr.go
@@ -2,6 +2,7 @@ package wrr
import (
"container/heap"
+ "errors"
"fmt"
"net/http"
"sync"
@@ -105,7 +106,7 @@ func (b *Balancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if b.stickyCookie != nil {
cookie, err := req.Cookie(b.stickyCookie.name)
- if err != nil && err != http.ErrNoCookie {
+ if err != nil && !errors.Is(err, http.ErrNoCookie) {
log.WithoutContext().Warnf("Error while reading cookie: %v", err)
}
diff --git a/pkg/server/service/proxy.go b/pkg/server/service/proxy.go
index 7be7db0a7..bb0f7d92d 100644
--- a/pkg/server/service/proxy.go
+++ b/pkg/server/service/proxy.go
@@ -2,6 +2,7 @@ package service
import (
"context"
+ "errors"
"fmt"
"io"
"net"
@@ -83,13 +84,14 @@ func buildProxy(passHostHeader *bool, responseForwarding *dynamic.ResponseForwar
statusCode := http.StatusInternalServerError
switch {
- case err == io.EOF:
+ case errors.Is(err, io.EOF):
statusCode = http.StatusBadGateway
- case err == context.Canceled:
+ case errors.Is(err, context.Canceled):
statusCode = StatusClientClosedRequest
default:
- if e, ok := err.(net.Error); ok {
- if e.Timeout() {
+ var netErr net.Error
+ if errors.As(err, &netErr) {
+ if netErr.Timeout() {
statusCode = http.StatusGatewayTimeout
} else {
statusCode = http.StatusBadGateway
diff --git a/pkg/server/service/proxy_websocket_test.go b/pkg/server/service/proxy_websocket_test.go
index fe169e1c5..a759cf95a 100644
--- a/pkg/server/service/proxy_websocket_test.go
+++ b/pkg/server/service/proxy_websocket_test.go
@@ -3,6 +3,7 @@ package service
import (
"bufio"
"crypto/tls"
+ "errors"
"fmt"
"net"
"net/http"
@@ -49,12 +50,13 @@ func TestWebSocketTCPClose(t *testing.T) {
withPath("/ws"),
).open()
require.NoError(t, err)
+
conn.Close()
serverErr := <-errChan
- wsErr, ok := serverErr.(*gorillawebsocket.CloseError)
- assert.Equal(t, true, ok)
+ var wsErr *gorillawebsocket.CloseError
+ require.True(t, errors.As(serverErr, &wsErr))
assert.Equal(t, 1006, wsErr.Code)
}
@@ -119,7 +121,7 @@ func TestWebSocketPingPong(t *testing.T) {
_, _, err = conn.ReadMessage()
- if err != goodErr {
+ if !errors.Is(err, goodErr) {
require.NoError(t, err)
}
}
diff --git a/pkg/tcp/router.go b/pkg/tcp/router.go
index 31ff07342..ea0f406e7 100644
--- a/pkg/tcp/router.go
+++ b/pkg/tcp/router.go
@@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"crypto/tls"
+ "errors"
"io"
"net"
"net/http"
@@ -197,10 +198,11 @@ func (c *Conn) Read(p []byte) (n int, err error) {
func clientHelloServerName(br *bufio.Reader) (string, bool, string, error) {
hdr, err := br.Peek(1)
if err != nil {
- opErr, ok := err.(*net.OpError)
- if err != io.EOF && (!ok || !opErr.Timeout()) {
+ var opErr *net.OpError
+ if !errors.Is(err, io.EOF) && (!errors.As(err, &opErr) || opErr.Timeout()) {
log.WithoutContext().Debugf("Error while Peeking first byte: %s", err)
}
+
return "", false, "", err
}
diff --git a/pkg/tracing/datadog/datadog.go b/pkg/tracing/datadog/datadog.go
index 3b39f8ebb..a64f81b4a 100644
--- a/pkg/tracing/datadog/datadog.go
+++ b/pkg/tracing/datadog/datadog.go
@@ -18,7 +18,7 @@ type Config struct {
LocalAgentHostPort string `description:"Set datadog-agent's host:port that the reporter will used." json:"localAgentHostPort,omitempty" toml:"localAgentHostPort,omitempty" yaml:"localAgentHostPort,omitempty"`
GlobalTag string `description:"Key:Value tag to be set on all the spans." json:"globalTag,omitempty" toml:"globalTag,omitempty" yaml:"globalTag,omitempty" export:"true"`
Debug bool `description:"Enable Datadog debug." json:"debug,omitempty" toml:"debug,omitempty" yaml:"debug,omitempty" export:"true"`
- PrioritySampling bool `description:"Enable priority sampling. When using distributed tracing, this option must be enabled in order to get all the parts of a distributed trace sampled." json:"prioritySampling,omitempty" toml:"prioritySampling,omitempty" yaml:"prioritySampling,omitempty"`
+ PrioritySampling bool `description:"Enable priority sampling. When using distributed tracing, this option must be enabled in order to get all the parts of a distributed trace sampled." json:"prioritySampling,omitempty" toml:"prioritySampling,omitempty" yaml:"prioritySampling,omitempty" export:"true"`
TraceIDHeaderName string `description:"Specifies the header name that will be used to store the trace ID." json:"traceIDHeaderName,omitempty" toml:"traceIDHeaderName,omitempty" yaml:"traceIDHeaderName,omitempty" export:"true"`
ParentIDHeaderName string `description:"Specifies the header name that will be used to store the parent ID." json:"parentIDHeaderName,omitempty" toml:"parentIDHeaderName,omitempty" yaml:"parentIDHeaderName,omitempty" export:"true"`
SamplingPriorityHeaderName string `description:"Specifies the header name that will be used to store the sampling priority." json:"samplingPriorityHeaderName,omitempty" toml:"samplingPriorityHeaderName,omitempty" yaml:"samplingPriorityHeaderName,omitempty" export:"true"`
diff --git a/pkg/tracing/elastic/elastic.go b/pkg/tracing/elastic/elastic.go
index d31d8c759..b80d2d14a 100644
--- a/pkg/tracing/elastic/elastic.go
+++ b/pkg/tracing/elastic/elastic.go
@@ -26,7 +26,7 @@ func init() {
type Config struct {
ServerURL string `description:"Set the URL of the Elastic APM server." json:"serverURL,omitempty" toml:"serverURL,omitempty" yaml:"serverURL,omitempty"`
SecretToken string `description:"Set the token used to connect to Elastic APM Server." json:"secretToken,omitempty" toml:"secretToken,omitempty" yaml:"secretToken,omitempty"`
- ServiceEnvironment string `description:"Set the name of the environment Traefik is deployed in, e.g. 'production' or 'staging'." json:"serviceEnvironment,omitempty" toml:"serviceEnvironment,omitempty" yaml:"serviceEnvironment,omitempty"`
+ ServiceEnvironment string `description:"Set the name of the environment Traefik is deployed in, e.g. 'production' or 'staging'." json:"serviceEnvironment,omitempty" toml:"serviceEnvironment,omitempty" yaml:"serviceEnvironment,omitempty" export:"true"`
}
// Setup sets up the tracer.
diff --git a/pkg/tracing/jaeger/jaeger.go b/pkg/tracing/jaeger/jaeger.go
index ae7cf050b..05f309a70 100644
--- a/pkg/tracing/jaeger/jaeger.go
+++ b/pkg/tracing/jaeger/jaeger.go
@@ -42,7 +42,7 @@ func (c *Config) SetDefaults() {
// Collector provides configuration settings for jaeger collector.
type Collector struct {
- Endpoint string `description:"Instructs reporter to send spans to jaeger-collector at this URL." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
+ Endpoint string `description:"Instructs reporter to send spans to jaeger-collector at this URL." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
User string `description:"User for basic http authentication when sending spans to jaeger-collector." json:"user,omitempty" toml:"user,omitempty" yaml:"user,omitempty"`
Password string `description:"Password for basic http authentication when sending spans to jaeger-collector." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
}
diff --git a/pkg/types/logs.go b/pkg/types/logs.go
index aeb7ee872..2c932e487 100644
--- a/pkg/types/logs.go
+++ b/pkg/types/logs.go
@@ -23,7 +23,7 @@ const (
type TraefikLog struct {
Level string `description:"Log level set to traefik logs." json:"level,omitempty" toml:"level,omitempty" yaml:"level,omitempty" export:"true"`
FilePath string `description:"Traefik log file path. Stdout is used when omitted or empty." json:"filePath,omitempty" toml:"filePath,omitempty" yaml:"filePath,omitempty"`
- Format string `description:"Traefik log format: json | common" json:"format,omitempty" toml:"format,omitempty" yaml:"format,omitempty"`
+ Format string `description:"Traefik log format: json | common" json:"format,omitempty" toml:"format,omitempty" yaml:"format,omitempty" export:"true"`
}
// SetDefaults sets the default values.
@@ -34,7 +34,7 @@ func (l *TraefikLog) SetDefaults() {
// AccessLog holds the configuration settings for the access logger (middlewares/accesslog).
type AccessLog struct {
- FilePath string `description:"Access log file path. Stdout is used when omitted or empty." json:"filePath,omitempty" toml:"filePath,omitempty" yaml:"filePath,omitempty" export:"true"`
+ FilePath string `description:"Access log file path. Stdout is used when omitted or empty." json:"filePath,omitempty" toml:"filePath,omitempty" yaml:"filePath,omitempty"`
Format string `description:"Access log format: json | common" json:"format,omitempty" toml:"format,omitempty" yaml:"format,omitempty" export:"true"`
Filters *AccessLogFilters `description:"Access log filters, used to keep only specific access logs." json:"filters,omitempty" toml:"filters,omitempty" yaml:"filters,omitempty" export:"true"`
Fields *AccessLogFields `description:"AccessLogFields." json:"fields,omitempty" toml:"fields,omitempty" yaml:"fields,omitempty" export:"true"`
diff --git a/pkg/types/metrics.go b/pkg/types/metrics.go
index e0916e720..f3391fc21 100644
--- a/pkg/types/metrics.go
+++ b/pkg/types/metrics.go
@@ -8,10 +8,10 @@ import (
// Metrics provides options to expose and send Traefik metrics to different third party monitoring systems.
type Metrics struct {
- Prometheus *Prometheus `description:"Prometheus metrics exporter type." json:"prometheus,omitempty" toml:"prometheus,omitempty" yaml:"prometheus,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- Datadog *Datadog `description:"Datadog metrics exporter type." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- StatsD *Statsd `description:"StatsD metrics exporter type." json:"statsD,omitempty" toml:"statsD,omitempty" yaml:"statsD,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
- InfluxDB *InfluxDB `description:"InfluxDB metrics exporter type." json:"influxDB,omitempty" toml:"influxDB,omitempty" yaml:"influxDB,omitempty" label:"allowEmpty" file:"allowEmpty"`
+ Prometheus *Prometheus `description:"Prometheus metrics exporter type." json:"prometheus,omitempty" toml:"prometheus,omitempty" yaml:"prometheus,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ Datadog *Datadog `description:"Datadog metrics exporter type." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ StatsD *Statsd `description:"StatsD metrics exporter type." json:"statsD,omitempty" toml:"statsD,omitempty" yaml:"statsD,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
+ InfluxDB *InfluxDB `description:"InfluxDB metrics exporter type." json:"influxDB,omitempty" toml:"influxDB,omitempty" yaml:"influxDB,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// Prometheus can contain specific configuration used by the Prometheus Metrics exporter.
@@ -20,7 +20,7 @@ type Prometheus struct {
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
- ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty"`
+ ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty" export:"true"`
}
// SetDefaults sets the default values.
@@ -72,8 +72,8 @@ type InfluxDB struct {
PushInterval types.Duration `description:"InfluxDB push interval." json:"pushInterval,omitempty" toml:"pushInterval,omitempty" yaml:"pushInterval,omitempty" export:"true"`
Database string `description:"InfluxDB database used when protocol is http." json:"database,omitempty" toml:"database,omitempty" yaml:"database,omitempty" export:"true"`
RetentionPolicy string `description:"InfluxDB retention policy used when protocol is http." json:"retentionPolicy,omitempty" toml:"retentionPolicy,omitempty" yaml:"retentionPolicy,omitempty" export:"true"`
- Username string `description:"InfluxDB username (only with http)." json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty" export:"true"`
- Password string `description:"InfluxDB password (only with http)." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" export:"true"`
+ Username string `description:"InfluxDB username (only with http)." json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"`
+ Password string `description:"InfluxDB password (only with http)." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`
}
diff --git a/pkg/types/tls.go b/pkg/types/tls.go
index 2ff8c9807..416136e78 100644
--- a/pkg/types/tls.go
+++ b/pkg/types/tls.go
@@ -15,10 +15,10 @@ import (
// CA, Cert and Key can be either path or file contents.
type ClientTLS struct {
CA string `description:"TLS CA" json:"ca,omitempty" toml:"ca,omitempty" yaml:"ca,omitempty"`
- CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty"`
+ CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty" export:"true"`
Cert string `description:"TLS cert" json:"cert,omitempty" toml:"cert,omitempty" yaml:"cert,omitempty"`
Key string `description:"TLS key" json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty"`
- InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"`
+ InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
}
// CreateTLSConfig creates a TLS config from ClientTLS structures.
diff --git a/pkg/udp/conn_test.go b/pkg/udp/conn_test.go
index 62c35d04a..f97eb3958 100644
--- a/pkg/udp/conn_test.go
+++ b/pkg/udp/conn_test.go
@@ -1,6 +1,7 @@
package udp
import (
+ "errors"
"io"
"net"
"testing"
@@ -24,7 +25,7 @@ func TestConsecutiveWrites(t *testing.T) {
go func() {
for {
conn, err := ln.Accept()
- if err == errClosedListener {
+ if errors.Is(err, errClosedListener) {
return
}
require.NoError(t, err)
@@ -86,7 +87,7 @@ func TestListenNotBlocking(t *testing.T) {
go func() {
for {
conn, err := ln.Accept()
- if err == errClosedListener {
+ if errors.Is(err, errClosedListener) {
return
}
require.NoError(t, err)
@@ -183,7 +184,7 @@ func testTimeout(t *testing.T, withRead bool) {
go func() {
for {
conn, err := ln.Accept()
- if err == errClosedListener {
+ if errors.Is(err, errClosedListener) {
return
}
require.NoError(t, err)