From b02381c2d574fd80982b2ce711414bbd47055f59 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 8 May 2018 12:00:03 +0200 Subject: [PATCH 1/9] Fix wrong tag in forward span in tracing middleware --- middlewares/tracing/forwarder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middlewares/tracing/forwarder.go b/middlewares/tracing/forwarder.go index 881302cb4..aa80486c5 100644 --- a/middlewares/tracing/forwarder.go +++ b/middlewares/tracing/forwarder.go @@ -33,7 +33,7 @@ func (f *forwarderMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, span.SetTag("frontend.name", f.frontend) span.SetTag("backend.name", f.backend) ext.HTTPMethod.Set(span, r.Method) - ext.HTTPUrl.Set(span, r.URL.String()) + ext.HTTPUrl.Set(span, fmt.Sprintf("%s%s", r.URL.String(), r.RequestURI)) span.SetTag("http.host", r.Host) InjectRequestHeaders(r) From ebd9af900e10d85cd916e72519cb7f14f7c2c3a3 Mon Sep 17 00:00:00 2001 From: Blake Patton Date: Wed, 9 May 2018 10:48:03 -0500 Subject: [PATCH 2/9] Changed "is could" to should --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 00a875695..80a10da71 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Træfik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy. Træfik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically. -Telling Træfik where your orchestrator is could be the _only_ configuration step you need to do. +Pointing Træfik at your orchestrator should be the _only_ configuration step you need. --- diff --git a/docs/index.md b/docs/index.md index d9c866abd..5d07831e9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,7 +12,7 @@ Træfik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy. Træfik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically. -Telling Træfik where your orchestrator is could be the _only_ configuration step you need to do. +Pointing Træfik at your orchestrator should be the _only_ configuration step you need. ## Overview From 8fcd242494dd89423910ac5ecd8b82077d3b15fa Mon Sep 17 00:00:00 2001 From: Daniel Tomcej Date: Fri, 11 May 2018 12:52:03 +0200 Subject: [PATCH 3/9] Add Documentation update for Kubernetes Ingress --- docs/configuration/backends/kubernetes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration/backends/kubernetes.md b/docs/configuration/backends/kubernetes.md index dfb20adcc..f54f84317 100644 --- a/docs/configuration/backends/kubernetes.md +++ b/docs/configuration/backends/kubernetes.md @@ -112,7 +112,7 @@ Although traefik will connect directly to the endpoints (pods), it still checks If the service port defined in the ingress spec is 443, then the backend communication protocol is assumed to be TLS, and will connect via TLS automatically. !!! note - Please note that by enabling TLS communication between traefik and your pods, you will have to have trusted certificates that have the proper trust chain and IP subject name. + Please note that by enabling TLS communication between traefik and your pods, you will have to have trusted certificates that have the proper trust chain and IP subject name. If this is not an option, you may need to skip TLS certificate verification. See the [insecureSkipVerify](/configuration/commons/#main-section) setting for more details. @@ -137,7 +137,7 @@ The following general annotations are applicable on the Ingress object: | `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. | | `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. | | `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. | -| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access. all source IPs are permitted if the list is empty or a single range is ill-formatted. | +| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access. all source IPs are permitted if the list is empty or a single range is ill-formatted. Please note, you may have to set `service.spec.externalTrafficPolicy` to the value `Local` to preserve the source IP of the request for filtering. Please see [this link](https://kubernetes.io/docs/tutorials/services/source-ip/) for more information.| | `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (4) | <1> `traefik.ingress.kubernetes.io/error-pages` example: @@ -261,4 +261,4 @@ More information are available in the [User Guide](/user-guide/kubernetes/#add- !!! note Only TLS certificates provided by users can be stored in Kubernetes Secrets. - [Let's Encrypt](https://letsencrypt.org) certificates cannot be managed in Kubernets Secrets yet. \ No newline at end of file + [Let's Encrypt](https://letsencrypt.org) certificates cannot be managed in Kubernets Secrets yet. From c5db8d903c82dbeb1a97c1118d4d5a7bbbe28c7f Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Sun, 13 May 2018 17:12:03 +0200 Subject: [PATCH 4/9] Enhance entry point TLS CLI reference. --- configuration/entrypoints_test.go | 12 ++++++++++-- docs/configuration/entrypoints.md | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/configuration/entrypoints_test.go b/configuration/entrypoints_test.go index a528c04b0..59b357220 100644 --- a/configuration/entrypoints_test.go +++ b/configuration/entrypoints_test.go @@ -170,7 +170,7 @@ func TestEntryPoints_Set(t *testing.T) { name: "all parameters camelcase", expression: "Name:foo " + "Address::8000 " + - "TLS:goo,gii " + + "TLS:goo,gii;foo,fii " + "TLS " + "CA:car " + "CA.Optional:true " + @@ -203,6 +203,10 @@ func TestEntryPoints_Set(t *testing.T) { CertFile: tls.FileOrContent("goo"), KeyFile: tls.FileOrContent("gii"), }, + { + CertFile: tls.FileOrContent("foo"), + KeyFile: tls.FileOrContent("fii"), + }, }, ClientCA: tls.ClientCA{ Files: []string{"car"}, @@ -272,7 +276,7 @@ func TestEntryPoints_Set(t *testing.T) { name: "all parameters lowercase", expression: "Name:foo " + "address::8000 " + - "tls:goo,gii " + + "tls:goo,gii;foo,fii " + "tls " + "ca:car " + "ca.Optional:true " + @@ -303,6 +307,10 @@ func TestEntryPoints_Set(t *testing.T) { CertFile: tls.FileOrContent("goo"), KeyFile: tls.FileOrContent("gii"), }, + { + CertFile: tls.FileOrContent("foo"), + KeyFile: tls.FileOrContent("fii"), + }, }, ClientCA: tls.ClientCA{ Files: []string{"car"}, diff --git a/docs/configuration/entrypoints.md b/docs/configuration/entrypoints.md index a41009ca0..36a4d8cce 100644 --- a/docs/configuration/entrypoints.md +++ b/docs/configuration/entrypoints.md @@ -106,7 +106,7 @@ traefik: ```ini Name:foo Address::80 -TLS:goo,gii +TLS:/my/path/foo.cert,/my/path/foo.key;/my/path/goo.cert,/my/path/goo.key;/my/path/hoo.cert,/my/path/hoo.key TLS CA:car CA.Optional:true From b3fd06fb4553259fbcdd85a3f0d43e1761c0a82a Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 14 May 2018 09:52:03 +0200 Subject: [PATCH 5/9] Add missing deprecation info in CLI help. --- acme/acme.go | 8 ++++---- configuration/configuration.go | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/acme/acme.go b/acme/acme.go index 805b2b744..f32445aeb 100644 --- a/acme/acme.go +++ b/acme/acme.go @@ -41,15 +41,15 @@ type ACME struct { Email string `description:"Email address used for registration"` Domains []types.Domain `description:"SANs (alternative domains) to each main domain using format: --acme.domains='main.com,san1.com,san2.com' --acme.domains='main.net,san1.net,san2.net'"` Storage string `description:"File or key used for certificates storage."` - StorageFile string // deprecated - OnDemand bool `description:"Enable on demand certificate generation. This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate."` //deprecated + StorageFile string // Deprecated + OnDemand bool `description:"(Deprecated) Enable on demand certificate generation. This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate."` //deprecated OnHostRule bool `description:"Enable certificate generation on frontends Host rules."` CAServer string `description:"CA server to use."` EntryPoint string `description:"Entrypoint to proxy acme challenge to."` DNSChallenge *acmeprovider.DNSChallenge `description:"Activate DNS-01 Challenge"` HTTPChallenge *acmeprovider.HTTPChallenge `description:"Activate HTTP-01 Challenge"` - DNSProvider string `description:"Activate DNS-01 Challenge (Deprecated)"` // deprecated - DelayDontCheckDNS flaeg.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` // deprecated + DNSProvider string `description:"(Deprecated) Activate DNS-01 Challenge"` // Deprecated + DelayDontCheckDNS flaeg.Duration `description:"(Deprecated) Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` // Deprecated ACMELogging bool `description:"Enable debug logging of ACME actions."` client *acme.Client defaultCertificate *tls.Certificate diff --git a/configuration/configuration.go b/configuration/configuration.go index 260391822..c21e12b05 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -105,13 +105,13 @@ type GlobalConfiguration struct { // WebCompatibility is a configuration to handle compatibility with deprecated web provider options type WebCompatibility struct { - Address string `description:"Web administration port" export:"true"` - CertFile string `description:"SSL certificate" export:"true"` - KeyFile string `description:"SSL certificate" export:"true"` - ReadOnly bool `description:"Enable read only API" export:"true"` - Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"` - Metrics *types.Metrics `description:"Enable a metrics exporter" export:"true"` - Path string `description:"Root path for dashboard and API" export:"true"` + Address string `description:"(Deprecated) Web administration port" export:"true"` + CertFile string `description:"(Deprecated) SSL certificate" export:"true"` + KeyFile string `description:"(Deprecated) SSL certificate" export:"true"` + ReadOnly bool `description:"(Deprecated) Enable read only API" export:"true"` + Statistics *types.Statistics `description:"(Deprecated) Enable more detailed statistics" export:"true"` + Metrics *types.Metrics `description:"(Deprecated) Enable a metrics exporter" export:"true"` + Path string `description:"(Deprecated) Root path for dashboard and API" export:"true"` Auth *types.Auth `export:"true"` Debug bool `export:"true"` } From a2a0c80acbdbecfb5150d76988cc791157cae991 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 14 May 2018 10:18:03 +0200 Subject: [PATCH 6/9] Fix segment backend name --- docs/configuration/backends/docker.md | 2 +- docs/configuration/backends/marathon.md | 2 +- docs/configuration/backends/rancher.md | 2 +- provider/docker/config.go | 2 +- provider/docker/config_segment_test.go | 2 +- provider/docker/deprecated_service.go | 2 +- provider/docker/deprecated_service_test.go | 4 ++-- provider/label/label.go | 6 +----- provider/label/names.go | 2 -- provider/rancher/config.go | 2 +- 10 files changed, 10 insertions(+), 16 deletions(-) diff --git a/docs/configuration/backends/docker.md b/docs/configuration/backends/docker.md index 006de85dd..da9ef6d4c 100644 --- a/docs/configuration/backends/docker.md +++ b/docs/configuration/backends/docker.md @@ -284,12 +284,12 @@ Segment labels override the default behavior. | Label | Description | |---------------------------------------------------------------------------|-------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | | `traefik..domain=DOMAIN` | Same as `traefik.domain` | | `traefik..port=PORT` | Same as `traefik.port` | | `traefik..protocol=http` | Same as `traefik.protocol` | | `traefik..weight=10` | Same as `traefik.weight` | | `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.backend=BACKEND` | Same as `traefik.frontend.backend` | | `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | | `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | | `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | diff --git a/docs/configuration/backends/marathon.md b/docs/configuration/backends/marathon.md index 1e5268795..84ba2c5f6 100644 --- a/docs/configuration/backends/marathon.md +++ b/docs/configuration/backends/marathon.md @@ -255,13 +255,13 @@ Segment labels override the default behavior. | Label | Description | |---------------------------------------------------------------------------|-------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | | `traefik..domain=DOMAIN` | Same as `traefik.domain` | | `traefik..portIndex=1` | Same as `traefik.portIndex` | | `traefik..port=PORT` | Same as `traefik.port` | | `traefik..protocol=http` | Same as `traefik.protocol` | | `traefik..weight=10` | Same as `traefik.weight` | | `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.backend=BACKEND` | Same as `traefik.frontend.backend` | | `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | | `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | | `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | diff --git a/docs/configuration/backends/rancher.md b/docs/configuration/backends/rancher.md index 0954ba34a..e9e566ead 100644 --- a/docs/configuration/backends/rancher.md +++ b/docs/configuration/backends/rancher.md @@ -222,12 +222,12 @@ Segment labels override the default behavior. | Label | Description | |---------------------------------------------------------------------------|-------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | | `traefik..domain=DOMAIN` | Same as `traefik.domain` | | `traefik..port=PORT` | Same as `traefik.port` | | `traefik..protocol=http` | Same as `traefik.protocol` | | `traefik..weight=10` | Same as `traefik.weight` | | `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.backend=BACKEND` | Same as `traefik.frontend.backend` | | `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | | `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | | `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | diff --git a/provider/docker/config.go b/provider/docker/config.go index 6e3421812..7ee1e2c76 100644 --- a/provider/docker/config.go +++ b/provider/docker/config.go @@ -262,7 +262,7 @@ func isBackendLBSwarm(container dockerData) bool { } func getSegmentBackendName(container dockerData) string { - if value := label.GetStringValue(container.SegmentLabels, label.TraefikFrontendBackend, ""); len(value) > 0 { + if value := label.GetStringValue(container.SegmentLabels, label.TraefikBackend, ""); len(value) > 0 { return provider.Normalize(container.ServiceName + "-" + value) } diff --git a/provider/docker/config_segment_test.go b/provider/docker/config_segment_test.go index 02e6c6311..caeeaee82 100644 --- a/provider/docker/config_segment_test.go +++ b/provider/docker/config_segment_test.go @@ -251,7 +251,7 @@ func TestSegmentBuildConfiguration(t *testing.T) { "traefik.sauternes.port": "2503", "traefik.sauternes.protocol": "https", "traefik.sauternes.weight": "80", - "traefik.sauternes.frontend.backend": "foobar", + "traefik.sauternes.backend": "foobar", "traefik.sauternes.frontend.passHostHeader": "false", "traefik.sauternes.frontend.rule": "Path:/mypath", "traefik.sauternes.frontend.priority": "5000", diff --git a/provider/docker/deprecated_service.go b/provider/docker/deprecated_service.go index d6180d445..a709cf0d5 100644 --- a/provider/docker/deprecated_service.go +++ b/provider/docker/deprecated_service.go @@ -88,7 +88,7 @@ func extractServicePortV1(labelName string) []string { // Extract backend from labels for a given service and a given docker container // Deprecated func getServiceBackendNameV1(container dockerData, serviceName string) string { - if value, ok := getServiceLabelsV1(container, serviceName)[label.SuffixFrontendBackend]; ok { + if value, ok := getServiceLabelsV1(container, serviceName)[label.SuffixBackend]; ok { return provider.Normalize(container.ServiceName + "-" + value) } return provider.Normalize(container.ServiceName + "-" + getBackendNameV1(container) + "-" + serviceName) diff --git a/provider/docker/deprecated_service_test.go b/provider/docker/deprecated_service_test.go index 9d955b1dc..50c0a404c 100644 --- a/provider/docker/deprecated_service_test.go +++ b/provider/docker/deprecated_service_test.go @@ -162,7 +162,7 @@ func TestDockerServiceBuildConfigurationV1(t *testing.T) { "traefik.service.port": "2503", "traefik.service.protocol": "https", "traefik.service.weight": "80", - "traefik.service.frontend.backend": "foobar", + "traefik.service.backend": "foobar", "traefik.service.frontend.passHostHeader": "false", "traefik.service.frontend.rule": "Path:/mypath", "traefik.service.frontend.priority": "5000", @@ -595,7 +595,7 @@ func TestDockerGetServiceBackendNameV1(t *testing.T) { }, { container: containerJSON(labels(map[string]string{ - "traefik.myservice.frontend.backend": "custom-backend", + "traefik.myservice.backend": "custom-backend", })), expected: "fake-custom-backend", }, diff --git a/provider/label/label.go b/provider/label/label.go index 71f9e1a64..87bf950f8 100644 --- a/provider/label/label.go +++ b/provider/label/label.go @@ -27,11 +27,6 @@ const ( DefaultBackendMaxconnExtractorFunc = "request.host" DefaultBackendLoadbalancerStickinessCookieName = "" DefaultBackendHealthCheckPort = 0 - - // TODO need to be remove in extra-service-fabric - DefaultWeightInt = 1 // Deprecated - DefaultPassHostHeaderBool = true // Deprecated - DefaultFrontendPriorityInt = 0 // Deprecated ) var ( @@ -64,6 +59,7 @@ func GetBoolValue(labels map[string]string, labelName string, defaultValue bool) if err == nil { return v } + log.Errorf("Unable to parse %q: %q, falling back to %v. %v", labelName, rawValue, defaultValue, err) } return defaultValue } diff --git a/provider/label/names.go b/provider/label/names.go index ae0aaaede..e23f9a087 100644 --- a/provider/label/names.go +++ b/provider/label/names.go @@ -32,7 +32,6 @@ const ( SuffixBackendBufferingRetryExpression = SuffixBackendBuffering + ".retryExpression" SuffixFrontend = "frontend" SuffixFrontendAuthBasic = "frontend.auth.basic" - SuffixFrontendBackend = "frontend.backend" SuffixFrontendEntryPoints = "frontend.entryPoints" SuffixFrontendHeaders = "frontend.headers." SuffixFrontendRequestHeaders = SuffixFrontendHeaders + "customRequestHeaders" @@ -98,7 +97,6 @@ const ( TraefikBackendBufferingRetryExpression = Prefix + SuffixBackendBufferingRetryExpression TraefikFrontend = Prefix + SuffixFrontend TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic - TraefikFrontendBackend = Prefix + SuffixFrontendBackend TraefikFrontendEntryPoints = Prefix + SuffixFrontendEntryPoints TraefikFrontendPassHostHeader = Prefix + SuffixFrontendPassHostHeader TraefikFrontendPassTLSCert = Prefix + SuffixFrontendPassTLSCert diff --git a/provider/rancher/config.go b/provider/rancher/config.go index 6b59ca9fd..255850fe6 100644 --- a/provider/rancher/config.go +++ b/provider/rancher/config.go @@ -150,7 +150,7 @@ func getBackendName(service rancherData) string { } func getSegmentBackendName(service rancherData) string { - if value := label.GetStringValue(service.SegmentLabels, label.TraefikFrontendBackend, ""); len(value) > 0 { + if value := label.GetStringValue(service.SegmentLabels, label.TraefikBackend, ""); len(value) > 0 { return provider.Normalize(service.Name + "-" + value) } From 67847c3117a20137442ee4dc00dc6497ecb24db5 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 14 May 2018 10:38:03 +0200 Subject: [PATCH 7/9] Error when accesslog and error pages --- middlewares/accesslog/logger.go | 18 ++++++++++++------ middlewares/accesslog/save_backend.go | 2 -- middlewares/errorpages/error_pages.go | 3 ++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/middlewares/accesslog/logger.go b/middlewares/accesslog/logger.go index 4754d7bba..f0480fc4d 100644 --- a/middlewares/accesslog/logger.go +++ b/middlewares/accesslog/logger.go @@ -101,19 +101,25 @@ func openAccessLogFile(filePath string) (*os.File, error) { return file, nil } -// GetLogDataTable gets the request context object that contains logging data. This accretes -// data as the request passes through the middleware chain. +// GetLogDataTable gets the request context object that contains logging data. +// This creates data as the request passes through the middleware chain. func GetLogDataTable(req *http.Request) *LogData { - return req.Context().Value(DataTableKey).(*LogData) + if ld, ok := req.Context().Value(DataTableKey).(*LogData); ok { + return ld + } + log.Errorf("%s is nil", DataTableKey) + return &LogData{Core: make(CoreLogData)} } func (l *LogHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.HandlerFunc) { now := time.Now().UTC() - core := make(CoreLogData) + + core := CoreLogData{ + StartUTC: now, + StartLocal: now.Local(), + } logDataTable := &LogData{Core: core, Request: req.Header} - core[StartUTC] = now - core[StartLocal] = now.Local() reqWithDataTable := req.WithContext(context.WithValue(req.Context(), DataTableKey, logDataTable)) diff --git a/middlewares/accesslog/save_backend.go b/middlewares/accesslog/save_backend.go index 353adbe71..674656a86 100644 --- a/middlewares/accesslog/save_backend.go +++ b/middlewares/accesslog/save_backend.go @@ -43,8 +43,6 @@ func (sb *SaveBackend) ServeHTTP(rw http.ResponseWriter, r *http.Request) { table.Core[OriginContentSize] = crw.Size() } -//------------------------------------------------------------------------------------------------- - // SaveFrontend sends the frontend name to the logger. These are sometimes used with a corresponding // SaveBackend handler, but not always. For example, redirected requests don't reach a backend. type SaveFrontend struct { diff --git a/middlewares/errorpages/error_pages.go b/middlewares/errorpages/error_pages.go index d73aa1eb0..dc460dbb6 100644 --- a/middlewares/errorpages/error_pages.go +++ b/middlewares/errorpages/error_pages.go @@ -99,7 +99,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request, next http. utils.CopyHeaders(pageReq.Header, req.Header) utils.CopyHeaders(w.Header(), recorder.Header()) w.WriteHeader(recorder.GetCode()) - h.backendHandler.ServeHTTP(w, pageReq) + + h.backendHandler.ServeHTTP(w, pageReq.WithContext(req.Context())) return } } From b72937e8fb56c9bbb78049154c4f3086141cc4bd Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 14 May 2018 19:46:03 +0200 Subject: [PATCH 8/9] Fix webui --- webui/.angular-cli.json | 4 +- webui/package.json | 2 +- webui/src/app.sass | 27 + webui/src/app/app.component.spec.ts | 2 +- webui/src/app/app.module.ts | 32 +- .../charts/bar-chart/bar-chart.component.ts | 51 +- .../line-chart/line-chart.component.html | 2 +- .../charts/line-chart/line-chart.component.ts | 87 ++- .../components/header/header.component.html | 38 +- .../app/components/header/header.component.ts | 1 + .../components/health/health.component.html | 12 +- .../app/components/health/health.component.ts | 40 +- .../providers/providers.component.html | 590 +++++++++--------- .../providers/providers.component.ts | 41 +- webui/src/app/directives/let.directive.ts | 21 + webui/src/app/pipes/backend.filter.pipe.ts | 17 + webui/src/app/pipes/frontend.filter.pipe.ts | 18 + webui/src/app/pipes/keys.pipe.ts | 4 +- webui/src/app/services/api.service.ts | 67 +- webui/src/styles/app.sass | 25 +- webui/src/styles/charts.sass | 6 - webui/src/styles/content.sass | 67 +- webui/src/styles/label.sass | 29 - webui/src/styles/message.sass | 98 ++- webui/src/styles/nav.sass | 6 +- webui/src/styles/typography.sass | 12 +- webui/src/styles/variables.sass | 1 + webui/yarn.lock | 6 +- 28 files changed, 696 insertions(+), 610 deletions(-) create mode 100644 webui/src/app.sass create mode 100644 webui/src/app/directives/let.directive.ts create mode 100644 webui/src/app/pipes/backend.filter.pipe.ts create mode 100644 webui/src/app/pipes/frontend.filter.pipe.ts delete mode 100644 webui/src/styles/label.sass create mode 100644 webui/src/styles/variables.sass diff --git a/webui/.angular-cli.json b/webui/.angular-cli.json index 145265719..dc1419956 100644 --- a/webui/.angular-cli.json +++ b/webui/.angular-cli.json @@ -8,7 +8,7 @@ "root": "src", "outDir": "dist", "assets": [ - "assets", + "assets/images", "favicon.ico" ], "index": "index.html", @@ -19,7 +19,7 @@ "testTsconfig": "tsconfig.spec.json", "prefix": "app", "styles": [ - "styles/app.sass" + "app.sass" ], "scripts": [ "../node_modules/@fortawesome/fontawesome/index.js", diff --git a/webui/package.json b/webui/package.json index 9dec23f21..b52a59d60 100644 --- a/webui/package.json +++ b/webui/package.json @@ -27,7 +27,7 @@ "@angular/router": "^5.2.0", "@fortawesome/fontawesome": "^1.1.5", "@fortawesome/fontawesome-free-solid": "^5.0.10", - "bulma": "^0.6.2", + "bulma": "^0.7.0", "core-js": "^2.4.1", "d3": "^4.13.0", "date-fns": "^1.29.0", diff --git a/webui/src/app.sass b/webui/src/app.sass new file mode 100644 index 000000000..64a380502 --- /dev/null +++ b/webui/src/app.sass @@ -0,0 +1,27 @@ +@charset "utf-8" + +@import 'styles/typography' +@import 'styles/variables' +@import 'styles/colors' +@import '~bulma/sass/utilities/all' +@import '~bulma/sass/base/all' +@import '~bulma/sass/grid/all' +@import '~bulma/sass/elements/container' +@import '~bulma/sass/elements/tag' +@import '~bulma/sass/elements/other' +@import '~bulma/sass/elements/box' +@import '~bulma/sass/elements/form' +@import '~bulma/sass/elements/table' +@import '~bulma/sass/components/navbar' +@import '~bulma/sass/components/tabs' +@import '~bulma/sass/elements/notification' +@import 'styles/nav' +@import 'styles/content' +@import 'styles/message' +@import 'styles/charts' +@import 'styles/helper' + +html + font-family: $open-sans + height: 100% + background: $background diff --git a/webui/src/app/app.component.spec.ts b/webui/src/app/app.component.spec.ts index 16c7679ce..8836204f4 100644 --- a/webui/src/app/app.component.spec.ts +++ b/webui/src/app/app.component.spec.ts @@ -1,4 +1,4 @@ -import { TestBed, async } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; describe('AppComponent', () => { diff --git a/webui/src/app/app.module.ts b/webui/src/app/app.module.ts index a544f385f..c9ba2741a 100644 --- a/webui/src/app/app.module.ts +++ b/webui/src/app/app.module.ts @@ -1,18 +1,21 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; -import { RouterModule } from '@angular/router'; import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; +import { AppComponent } from './app.component'; +import { BarChartComponent } from './charts/bar-chart/bar-chart.component'; +import { LineChartComponent } from './charts/line-chart/line-chart.component'; +import { HeaderComponent } from './components/header/header.component'; +import { HealthComponent } from './components/health/health.component'; +import { ProvidersComponent } from './components/providers/providers.component'; +import { LetDirective } from './directives/let.directive'; +import { BackendFilterPipe } from './pipes/backend.filter.pipe'; +import { FrontendFilterPipe } from './pipes/frontend.filter.pipe'; +import { KeysPipe } from './pipes/keys.pipe'; import { ApiService } from './services/api.service'; import { WindowService } from './services/window.service'; -import { AppComponent } from './app.component'; -import { HeaderComponent } from './components/header/header.component'; -import { ProvidersComponent } from './components/providers/providers.component'; -import { HealthComponent } from './components/health/health.component'; -import { LineChartComponent } from './charts/line-chart/line-chart.component'; -import { BarChartComponent } from './charts/bar-chart/bar-chart.component'; -import { KeysPipe } from './pipes/keys.pipe'; @NgModule({ declarations: [ @@ -22,7 +25,10 @@ import { KeysPipe } from './pipes/keys.pipe'; HealthComponent, LineChartComponent, BarChartComponent, - KeysPipe + KeysPipe, + FrontendFilterPipe, + BackendFilterPipe, + LetDirective ], imports: [ BrowserModule, @@ -30,8 +36,8 @@ import { KeysPipe } from './pipes/keys.pipe'; HttpClientModule, FormsModule, RouterModule.forRoot([ - { path: '', component: ProvidersComponent, pathMatch: 'full' }, - { path: 'status', component: HealthComponent } + {path: '', component: ProvidersComponent, pathMatch: 'full'}, + {path: 'status', component: HealthComponent} ]) ], providers: [ diff --git a/webui/src/app/charts/bar-chart/bar-chart.component.ts b/webui/src/app/charts/bar-chart/bar-chart.component.ts index 8d130c4fb..47946d9ae 100644 --- a/webui/src/app/charts/bar-chart/bar-chart.component.ts +++ b/webui/src/app/charts/bar-chart/bar-chart.component.ts @@ -1,15 +1,7 @@ -import { Component, Input, OnInit, ElementRef, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { axisBottom, axisLeft, easeLinear, max, min, scaleBand, scaleLinear, select } from 'd3'; +import * as _ from 'lodash'; import { WindowService } from '../../services/window.service'; -import { - min, - max, - easeLinear, - select, - axisLeft, - axisBottom, - scaleBand, - scaleLinear -} from 'd3'; @Component({ selector: 'app-bar-chart', @@ -23,12 +15,12 @@ export class BarChartComponent implements OnInit, OnChanges { x: any; y: any; g: any; - bars: any; width: number; height: number; - margin = { top: 40, right: 40, bottom: 40, left: 40 }; + margin = {top: 40, right: 40, bottom: 40, left: 40}; loading: boolean; data: any[]; + previousData: any[]; constructor(public elementRef: ElementRef, public windowService: WindowService) { this.loading = true; @@ -37,7 +29,7 @@ export class BarChartComponent implements OnInit, OnChanges { ngOnInit() { this.barChartEl = this.elementRef.nativeElement.querySelector('.bar-chart'); this.setup(); - setTimeout(() => this.loading = false, 4000); + setTimeout(() => this.loading = false, 1000); this.windowService.resize.subscribe(w => this.draw()); } @@ -47,15 +39,20 @@ export class BarChartComponent implements OnInit, OnChanges { return; } - this.data = this.value; - this.draw(); + if (!_.isEqual(this.previousData, this.value)) { + this.previousData = _.cloneDeep(this.value); + this.data = this.value; + + this.draw(); + } } setup(): void { this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right; this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom; - this.svg = select(this.barChartEl).append('svg') + this.svg = select(this.barChartEl) + .append('svg') .attr('width', this.width + this.margin.left + this.margin.right) .attr('height', this.height + this.margin.top + this.margin.bottom); @@ -73,11 +70,16 @@ export class BarChartComponent implements OnInit, OnChanges { } draw(): void { + if (this.barChartEl.clientWidth === 0 || this.barChartEl.clientHeight === 0) { + this.previousData = []; + } else { + this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right; + this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom; + } + this.x.domain(this.data.map((d: any) => d.code)); this.y.domain([0, max(this.data, (d: any) => d.count)]); - this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right; - this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom; this.svg .attr('width', this.width + this.margin.left + this.margin.right) @@ -93,17 +95,16 @@ export class BarChartComponent implements OnInit, OnChanges { this.g.select('.axis--y') .call(axisLeft(this.y).tickSize(-this.width)); + // Clean previous graph + this.g.selectAll('.bar').remove(); + const bars = this.g.selectAll('.bar').data(this.data); bars.enter() .append('rect') .attr('class', 'bar') - .attr('x', (d: any) => d.code) - .attr('y', (d: any) => d.count) - .attr('width', this.x.bandwidth()) - .attr('height', (d: any) => (this.height - this.y(d.count)) < 0 ? 0 : this.height - this.y(d.count)); - - bars.attr('x', (d: any) => this.x(d.code)) + .style('fill', (d: any) => 'hsl(' + Math.floor(((d.code - 100) * 310 / 427) + 50) + ', 50%, 50%)') + .attr('x', (d: any) => this.x(d.code)) .attr('y', (d: any) => this.y(d.count)) .attr('width', this.x.bandwidth()) .attr('height', (d: any) => (this.height - this.y(d.count)) < 0 ? 0 : this.height - this.y(d.count)); diff --git a/webui/src/app/charts/line-chart/line-chart.component.html b/webui/src/app/charts/line-chart/line-chart.component.html index 929411c3e..f216459d8 100644 --- a/webui/src/app/charts/line-chart/line-chart.component.html +++ b/webui/src/app/charts/line-chart/line-chart.component.html @@ -1,5 +1,5 @@
-
+
Loading, please wait... diff --git a/webui/src/app/charts/line-chart/line-chart.component.ts b/webui/src/app/charts/line-chart/line-chart.component.ts index 92fc7c0cd..e07f132ea 100644 --- a/webui/src/app/charts/line-chart/line-chart.component.ts +++ b/webui/src/app/charts/line-chart/line-chart.component.ts @@ -1,20 +1,20 @@ -import { Component, Input, OnInit, ElementRef, OnChanges, SimpleChanges } from '@angular/core'; -import { WindowService } from '../../services/window.service'; +import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { - range, - scaleTime, - scaleLinear, - min, - max, - curveLinear, - line, - easeLinear, - select, - axisLeft, axisBottom, - timeSecond, - timeFormat + axisLeft, + curveLinear, + easeLinear, + line, + max, + min, + range, + scaleLinear, + scaleTime, + select, + timeFormat, + timeSecond } from 'd3'; +import { WindowService } from '../../services/window.service'; @Component({ selector: 'app-line-chart', @@ -23,7 +23,10 @@ import { export class LineChartComponent implements OnChanges, OnInit { @Input() value: { count: number, date: string }; + firstDisplay: boolean; + dirty: boolean; lineChartEl: HTMLElement; + loadingEl: HTMLElement; svg: any; g: any; line: any; @@ -39,15 +42,19 @@ export class LineChartComponent implements OnChanges, OnInit { yAxis: any; height: number; width: number; - margin = { top: 40, right: 40, bottom: 60, left: 60 }; + margin = {top: 40, right: 40, bottom: 60, left: 60}; loading = true; constructor(private elementRef: ElementRef, public windowService: WindowService) { } ngOnInit() { this.lineChartEl = this.elementRef.nativeElement.querySelector('.line-chart'); + this.loadingEl = this.elementRef.nativeElement.querySelector('.line-chart-loading'); this.limit = 40; + + // related to the Observable.timer(0, 3000) in health component this.duration = 3000; + this.now = new Date(Date.now() - this.duration); this.options = { @@ -55,22 +62,37 @@ export class LineChartComponent implements OnChanges, OnInit { color: '#3A84C5' }; + this.firstDisplay = true; this.render(); - setTimeout(() => this.loading = false, 4000); + this.windowService.resize.subscribe(w => { if (this.svg) { - const el = this.lineChartEl.querySelector('svg'); - el.parentNode.removeChild(el); + this.dirty = true; + this.loading = true; this.render(); } }); } render() { - this.width = this.lineChartEl.clientWidth - this.margin.left - this.margin.right; - this.height = this.lineChartEl.clientHeight - this.margin.top - this.margin.bottom; + // When the lineChartEl is not displayed (is-hidden), width and length are equal to 0. + let elt; + if (this.lineChartEl.clientWidth === 0 || this.lineChartEl.clientHeight === 0) { + elt = this.loadingEl; + } else { + elt = this.lineChartEl; + } + this.width = elt.clientWidth - this.margin.left - this.margin.right; + this.height = elt.clientHeight - this.margin.top - this.margin.bottom; - this.svg = select(this.lineChartEl).append('svg') + + const el = this.lineChartEl.querySelector('svg'); + if (el) { + el.parentNode.removeChild(el); + } + + this.svg = select(this.lineChartEl) + .append('svg') .attr('width', this.width + this.margin.left + this.margin.right) .attr('height', this.height + this.margin.top + this.margin.bottom) .append('g') @@ -80,7 +102,7 @@ export class LineChartComponent implements OnChanges, OnInit { this.data = range(this.limit).map(i => 0); } - this.x = scaleTime().range([0, this.width]); + this.x = scaleTime().range([0, this.width - 10]); this.y = scaleLinear().range([this.height, 0]); this.x.domain([this.now - (this.limit - 2), this.now - this.duration]); @@ -91,7 +113,9 @@ export class LineChartComponent implements OnChanges, OnInit { .y((d: any) => this.y(d)) .curve(curveLinear); - this.svg.append('defs').append('clipPath') + this.svg + .append('defs') + .append('clipPath') .attr('id', 'clip') .append('rect') .attr('width', this.width) @@ -121,7 +145,7 @@ export class LineChartComponent implements OnChanges, OnInit { this.updateData(this.value.count); } - updateData = (value: number) => { + updateData(value: number) { this.data.push(value * 1000000); this.now = new Date(); @@ -132,9 +156,13 @@ export class LineChartComponent implements OnChanges, OnInit { this.xAxis .transition() - .duration(this.duration) + .duration(this.firstDisplay || this.dirty ? 0 : this.duration) .ease(easeLinear) - .call(axisBottom(this.x).tickSize(-this.height).ticks(timeSecond, 5).tickFormat(timeFormat('%H:%M:%S'))) + .call(axisBottom(this.x).tickSize(-this.height).ticks(timeSecond, 5).tickFormat(timeFormat('%H:%M:%S'))); + + this.xAxis + .transition() + .duration(0) .selectAll('text') .style('text-anchor', 'end') .attr('dx', '-.8em') @@ -157,6 +185,13 @@ export class LineChartComponent implements OnChanges, OnInit { .ease(easeLinear) .attr('transform', `translate(${this.x(this.now - (this.limit - 1) * this.duration)})`); + this.firstDisplay = false; + this.dirty = false; + + if (this.loading) { + this.loading = false; + } + this.data.shift(); } } diff --git a/webui/src/app/components/header/header.component.html b/webui/src/app/components/header/header.component.html index 46fc6d6a3..7254a8afb 100644 --- a/webui/src/app/components/header/header.component.html +++ b/webui/src/app/components/header/header.component.html @@ -1,22 +1,27 @@ -