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
- +
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)