From 9ab5cbf235d78a432c4b4f800ccab6c57d3fcc1e Mon Sep 17 00:00:00 2001 From: Manfred Dreese Date: Fri, 21 Sep 2018 16:44:02 +0200 Subject: [PATCH 01/23] Removed non-applicable default tests and fixed custom tests --- webui/src/app/app.component.spec.ts | 18 +++++------------- .../bar-chart/bar-chart.component.spec.ts | 10 ++++++++-- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/webui/src/app/app.component.spec.ts b/webui/src/app/app.component.spec.ts index 8836204f4..75f4560b9 100644 --- a/webui/src/app/app.component.spec.ts +++ b/webui/src/app/app.component.spec.ts @@ -1,5 +1,6 @@ import { async, TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; describe('AppComponent', () => { @@ -8,6 +9,9 @@ describe('AppComponent', () => { declarations: [ AppComponent ], + schemas: [ + CUSTOM_ELEMENTS_SCHEMA + ] }).compileComponents(); })); @@ -16,17 +20,5 @@ describe('AppComponent', () => { const app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); })); - - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app.title).toEqual('app'); - })); - - it('should render title in a h1 tag', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); + }); diff --git a/webui/src/app/charts/bar-chart/bar-chart.component.spec.ts b/webui/src/app/charts/bar-chart/bar-chart.component.spec.ts index c4d89509b..98d809215 100644 --- a/webui/src/app/charts/bar-chart/bar-chart.component.spec.ts +++ b/webui/src/app/charts/bar-chart/bar-chart.component.spec.ts @@ -1,6 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { BarChartComponent } from './bar-chart.component'; +import { WindowService } from '../../services/window.service'; describe('BarChartComponent', () => { let component: BarChartComponent; @@ -8,7 +9,8 @@ describe('BarChartComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ BarChartComponent ] + declarations: [ BarChartComponent ], + providers: [{provide: WindowService, useInstance: {}}] }) .compileComponents(); })); @@ -16,10 +18,14 @@ describe('BarChartComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(BarChartComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); + + it('should initially go to loading state', () => { + expect(component.loading).toBeTruthy() + }); + }); From 38d655636dc1ee2473447e3ffd563bec6b25476a Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Fri, 21 Sep 2018 18:38:02 +0200 Subject: [PATCH 02/23] Fix some DNS providers issues --- Gopkg.lock | 2 +- vendor/github.com/xenolf/lego/acme/client.go | 2 +- .../xenolf/lego/acme/dns_challenge.go | 6 +++- vendor/github.com/xenolf/lego/log/logger.go | 12 +++++++- .../xenolf/lego/providers/dns/azure/azure.go | 10 +++++-- .../lego/providers/dns/gcloud/googlecloud.go | 28 +++++++++++++------ .../xenolf/lego/providers/dns/iij/iij.go | 10 +++++-- .../xenolf/lego/providers/dns/ns1/ns1.go | 22 ++++++--------- 8 files changed, 62 insertions(+), 30 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 111a16957..10f86227c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1371,7 +1371,7 @@ "providers/dns/vegadns", "providers/dns/vultr" ] - revision = "83e2300e01226dcb006946873ca5434291fb16ef" + revision = "621237d07213aa6dead90bdf6fd46251220fa669" [[projects]] branch = "master" diff --git a/vendor/github.com/xenolf/lego/acme/client.go b/vendor/github.com/xenolf/lego/acme/client.go index 72e5f63f4..12fd5b37a 100644 --- a/vendor/github.com/xenolf/lego/acme/client.go +++ b/vendor/github.com/xenolf/lego/acme/client.go @@ -593,7 +593,7 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error { } } - // for all valid presolvers, first submit the challenges so they have max time to propigate + // for all valid presolvers, first submit the challenges so they have max time to propagate for _, item := range authSolvers { authz := item.authz i := item.challengeIndex diff --git a/vendor/github.com/xenolf/lego/acme/dns_challenge.go b/vendor/github.com/xenolf/lego/acme/dns_challenge.go index 739566251..630940647 100644 --- a/vendor/github.com/xenolf/lego/acme/dns_challenge.go +++ b/vendor/github.com/xenolf/lego/acme/dns_challenge.go @@ -30,6 +30,9 @@ const ( // DefaultPollingInterval default polling interval DefaultPollingInterval = 2 * time.Second + + // DefaultTTL default TTL + DefaultTTL = 120 ) var defaultNameservers = []string{ @@ -67,7 +70,7 @@ func DNS01Record(domain, keyAuth string) (fqdn string, value string, ttl int) { keyAuthShaBytes := sha256.Sum256([]byte(keyAuth)) // base64URL encoding without padding value = base64.RawURLEncoding.EncodeToString(keyAuthShaBytes[:sha256.Size]) - ttl = 120 + ttl = DefaultTTL fqdn = fmt.Sprintf("_acme-challenge.%s.", domain) return } @@ -149,6 +152,7 @@ func checkDNSPropagation(fqdn, value string) (bool, error) { if err != nil { return false, err } + if r.Rcode == dns.RcodeSuccess { // If we see a CNAME here then use the alias for _, rr := range r.Answer { diff --git a/vendor/github.com/xenolf/lego/log/logger.go b/vendor/github.com/xenolf/lego/log/logger.go index 101a2c993..22ec98f0a 100644 --- a/vendor/github.com/xenolf/lego/log/logger.go +++ b/vendor/github.com/xenolf/lego/log/logger.go @@ -6,7 +6,17 @@ import ( ) // Logger is an optional custom logger. -var Logger = log.New(os.Stdout, "", log.LstdFlags) +var Logger StdLogger = log.New(os.Stdout, "", log.LstdFlags) + +// StdLogger interface for Standard Logger. +type StdLogger interface { + Fatal(args ...interface{}) + Fatalln(args ...interface{}) + Fatalf(format string, args ...interface{}) + Print(args ...interface{}) + Println(args ...interface{}) + Printf(format string, args ...interface{}) +} // Fatal writes a log entry. // It uses Logger if not nil, otherwise it uses the default log.Logger. diff --git a/vendor/github.com/xenolf/lego/providers/dns/azure/azure.go b/vendor/github.com/xenolf/lego/providers/dns/azure/azure.go index 7f1569930..8012aa659 100644 --- a/vendor/github.com/xenolf/lego/providers/dns/azure/azure.go +++ b/vendor/github.com/xenolf/lego/providers/dns/azure/azure.go @@ -127,7 +127,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { } _, err = rsc.CreateOrUpdate(ctx, d.config.ResourceGroup, zone, relative, dns.TXT, rec, "", "") - return fmt.Errorf("azure: %v", err) + if err != nil { + return fmt.Errorf("azure: %v", err) + } + return nil } // CleanUp removes the TXT record matching the specified parameters @@ -150,7 +153,10 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { rsc.Authorizer = autorest.NewBearerAuthorizer(spt) _, err = rsc.Delete(ctx, d.config.ResourceGroup, zone, relative, dns.TXT, "") - return fmt.Errorf("azure: %v", err) + if err != nil { + return fmt.Errorf("azure: %v", err) + } + return nil } // Checks that azure has a zone for this domain name. diff --git a/vendor/github.com/xenolf/lego/providers/dns/gcloud/googlecloud.go b/vendor/github.com/xenolf/lego/providers/dns/gcloud/googlecloud.go index 36e067a59..d8df7071d 100644 --- a/vendor/github.com/xenolf/lego/providers/dns/gcloud/googlecloud.go +++ b/vendor/github.com/xenolf/lego/providers/dns/gcloud/googlecloud.go @@ -131,26 +131,33 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { return fmt.Errorf("googlecloud: %v", err) } + // Look for existing records. + existing, err := d.findTxtRecords(zone, fqdn) + if err != nil { + return fmt.Errorf("googlecloud: %v", err) + } + rec := &dns.ResourceRecordSet{ Name: fqdn, Rrdatas: []string{value}, Ttl: int64(d.config.TTL), Type: "TXT", } - change := &dns.Change{ - Additions: []*dns.ResourceRecordSet{rec}, - } - // Look for existing records. - existing, err := d.findTxtRecords(zone, fqdn) - if err != nil { - return fmt.Errorf("googlecloud: %v", err) - } + change := &dns.Change{} + if len(existing) > 0 { // Attempt to delete the existing records when adding our new one. change.Deletions = existing + + // Append existing TXT record data to the new TXT record data + for _, value := range existing { + rec.Rrdatas = append(rec.Rrdatas, value.Rrdatas...) + } } + change.Additions = []*dns.ResourceRecordSet{rec} + chg, err := d.client.Changes.Create(d.config.Project, zone, change).Do() if err != nil { return fmt.Errorf("googlecloud: %v", err) @@ -188,7 +195,10 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { } _, err = d.client.Changes.Create(d.config.Project, zone, &dns.Change{Deletions: records}).Do() - return fmt.Errorf("googlecloud: %v", err) + if err != nil { + return fmt.Errorf("googlecloud: %v", err) + } + return nil } // Timeout customizes the timeout values used by the ACME package for checking diff --git a/vendor/github.com/xenolf/lego/providers/dns/iij/iij.go b/vendor/github.com/xenolf/lego/providers/dns/iij/iij.go index 028e335d4..fc09f8638 100644 --- a/vendor/github.com/xenolf/lego/providers/dns/iij/iij.go +++ b/vendor/github.com/xenolf/lego/providers/dns/iij/iij.go @@ -76,7 +76,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { _, value, _ := acme.DNS01Record(domain, keyAuth) err := d.addTxtRecord(domain, value) - return fmt.Errorf("iij: %v", err) + if err != nil { + return fmt.Errorf("iij: %v", err) + } + return nil } // CleanUp removes the TXT record matching the specified parameters @@ -84,7 +87,10 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { _, value, _ := acme.DNS01Record(domain, keyAuth) err := d.deleteTxtRecord(domain, value) - return fmt.Errorf("iij: %v", err) + if err != nil { + return fmt.Errorf("iij: %v", err) + } + return nil } func (d *DNSProvider) addTxtRecord(domain, value string) error { diff --git a/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go b/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go index 40dff6c60..05397f27e 100644 --- a/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go +++ b/vendor/github.com/xenolf/lego/providers/dns/ns1/ns1.go @@ -85,7 +85,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { func (d *DNSProvider) Present(domain, token, keyAuth string) error { fqdn, value, _ := acme.DNS01Record(domain, keyAuth) - zone, err := d.getHostedZone(domain) + zone, err := d.getHostedZone(fqdn) if err != nil { return fmt.Errorf("ns1: %v", err) } @@ -93,7 +93,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { record := d.newTxtRecord(zone, fqdn, value, d.config.TTL) _, err = d.client.Records.Create(record) if err != nil && err != rest.ErrRecordExists { - return fmt.Errorf("ns1: %v", err) + return fmt.Errorf("ns1: failed to create record [zone: %q, fqdn: %q]: %v", zone.Zone, fqdn, err) } return nil @@ -103,14 +103,14 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { fqdn, _, _ := acme.DNS01Record(domain, keyAuth) - zone, err := d.getHostedZone(domain) + zone, err := d.getHostedZone(fqdn) if err != nil { return fmt.Errorf("ns1: %v", err) } name := acme.UnFqdn(fqdn) _, err = d.client.Records.Delete(zone.Zone, name, "TXT") - return fmt.Errorf("ns1: %v", err) + return fmt.Errorf("ns1: failed to delete record [zone: %q, domain: %q]: %v", zone.Zone, name, err) } // Timeout returns the timeout and interval to use when checking for DNS propagation. @@ -119,15 +119,15 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { return d.config.PropagationTimeout, d.config.PollingInterval } -func (d *DNSProvider) getHostedZone(domain string) (*dns.Zone, error) { - authZone, err := getAuthZone(domain) +func (d *DNSProvider) getHostedZone(fqdn string) (*dns.Zone, error) { + authZone, err := getAuthZone(fqdn) if err != nil { - return nil, fmt.Errorf("ns1: %v", err) + return nil, fmt.Errorf("failed to extract auth zone from fqdn %q: %v", fqdn, err) } zone, _, err := d.client.Zones.Get(authZone) if err != nil { - return nil, fmt.Errorf("ns1: %v", err) + return nil, fmt.Errorf("failed to get zone [authZone: %q, fqdn: %q]: %v", authZone, fqdn, err) } return zone, nil @@ -139,11 +139,7 @@ func getAuthZone(fqdn string) (string, error) { return "", err } - if strings.HasSuffix(authZone, ".") { - authZone = authZone[:len(authZone)-len(".")] - } - - return authZone, err + return strings.TrimSuffix(authZone, "."), nil } func (d *DNSProvider) newTxtRecord(zone *dns.Zone, fqdn, value string, ttl int) *dns.Record { From 1f1ecb15f6aa1f0355d56c95b990413bc67184a9 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 24 Sep 2018 10:04:03 +0200 Subject: [PATCH 03/23] Fix logger in Oxy --- Gopkg.lock | 2 +- vendor/github.com/vulcand/oxy/buffer/buffer.go | 6 +++--- vendor/github.com/vulcand/oxy/cbreaker/fallback.go | 4 ++-- vendor/github.com/vulcand/oxy/forward/fwd.go | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 10f86227c..fe8ee8cd4 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1298,7 +1298,7 @@ "roundrobin", "utils" ] - revision = "77148e9694210e5f5610328f1cd7cf65583014c2" + revision = "fe51048067db50958154cd4040da878b10002a3a" [[projects]] name = "github.com/vulcand/predicate" diff --git a/vendor/github.com/vulcand/oxy/buffer/buffer.go b/vendor/github.com/vulcand/oxy/buffer/buffer.go index 68b387925..08eb8b3e7 100644 --- a/vendor/github.com/vulcand/oxy/buffer/buffer.go +++ b/vendor/github.com/vulcand/oxy/buffer/buffer.go @@ -216,7 +216,7 @@ func (b *Buffer) ServeHTTP(w http.ResponseWriter, req *http.Request) { } if err := b.checkLimit(req); err != nil { - log.Errorf("vulcand/oxy/buffer: request body over limit, err: %v", err) + b.log.Errorf("vulcand/oxy/buffer: request body over limit, err: %v", err) b.errHandler.ServeHTTP(w, req, err) return } @@ -239,7 +239,7 @@ func (b *Buffer) ServeHTTP(w http.ResponseWriter, req *http.Request) { if body != nil { errClose := body.Close() if errClose != nil { - log.Errorf("vulcand/oxy/buffer: failed to close body, err: %v", errClose) + b.log.Errorf("vulcand/oxy/buffer: failed to close body, err: %v", errClose) } } }() @@ -417,7 +417,7 @@ func (b *bufferWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { return conn, rw, err } b.log.Warningf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(b.responseWriter)) - return nil, nil, fmt.Errorf("the response writer wrapped in this proxy does not implement http.Hijacker. Its type is: %v”", reflect.TypeOf(b.responseWriter)) + return nil, nil, fmt.Errorf("the response writer wrapped in this proxy does not implement http.Hijacker. Its type is: %v", reflect.TypeOf(b.responseWriter)) } // SizeErrHandler Size error handler diff --git a/vendor/github.com/vulcand/oxy/cbreaker/fallback.go b/vendor/github.com/vulcand/oxy/cbreaker/fallback.go index ea0655311..5c24548da 100644 --- a/vendor/github.com/vulcand/oxy/cbreaker/fallback.go +++ b/vendor/github.com/vulcand/oxy/cbreaker/fallback.go @@ -51,7 +51,7 @@ func (f *ResponseFallback) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.WriteHeader(f.r.StatusCode) _, err := w.Write(f.r.Body) if err != nil { - log.Errorf("vulcand/oxy/fallback/response: failed to write response, err: %v", err) + f.log.Errorf("vulcand/oxy/fallback/response: failed to write response, err: %v", err) } } @@ -100,6 +100,6 @@ func (f *RedirectFallback) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusFound) _, err := w.Write([]byte(http.StatusText(http.StatusFound))) if err != nil { - log.Errorf("vulcand/oxy/fallback/redirect: failed to write response, err: %v", err) + f.log.Errorf("vulcand/oxy/fallback/redirect: failed to write response, err: %v", err) } } diff --git a/vendor/github.com/vulcand/oxy/forward/fwd.go b/vendor/github.com/vulcand/oxy/forward/fwd.go index 5a8e81c77..e81ee89c2 100644 --- a/vendor/github.com/vulcand/oxy/forward/fwd.go +++ b/vendor/github.com/vulcand/oxy/forward/fwd.go @@ -349,17 +349,17 @@ func (f *httpForwarder) serveWebSocket(w http.ResponseWriter, req *http.Request, if resp == nil { ctx.errHandler.ServeHTTP(w, req, err) } else { - log.Errorf("vulcand/oxy/forward/websocket: Error dialing %q: %v with resp: %d %s", outReq.Host, err, resp.StatusCode, resp.Status) + f.log.Errorf("vulcand/oxy/forward/websocket: Error dialing %q: %v with resp: %d %s", outReq.Host, err, resp.StatusCode, resp.Status) hijacker, ok := w.(http.Hijacker) if !ok { - log.Errorf("vulcand/oxy/forward/websocket: %s can not be hijack", reflect.TypeOf(w)) + f.log.Errorf("vulcand/oxy/forward/websocket: %s can not be hijack", reflect.TypeOf(w)) ctx.errHandler.ServeHTTP(w, req, err) return } conn, _, errHijack := hijacker.Hijack() if errHijack != nil { - log.Errorf("vulcand/oxy/forward/websocket: Failed to hijack responseWriter") + f.log.Errorf("vulcand/oxy/forward/websocket: Failed to hijack responseWriter") ctx.errHandler.ServeHTTP(w, req, errHijack) return } @@ -367,7 +367,7 @@ func (f *httpForwarder) serveWebSocket(w http.ResponseWriter, req *http.Request, errWrite := resp.Write(conn) if errWrite != nil { - log.Errorf("vulcand/oxy/forward/websocket: Failed to forward response") + f.log.Errorf("vulcand/oxy/forward/websocket: Failed to forward response") ctx.errHandler.ServeHTTP(w, req, errWrite) return } @@ -385,7 +385,7 @@ func (f *httpForwarder) serveWebSocket(w http.ResponseWriter, req *http.Request, underlyingConn, err := upgrader.Upgrade(w, req, resp.Header) if err != nil { - log.Errorf("vulcand/oxy/forward/websocket: Error while upgrading connection : %v", err) + f.log.Errorf("vulcand/oxy/forward/websocket: Error while upgrading connection : %v", err) return } defer func() { From 29473ef356f1d56df2c507ea145c5d1df59c6f3d Mon Sep 17 00:00:00 2001 From: stffabi Date: Mon, 24 Sep 2018 10:42:03 +0200 Subject: [PATCH 04/23] Do not copy hop-by-hop headers to forward auth request --- middlewares/auth/forward.go | 1 + middlewares/auth/forward_test.go | 46 +++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/middlewares/auth/forward.go b/middlewares/auth/forward.go index 86c365e8c..5292c282c 100644 --- a/middlewares/auth/forward.go +++ b/middlewares/auth/forward.go @@ -105,6 +105,7 @@ func Forward(config *types.Forward, w http.ResponseWriter, r *http.Request, next func writeHeader(req *http.Request, forwardReq *http.Request, trustForwardHeader bool) { utils.CopyHeaders(forwardReq.Header, req.Header) + utils.RemoveHeaders(forwardReq.Header, forward.HopHeaders...) if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { if trustForwardHeader { diff --git a/middlewares/auth/forward_test.go b/middlewares/auth/forward_test.go index bf0ada6fb..a0364a030 100644 --- a/middlewares/auth/forward_test.go +++ b/middlewares/auth/forward_test.go @@ -231,11 +231,12 @@ func TestForwardAuthFailResponseHeaders(t *testing.T) { func Test_writeHeader(t *testing.T) { testCases := []struct { - name string - headers map[string]string - trustForwardHeader bool - emptyHost bool - expectedHeaders map[string]string + name string + headers map[string]string + trustForwardHeader bool + emptyHost bool + expectedHeaders map[string]string + checkForUnexpectedHeaders bool }{ { name: "trust Forward Header", @@ -334,6 +335,29 @@ func Test_writeHeader(t *testing.T) { "X-Forwarded-Method": "GET", }, }, + { + name: "remove hop-by-hop headers", + headers: map[string]string{ + forward.Connection: "Connection", + forward.KeepAlive: "KeepAlive", + forward.ProxyAuthenticate: "ProxyAuthenticate", + forward.ProxyAuthorization: "ProxyAuthorization", + forward.Te: "Te", + forward.Trailers: "Trailers", + forward.TransferEncoding: "TransferEncoding", + forward.Upgrade: "Upgrade", + "X-CustomHeader": "CustomHeader", + }, + trustForwardHeader: false, + expectedHeaders: map[string]string{ + "X-CustomHeader": "CustomHeader", + "X-Forwarded-Proto": "http", + "X-Forwarded-Host": "foo.bar", + "X-Forwarded-Uri": "/path?q=1", + "X-Forwarded-Method": "GET", + }, + checkForUnexpectedHeaders: true, + }, } for _, test := range testCases { @@ -352,8 +376,16 @@ func Test_writeHeader(t *testing.T) { writeHeader(req, forwardReq, test.trustForwardHeader) - for key, value := range test.expectedHeaders { - assert.Equal(t, value, forwardReq.Header.Get(key)) + actualHeaders := forwardReq.Header + expectedHeaders := test.expectedHeaders + for key, value := range expectedHeaders { + assert.Equal(t, value, actualHeaders.Get(key)) + actualHeaders.Del(key) + } + if test.checkForUnexpectedHeaders { + for key := range actualHeaders { + assert.Fail(t, "Unexpected header found", key) + } } }) } From 6a50a6fd5a1fa9c4c97fd95f615d9cda05806898 Mon Sep 17 00:00:00 2001 From: Manfred Dreese Date: Mon, 24 Sep 2018 11:20:03 +0200 Subject: [PATCH 05/23] Added Dashboard table item for Rate Limits --- webui/src/app/app.module.ts | 2 + .../providers/providers.component.html | 35 ++++++++++++++ .../pipes/humanreadable.filter.pipe.spec.ts | 46 +++++++++++++++++++ .../app/pipes/humanreadable.filter.pipe.ts | 27 +++++++++++ webui/src/app/services/api.service.ts | 3 ++ 5 files changed, 113 insertions(+) create mode 100644 webui/src/app/pipes/humanreadable.filter.pipe.spec.ts create mode 100644 webui/src/app/pipes/humanreadable.filter.pipe.ts diff --git a/webui/src/app/app.module.ts b/webui/src/app/app.module.ts index c9ba2741a..c9f573855 100644 --- a/webui/src/app/app.module.ts +++ b/webui/src/app/app.module.ts @@ -13,6 +13,7 @@ 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 { HumanReadableFilterPipe } from './pipes/humanreadable.filter.pipe'; import { KeysPipe } from './pipes/keys.pipe'; import { ApiService } from './services/api.service'; import { WindowService } from './services/window.service'; @@ -28,6 +29,7 @@ import { WindowService } from './services/window.service'; KeysPipe, FrontendFilterPipe, BackendFilterPipe, + HumanReadableFilterPipe, LetDirective ], imports: [ diff --git a/webui/src/app/components/providers/providers.component.html b/webui/src/app/components/providers/providers.component.html index bcf9df5e5..72fa96973 100644 --- a/webui/src/app/components/providers/providers.component.html +++ b/webui/src/app/components/providers/providers.component.html @@ -435,6 +435,41 @@ + +
+
+
+
+
+

Rate Limiting

+
+
+
+
+ Extractor Function + {{ p.ratelimit.extractorFunc }} +
+
+ + + + + + + + + + + + + + + +
RatesetPeriodAverageBurst
{{rateset.id}}{{rateset.period | humanreadable}}{{rateset.average}}{{rateset.burst}}
+
+
+
+
diff --git a/webui/src/app/pipes/humanreadable.filter.pipe.spec.ts b/webui/src/app/pipes/humanreadable.filter.pipe.spec.ts new file mode 100644 index 000000000..4cdaa6f4a --- /dev/null +++ b/webui/src/app/pipes/humanreadable.filter.pipe.spec.ts @@ -0,0 +1,46 @@ +import { HumanReadableFilterPipe } from './humanreadable.filter.pipe'; + +describe('HumanReadableFilterPipe', () => { + const pipe = new HumanReadableFilterPipe(); + + const datatable = [{ + 'given': '180000000000', + 'expected': '180s' + }, + { + 'given': '4096.0', + 'expected': '4096ns' + }, + { + 'given': '7200000000000', + 'expected': '120m' + }, + { + 'given': '1337', + 'expected': '1337ns' + }, + { + 'given': 'traefik', + 'expected': 'traefik', + }, + { + 'given': '-23', + 'expected': '-23', + }, + { + 'given': '0', + 'expected': '0', + }, + ]; + + datatable.forEach(item => { + it((item.given + ' should be transformed to ' + item.expected ), () => { + expect(pipe.transform(item.given)).toEqual(item.expected); + }); + }); + + it('create an instance', () => { + expect(pipe).toBeTruthy(); + }); + +}); diff --git a/webui/src/app/pipes/humanreadable.filter.pipe.ts b/webui/src/app/pipes/humanreadable.filter.pipe.ts new file mode 100644 index 000000000..d0f5e8736 --- /dev/null +++ b/webui/src/app/pipes/humanreadable.filter.pipe.ts @@ -0,0 +1,27 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +/** + * HumanReadableFilterPipe converts a time period in nanoseconds to a human-readable + * string. + */ +@Pipe({name: 'humanreadable'}) +export class HumanReadableFilterPipe implements PipeTransform { + transform(value): any { + let result = ''; + const powerOf10 = Math.floor(Math.log10(value)); + + if (powerOf10 > 11) { + result = value / (60 * Math.pow(10, 9)) + 'm'; + } else if (powerOf10 > 9) { + result = value / Math.pow(10, 9) + 's'; + } else if (powerOf10 > 6) { + result = value / Math.pow(10, 6) + 'ms'; + } else if (value > 0) { + result = Math.floor(value) + 'ns'; + } else { + result = value; + } + + return result; + } +} diff --git a/webui/src/app/services/api.service.ts b/webui/src/app/services/api.service.ts index ae87b4ff8..d4b02289e 100644 --- a/webui/src/app/services/api.service.ts +++ b/webui/src/app/services/api.service.ts @@ -67,6 +67,9 @@ export class ApiService { frontend.headers.customResponseHeaders = this.toHeaderArray(frontend.headers.customResponseHeaders); frontend.headers.sslProxyHeaders = this.toHeaderArray(frontend.headers.sslProxyHeaders); } + if (frontend.ratelimit && frontend.ratelimit.rateset) { + frontend.ratelimit.rateset = this.toArray(frontend.ratelimit.rateset, 'id'); + } return frontend; }); From d4311f9cf55f8b49974158fd01ac5ad6006b906b Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 24 Sep 2018 11:44:03 +0200 Subject: [PATCH 06/23] Prepare release v1.7.0 --- CHANGELOG.md | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a73ecd214..89b83a958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,169 @@ # Change Log +## [v1.7.0](https://github.com/containous/traefik/tree/v1.7.0) (2018-09-24) +[Commits](https://github.com/containous/traefik/compare/v1.7.0-rc1...v1.7.0) +[Commits pre RC](https://github.com/containous/traefik/compare/v1.6.0-rc1...v1.7.0-rc1) + +**Enhancements:** +- **[acme]** Simplify get acme client ([#3499](https://github.com/containous/traefik/pull/3499) by [ldez](https://github.com/ldez)) +- **[acme]** Simplify acme e2e tests. ([#3534](https://github.com/containous/traefik/pull/3534) by [ldez](https://github.com/ldez)) +- **[acme]** Add option to select algorithm to generate ACME certificates ([#3319](https://github.com/containous/traefik/pull/3319) by [mmatur](https://github.com/mmatur)) +- **[acme]** Enable to override certificates in key-value store when using storeconfig ([#3202](https://github.com/containous/traefik/pull/3202) by [thomasjpfan](https://github.com/thomasjpfan)) +- **[acme]** ACME TLS ALPN ([#3553](https://github.com/containous/traefik/pull/3553) by [ldez](https://github.com/ldez)) +- **[acme]** Remove acme provider dependency in server ([#3225](https://github.com/containous/traefik/pull/3225) by [Juliens](https://github.com/Juliens)) +- **[acme]** Use official Pebble Image. ([#3708](https://github.com/containous/traefik/pull/3708) by [ldez](https://github.com/ldez)) +- **[api,cluster]** Improved cluster api to include the current leader node ([#3100](https://github.com/containous/traefik/pull/3100) by [aantono](https://github.com/aantono)) +- **[authentication,consul,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Auth support in frontends ([#3559](https://github.com/containous/traefik/pull/3559) by [jbdoumenjou](https://github.com/jbdoumenjou)) +- **[authentication,k8s]** Auth support in frontends for k8s and file ([#3460](https://github.com/containous/traefik/pull/3460) by [Zatte](https://github.com/Zatte)) +- **[authentication,middleware]** Add xforwarded method ([#3424](https://github.com/containous/traefik/pull/3424) by [erik-sjoestedt](https://github.com/erik-sjoestedt)) +- **[authentication,middleware]** Forward auth headers ([#3521](https://github.com/containous/traefik/pull/3521) by [hwhelan-CB](https://github.com/hwhelan-CB)) +- **[consul,etcd,tls]** Improve TLS integration tests ([#3679](https://github.com/containous/traefik/pull/3679) by [mmatur](https://github.com/mmatur)) +- **[consulcatalog,docker,ecs,file,k8s,kv,marathon,mesos,rancher]** Add SSLForceHost support. ([#3246](https://github.com/containous/traefik/pull/3246) by [ldez](https://github.com/ldez)) +- **[consulcatalog]** Multiple frontends for consulcatalog ([#3796](https://github.com/containous/traefik/pull/3796) by [hsmade](https://github.com/hsmade)) +- **[consulcatalog]** Add support for stale reads from Consul catalog ([#3523](https://github.com/containous/traefik/pull/3523) by [marenzo](https://github.com/marenzo)) +- **[docker]** Add a default value for the docker.network configuration ([#3471](https://github.com/containous/traefik/pull/3471) by [jbdoumenjou](https://github.com/jbdoumenjou)) +- **[ecs]** Support for AWS ECS Fargate ([#3379](https://github.com/containous/traefik/pull/3379) by [mmatur](https://github.com/mmatur)) +- **[ecs]** Add support for ECS constraints ([#3537](https://github.com/containous/traefik/pull/3537) by [andrewstucki](https://github.com/andrewstucki)) +- **[ecs]** Add segment support for ECS ([#3817](https://github.com/containous/traefik/pull/3817) by [mmatur](https://github.com/mmatur)) +- **[ecs]** Support `traefik.backend` for ECS ([#3510](https://github.com/containous/traefik/pull/3510) by [hwhelan-CB](https://github.com/hwhelan-CB)) +- **[ecs]** Allow binding ECS container port ([#3533](https://github.com/containous/traefik/pull/3533) by [andrewstucki](https://github.com/andrewstucki)) +- **[healthcheck,consul,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Override health check scheme ([#3315](https://github.com/containous/traefik/pull/3315) by [ldez](https://github.com/ldez)) +- **[healthcheck]** Support 3xx HTTP status codes for health check ([#3364](https://github.com/containous/traefik/pull/3364) by [SniperCZE](https://github.com/SniperCZE)) +- **[healthcheck]** Support all 2xx HTTP status code for health check. ([#3362](https://github.com/containous/traefik/pull/3362) by [ldez](https://github.com/ldez)) +- **[healthcheck]** Add HTTP headers to healthcheck. ([#3047](https://github.com/containous/traefik/pull/3047) by [zetaab](https://github.com/zetaab)) +- **[k8s]** Add more k8s tests ([#3491](https://github.com/containous/traefik/pull/3491) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Substitude hardcoded "<namespace>/<name>" with k8s ListerGetter ([#3470](https://github.com/containous/traefik/pull/3470) by [yue9944882](https://github.com/yue9944882)) +- **[k8s]** Custom frontend name for test helper ([#3444](https://github.com/containous/traefik/pull/3444) by [ldez](https://github.com/ldez)) +- **[k8s]** Add annotation to allow modifiers to be used properly in kubernetes ([#3481](https://github.com/containous/traefik/pull/3481) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Create Global Backend Ingress ([#3404](https://github.com/containous/traefik/pull/3404) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Specify backend servers' weight via annotation for kubernetes ([#3112](https://github.com/containous/traefik/pull/3112) by [yue9944882](https://github.com/yue9944882)) +- **[k8s]** Support multi-port services. ([#3121](https://github.com/containous/traefik/pull/3121) by [timoreimann](https://github.com/timoreimann)) +- **[k8s]** Mapping ExternalNames to custom ports ([#3231](https://github.com/containous/traefik/pull/3231) by [gildas](https://github.com/gildas)) +- **[k8s]** Allow any kubernetes ingressClass value ([#3516](https://github.com/containous/traefik/pull/3516) by [rtreffer](https://github.com/rtreffer)) +- **[k8s]** Enable Ingress Status updates ([#3324](https://github.com/containous/traefik/pull/3324) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Add possibility to set a protocol ([#3648](https://github.com/containous/traefik/pull/3648) by [SantoDE](https://github.com/SantoDE)) +- **[k8s]** Remove unnecessary loop ([#3799](https://github.com/containous/traefik/pull/3799) by [ZloyDyadka](https://github.com/ZloyDyadka)) +- **[kv]** Use index-based syntax in KV tests. ([#3352](https://github.com/containous/traefik/pull/3352) by [ldez](https://github.com/ldez)) +- **[logs,middleware]** Make accesslogs.logTheRoundTrip async to get lost performance ([#3152](https://github.com/containous/traefik/pull/3152) by [ryarnyah](https://github.com/ryarnyah)) +- **[logs,middleware]** Added duration filter for logs ([#3463](https://github.com/containous/traefik/pull/3463) by [rodrigodiez](https://github.com/rodrigodiez)) +- **[marathon]** Sane default and configurable Marathon request timeouts ([#3286](https://github.com/containous/traefik/pull/3286) by [marco-jantke](https://github.com/marco-jantke)) +- **[marathon]** Adding compatibility for marathon 1.5 ([#3505](https://github.com/containous/traefik/pull/3505) by [TrevinTeacutter](https://github.com/TrevinTeacutter)) +- **[mesos]** Segments Labels: Mesos ([#3383](https://github.com/containous/traefik/pull/3383) by [drewkerrigan](https://github.com/drewkerrigan)) +- **[metrics]** Metrics: Add support for InfluxDB Database / RetentionPolicy and HTTP client ([#3391](https://github.com/containous/traefik/pull/3391) by [drewkerrigan](https://github.com/drewkerrigan)) +- **[middleware,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Pass the TLS Cert infos in headers ([#3826](https://github.com/containous/traefik/pull/3826) by [jbdoumenjou](https://github.com/jbdoumenjou)) +- **[middleware,server]** Extreme Makeover: server refactoring ([#3461](https://github.com/containous/traefik/pull/3461) by [ldez](https://github.com/ldez)) +- **[middleware,tracing]** Added integration support for DataDog APM Tracing ([#3517](https://github.com/containous/traefik/pull/3517) by [aantono](https://github.com/aantono)) +- **[middleware,tracing]** Create a custom logger for jaeger ([#3541](https://github.com/containous/traefik/pull/3541) by [mmatur](https://github.com/mmatur)) +- **[middleware]** Performance enhancements for the rules matchers. ([#3563](https://github.com/containous/traefik/pull/3563) by [ShaneSaww](https://github.com/ShaneSaww)) +- **[middleware]** Extract internal router creation from server ([#3204](https://github.com/containous/traefik/pull/3204) by [Juliens](https://github.com/Juliens)) +- **[rules]** CNAME flattening ([#3403](https://github.com/containous/traefik/pull/3403) by [gamalan](https://github.com/gamalan)) +- **[servicefabric]** Add HTTP headers to healthcheck. ([#3205](https://github.com/containous/traefik/pull/3205) by [ldez](https://github.com/ldez)) +- **[tls]** Support TLS MinVersion and CipherSuite as CLI option. ([#3107](https://github.com/containous/traefik/pull/3107) by [ldez](https://github.com/ldez)) +- **[tls]** Improve TLS Handshake ([#3512](https://github.com/containous/traefik/pull/3512) by [dtomcej](https://github.com/dtomcej)) +- **[webui]** Add some missing elements in the WebUI ([#3327](https://github.com/containous/traefik/pull/3327) by [ldez](https://github.com/ldez)) +- Call functions to enable block/mutex pprof profiles. ([#3564](https://github.com/containous/traefik/pull/3564) by [timoreimann](https://github.com/timoreimann)) +- Minor changes ([#3554](https://github.com/containous/traefik/pull/3554) by [ldez](https://github.com/ldez)) +- Generated assets file are only mandatory in main ([#3386](https://github.com/containous/traefik/pull/3386) by [Juliens](https://github.com/Juliens)) +- h2c server ([#3387](https://github.com/containous/traefik/pull/3387) by [Juliens](https://github.com/Juliens)) +- Fix backend reuse ([#3312](https://github.com/containous/traefik/pull/3312) by [arnested](https://github.com/arnested)) +- Upgrade GRPC dependencies ([#3342](https://github.com/containous/traefik/pull/3342) by [gottwald](https://github.com/gottwald)) +- Implement h2c with backend ([#3371](https://github.com/containous/traefik/pull/3371) by [Juliens](https://github.com/Juliens)) + +**Bug fixes:** +- **[acme,cluster]** StoreConfig always initializes the account if it is missing ([#3844](https://github.com/containous/traefik/pull/3844) by [geraldcroes](https://github.com/geraldcroes)) +- **[acme,provider]** Create init method on provider interface ([#3580](https://github.com/containous/traefik/pull/3580) by [Juliens](https://github.com/Juliens)) +- **[acme]** Does not generate ACME certificate if domain is checked by dynamic certificate ([#3238](https://github.com/containous/traefik/pull/3238) by [Juliens](https://github.com/Juliens)) +- **[acme]** Ensure only certificates from ACME enabled entrypoint are used ([#3880](https://github.com/containous/traefik/pull/3880) by [dtomcej](https://github.com/dtomcej)) +- **[acme]** Fix acme account deletion without provider change ([#3664](https://github.com/containous/traefik/pull/3664) by [zyclonite](https://github.com/zyclonite)) +- **[acme]** Fix some DNS providers issues ([#3915](https://github.com/containous/traefik/pull/3915) by [ldez](https://github.com/ldez)) +- **[acme]** Fix LEGO update ([#3895](https://github.com/containous/traefik/pull/3895) by [ldez](https://github.com/ldez)) +- **[acme]** Set a keyType to ACME if the account is stored with no KeyType ([#3733](https://github.com/containous/traefik/pull/3733) by [nmengin](https://github.com/nmengin)) +- **[acme]** Fix ACME certificate for wildcard and root domains ([#3675](https://github.com/containous/traefik/pull/3675) by [nmengin](https://github.com/nmengin)) +- **[acme]** Update lego ([#3659](https://github.com/containous/traefik/pull/3659) by [mmatur](https://github.com/mmatur)) +- **[acme]** Bump LEGO version ([#3888](https://github.com/containous/traefik/pull/3888) by [ldez](https://github.com/ldez)) +- **[acme]** Serve TLS-Challenge certificate in first ([#3605](https://github.com/containous/traefik/pull/3605) by [nmengin](https://github.com/nmengin)) +- **[api,authentication,webui]** Auth section in web UI. ([#3628](https://github.com/containous/traefik/pull/3628) by [ldez](https://github.com/ldez)) +- **[api]** Remove TLS in API ([#3665](https://github.com/containous/traefik/pull/3665) by [mmatur](https://github.com/mmatur)) +- **[authentication,consulcatalog,docker,ecs,k8s,kv,marathon,mesos,rancher]** Auth Forward with certificates in templates. ([#3804](https://github.com/containous/traefik/pull/3804) by [ldez](https://github.com/ldez)) +- **[authentication,middleware,provider]** Don't pass the Authorization header to the backends ([#3606](https://github.com/containous/traefik/pull/3606) by [jbdoumenjou](https://github.com/jbdoumenjou)) +- **[authentication,middleware]** Do not copy hop-by-hop headers to forward auth request ([#3907](https://github.com/containous/traefik/pull/3907) by [stffabi](https://github.com/stffabi)) +- **[authentication,middleware]** Remove hop-by-hop headers from forward auth response ([#3900](https://github.com/containous/traefik/pull/3900) by [stffabi](https://github.com/stffabi)) +- **[docker]** Uses both binded HostIP and HostPort when useBindPortIP=true ([#3638](https://github.com/containous/traefik/pull/3638) by [geraldcroes](https://github.com/geraldcroes)) +- **[ecs]** Fix 400 bad request on AWS ECS API ([#3629](https://github.com/containous/traefik/pull/3629) by [mmatur](https://github.com/mmatur)) +- **[k8s]** Fix Rewrite-target regex ([#3699](https://github.com/containous/traefik/pull/3699) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Don't merge kubernetes ingresses when priority is set ([#3743](https://github.com/containous/traefik/pull/3743) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Prevent unparsable strings from being rendered in the Kubernetes template ([#3753](https://github.com/containous/traefik/pull/3753) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Correct App-Root kubernetes behavior ([#3592](https://github.com/containous/traefik/pull/3592) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Add more K8s Unit Tests ([#3583](https://github.com/containous/traefik/pull/3583) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Fix rewrite-target Annotation behavior ([#3582](https://github.com/containous/traefik/pull/3582) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Fix panic setting ingress status ([#3492](https://github.com/containous/traefik/pull/3492) by [dtomcej](https://github.com/dtomcej)) +- **[kv]** KV and authentication ([#3615](https://github.com/containous/traefik/pull/3615) by [ldez](https://github.com/ldez)) +- **[kv]** Add missing quotes around backendName in kv template ([#3885](https://github.com/containous/traefik/pull/3885) by [NatMarchand](https://github.com/NatMarchand)) +- **[kv]** Include missing key in error message for KV store ([#3779](https://github.com/containous/traefik/pull/3779) by [camelpunch](https://github.com/camelpunch)) +- **[logs]** Add logs when error is generated in error handler ([#3571](https://github.com/containous/traefik/pull/3571) by [Juliens](https://github.com/Juliens)) +- **[logs]** Add interface to Træfik logger ([#3889](https://github.com/containous/traefik/pull/3889) by [nmengin](https://github.com/nmengin)) +- **[metrics]** Avoid a panic during Prometheus registering ([#3717](https://github.com/containous/traefik/pull/3717) by [nmengin](https://github.com/nmengin)) +- **[middleware,tracing]** Fix tracing duplicated headers ([#3878](https://github.com/containous/traefik/pull/3878) by [mmatur](https://github.com/mmatur)) +- **[middleware,websocket]** Enable retry on websocket ([#3825](https://github.com/containous/traefik/pull/3825) by [Juliens](https://github.com/Juliens)) +- **[middleware]** Avoid retries when any data was written to the backend ([#3285](https://github.com/containous/traefik/pull/3285) by [marco-jantke](https://github.com/marco-jantke)) +- **[middleware]** Extend https redirection tests, and fix incorrect behavior ([#3742](https://github.com/containous/traefik/pull/3742) by [dtomcej](https://github.com/dtomcej)) +- **[middleware]** Send 'Retry-After' to comply with RFC6585. ([#3593](https://github.com/containous/traefik/pull/3593) by [ldez](https://github.com/ldez)) +- **[middleware]** Correct Entrypoint Redirect with Stripped or Added Path ([#3631](https://github.com/containous/traefik/pull/3631) by [dtomcej](https://github.com/dtomcej)) +- **[middleware]** Fix error pages ([#3894](https://github.com/containous/traefik/pull/3894) by [Juliens](https://github.com/Juliens)) +- **[oxy]** Handle Te header when http2 ([#3824](https://github.com/containous/traefik/pull/3824) by [Juliens](https://github.com/Juliens)) +- **[server]** Avoid goroutine leak in server ([#3851](https://github.com/containous/traefik/pull/3851) by [nmengin](https://github.com/nmengin)) +- **[server]** Avoid panic during stop ([#3898](https://github.com/containous/traefik/pull/3898) by [nmengin](https://github.com/nmengin)) +- **[tracing]** Added default configuration for DataDog APM Tracer ([#3655](https://github.com/containous/traefik/pull/3655) by [aantono](https://github.com/aantono)) +- **[tracing]** Added support for Trace name truncation for traces ([#3689](https://github.com/containous/traefik/pull/3689) by [aantono](https://github.com/aantono)) +- **[websocket]** Handle shutdown of Hijacked connections ([#3636](https://github.com/containous/traefik/pull/3636) by [Juliens](https://github.com/Juliens)) +- **[webui]** Added Dashboard table item for Rate Limits ([#3893](https://github.com/containous/traefik/pull/3893) by [codecyclist](https://github.com/codecyclist)) +- Fix logger in Oxy ([#3913](https://github.com/containous/traefik/pull/3913) by [ldez](https://github.com/ldez)) +- H2C: Remove buggy line in init to make verbose switch working ([#3701](https://github.com/containous/traefik/pull/3701) by [dduportal](https://github.com/dduportal)) +- Updating oxy dependency ([#3700](https://github.com/containous/traefik/pull/3700) by [crholm](https://github.com/crholm)) + +**Documentation:** +- **[acme]** Update ACME documentation about TLS-ALPN challenge ([#3756](https://github.com/containous/traefik/pull/3756) by [ldez](https://github.com/ldez)) +- **[acme]** Fix some DNS provider link ([#3639](https://github.com/containous/traefik/pull/3639) by [ldez](https://github.com/ldez)) +- **[acme]** Fix documentation for route53 acme provider ([#3811](https://github.com/containous/traefik/pull/3811) by [A-Shleifman](https://github.com/A-Shleifman)) +- **[acme]** Update Namecheap status ([#3604](https://github.com/containous/traefik/pull/3604) by [stoinov](https://github.com/stoinov)) +- **[docker]** Fix style in examples/quickstart ([#3705](https://github.com/containous/traefik/pull/3705) by [korigod](https://github.com/korigod)) +- **[docker]** Change syntax in quick start guide ([#3726](https://github.com/containous/traefik/pull/3726) by [trotro](https://github.com/trotro)) +- **[docker]** Typo in docker-and-lets-encrypt.md ([#3724](https://github.com/containous/traefik/pull/3724) by [A-Shleifman](https://github.com/A-Shleifman)) +- **[docker]** Improve the wording in the documentation for Docker and fix title for Docker User Guide ([#3797](https://github.com/containous/traefik/pull/3797) by [dduportal](https://github.com/dduportal)) +- **[k8s]** Add a k8s guide section on traffic splitting via service weights. ([#3556](https://github.com/containous/traefik/pull/3556) by [timoreimann](https://github.com/timoreimann)) +- **[k8s]** Change code block of traefik-web-ui to match file ([#3542](https://github.com/containous/traefik/pull/3542) by [drewgwallace](https://github.com/drewgwallace)) +- **[k8s]** Fix typo which breaks k8s example manifest ([#3441](https://github.com/containous/traefik/pull/3441) by [GeertJohan](https://github.com/GeertJohan)) +- **[k8s]** Correct Modifier in Kubernetes Documentation ([#3610](https://github.com/containous/traefik/pull/3610) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Improve Connection Limit Kubernetes Documentation ([#3711](https://github.com/containous/traefik/pull/3711) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Add traefik prefix to k8s annotations ([#3682](https://github.com/containous/traefik/pull/3682) by [zifeo](https://github.com/zifeo)) +- **[k8s]** Update kubernetes docs to reflect https options ([#3807](https://github.com/containous/traefik/pull/3807) by [dtomcej](https://github.com/dtomcej)) +- **[k8s]** Update kubernetes.md ([#3719](https://github.com/containous/traefik/pull/3719) by [kmaris](https://github.com/kmaris)) +- **[metrics]** Adding grafana dashboards based on prometheus metrics ([#3393](https://github.com/containous/traefik/pull/3393) by [deimosfr](https://github.com/deimosfr)) +- **[middleware,tracing]** Fix missing tracing backend in documentation ([#3706](https://github.com/containous/traefik/pull/3706) by [mmatur](https://github.com/mmatur)) +- **[provider]** Typo in auth labels. ([#3730](https://github.com/containous/traefik/pull/3730) by [ldez](https://github.com/ldez)) +- **[servicefabric]** Fix Service Fabric docs to use v1.6 labels ([#3209](https://github.com/containous/traefik/pull/3209) by [jjcollinge](https://github.com/jjcollinge)) +- **[tracing]** Simple documentation grammar update in tracing ([#3720](https://github.com/containous/traefik/pull/3720) by [loadstar81](https://github.com/loadstar81)) +- Replace unrendered emoji ([#3690](https://github.com/containous/traefik/pull/3690) by [korigod](https://github.com/korigod)) +- Make the "base domain" on all providers ([#3835](https://github.com/containous/traefik/pull/3835) by [dduportal](https://github.com/dduportal)) +- Prepare release v1.7.0-rc5 ([#3902](https://github.com/containous/traefik/pull/3902) by [dduportal](https://github.com/dduportal)) +- Prepare release v1.7.0-rc3 ([#3709](https://github.com/containous/traefik/pull/3709) by [mmatur](https://github.com/mmatur)) +- Prepare release v1.7.0-rc4 ([#3864](https://github.com/containous/traefik/pull/3864) by [Juliens](https://github.com/Juliens)) +- Prepare release v1.7.0-rc2 ([#3632](https://github.com/containous/traefik/pull/3632) by [nmengin](https://github.com/nmengin)) +- Prepare release v1.7.0-rc1 ([#3578](https://github.com/containous/traefik/pull/3578) by [mmatur](https://github.com/mmatur)) + +**Misc:** +- **[webui]** Removed non-applicable default tests and fixed custom tests ([#3908](https://github.com/containous/traefik/pull/3908) by [codecyclist](https://github.com/codecyclist)) +- Merge v1.6.6 into v1.7 ([#3802](https://github.com/containous/traefik/pull/3802) by [ldez](https://github.com/ldez)) +- Merge v1.6.5 into v1.7 ([#3595](https://github.com/containous/traefik/pull/3595) by [ldez](https://github.com/ldez)) +- Merge v1.6.4 into master ([#3502](https://github.com/containous/traefik/pull/3502) by [ldez](https://github.com/ldez)) +- Merge v1.6.3 into master ([#3439](https://github.com/containous/traefik/pull/3439) by [ldez](https://github.com/ldez)) +- Merge v1.6.2 into master ([#3367](https://github.com/containous/traefik/pull/3367) by [ldez](https://github.com/ldez)) +- Merge v1.6.1 into master ([#3326](https://github.com/containous/traefik/pull/3326) by [ldez](https://github.com/ldez)) +- Merge v1.6.0 into master ([#3253](https://github.com/containous/traefik/pull/3253) by [ldez](https://github.com/ldez)) +- Merge v1.6.0-rc6 into master ([#3203](https://github.com/containous/traefik/pull/3203) by [ldez](https://github.com/ldez)) +- Merge v1.6.0-rc5 into master ([#3180](https://github.com/containous/traefik/pull/3180) by [ldez](https://github.com/ldez)) +- Merge v1.6.0-rc4 into master ([#3129](https://github.com/containous/traefik/pull/3129) by [ldez](https://github.com/ldez)) + ## [v1.7.0-rc5](https://github.com/containous/traefik/tree/v1.7.0-rc5) (2018-09-18) [All Commits](https://github.com/containous/traefik/compare/v1.7.0-rc4...v1.7.0-rc5) From 0c76a8ac892665cf5a2b58cade27c38347a831e3 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Thu, 27 Sep 2018 16:54:05 +0200 Subject: [PATCH 07/23] Fix TLS ALPN cluster mode. --- acme/acme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/acme.go b/acme/acme.go index d9c90137f..b1e56f65f 100644 --- a/acme/acme.go +++ b/acme/acme.go @@ -127,7 +127,6 @@ func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tl a.checkOnDemandDomain = checkOnDemandDomain a.dynamicCerts = certs - a.challengeTLSProvider = &challengeTLSProvider{store: a.store} tlsConfig.GetCertificate = a.getCertificate a.TLSConfig = tlsConfig @@ -157,6 +156,7 @@ func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tl } a.store = datastore + a.challengeTLSProvider = &challengeTLSProvider{store: a.store} ticker := time.NewTicker(24 * time.Hour) leadership.Pool.AddGoCtx(func(ctx context.Context) { From 7033b996c695797b1a67a2a4afd00179a7271c83 Mon Sep 17 00:00:00 2001 From: SALLEYRON Julien Date: Thu, 27 Sep 2018 18:04:03 +0200 Subject: [PATCH 08/23] Don't challenge ACME when host rule on another entry point --- provider/acme/provider.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/provider/acme/provider.go b/provider/acme/provider.go index 3f43eaf91..7544cb2cb 100644 --- a/provider/acme/provider.go +++ b/provider/acme/provider.go @@ -323,12 +323,24 @@ func (p *Provider) initAccount() (*Account, error) { return p.account, nil } +func contains(entryPoints []string, acmeEntryPoint string) bool { + for _, entryPoint := range entryPoints { + if entryPoint == acmeEntryPoint { + return true + } + } + return false +} + func (p *Provider) watchNewDomains() { p.pool.Go(func(stop chan bool) { for { select { case config := <-p.configFromListenerChan: for _, frontend := range config.Frontends { + if !contains(frontend.EntryPoints, p.EntryPoint) { + continue + } for _, route := range frontend.Routes { domainRules := rules.Rules{} domains, err := domainRules.ParseDomains(route.Rule) From 1d8bdd43847344d4ad5315c649f68b544a962444 Mon Sep 17 00:00:00 2001 From: SALLEYRON Julien Date: Fri, 28 Sep 2018 17:54:04 +0200 Subject: [PATCH 09/23] Don't remove static certs from config when cluster mode --- server/server.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/server/server.go b/server/server.go index d19462278..cacad7fca 100644 --- a/server/server.go +++ b/server/server.go @@ -480,18 +480,17 @@ func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefiktls.TL } } else { config.GetCertificate = s.serverEntryPoints[entryPointName].getCertificate - } + if len(config.Certificates) != 0 { + certMap := s.buildNameOrIPToCertificate(config.Certificates) - if len(config.Certificates) != 0 { - certMap := s.buildNameOrIPToCertificate(config.Certificates) - - if s.entryPoints[entryPointName].CertificateStore != nil { - s.entryPoints[entryPointName].CertificateStore.StaticCerts.Set(certMap) + if s.entryPoints[entryPointName].CertificateStore != nil { + s.entryPoints[entryPointName].CertificateStore.StaticCerts.Set(certMap) + } } - } - // Remove certs from the TLS config object - config.Certificates = []tls.Certificate{} + // Remove certs from the TLS config object + config.Certificates = []tls.Certificate{} + } // Set the minimum TLS version if set in the config TOML if minConst, exists := traefiktls.MinVersion[s.entryPoints[entryPointName].Configuration.TLS.MinVersion]; exists { From 8cc3c4a6b765fc37f72dc557c453a219346befb9 Mon Sep 17 00:00:00 2001 From: SALLEYRON Julien Date: Sat, 29 Sep 2018 00:04:02 +0200 Subject: [PATCH 10/23] Use the first static certificate as a fallback when no default is given --- configuration/configuration.go | 5 +++++ integration/etcd_test.go | 16 ++++++++-------- server/server_configuration.go | 26 ++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/configuration/configuration.go b/configuration/configuration.go index 47899bd9e..5f745b647 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -207,6 +207,11 @@ func (gc *GlobalConfiguration) SetEffectiveConfiguration(configFile string) { entryPoint.WhitelistSourceRange = nil } } + + if entryPoint.TLS != nil && entryPoint.TLS.DefaultCertificate == nil && len(entryPoint.TLS.Certificates) > 0 { + log.Infof("No tls.defaultCertificate given for %s: using the first item in tls.certificates as a fallback.", entryPointName) + entryPoint.TLS.DefaultCertificate = &entryPoint.TLS.Certificates[0] + } } // Make sure LifeCycle isn't nil to spare nil checks elsewhere. diff --git a/integration/etcd_test.go b/integration/etcd_test.go index 80dcf0b40..1da3f7408 100644 --- a/integration/etcd_test.go +++ b/integration/etcd_test.go @@ -315,13 +315,13 @@ func (s *EtcdSuite) TestCertificatesContentWithSNIConfigHandshake(c *check.C) { snitestOrgKey, err := ioutil.ReadFile("fixtures/https/snitest.org.key") c.Assert(err, checker.IsNil) - globalConfig := map[string]string{ - "/traefik/entrypoints/https/address": ":4443", - "/traefik/entrypoints/https/tls/certificates/0/certfile": string(snitestComCert), - "/traefik/entrypoints/https/tls/certificates/0/keyfile": string(snitestComKey), - "/traefik/entrypoints/https/tls/certificates/1/certfile": string(snitestOrgCert), - "/traefik/entrypoints/https/tls/certificates/1/keyfile": string(snitestOrgKey), - "/traefik/defaultentrypoints/0": "https", + globalConfig := map[string][]byte{ + "/traefik/entrypoints/https/address": []byte(":4443"), + "/traefik/entrypoints/https/tls/certificates/0/certfile": snitestComCert, + "/traefik/entrypoints/https/tls/certificates/0/keyfile": snitestComKey, + "/traefik/entrypoints/https/tls/certificates/1/certfile": snitestOrgCert, + "/traefik/entrypoints/https/tls/certificates/1/keyfile": snitestOrgKey, + "/traefik/defaultentrypoints/0": []byte("https"), } backend1 := map[string]string{ @@ -351,7 +351,7 @@ func (s *EtcdSuite) TestCertificatesContentWithSNIConfigHandshake(c *check.C) { "/traefik/frontends/frontend2/routes/test_2/rule": "Host:snitest.org", } for key, value := range globalConfig { - err := s.kv.Put(key, []byte(value), nil) + err := s.kv.Put(key, value, nil) c.Assert(err, checker.IsNil) } for key, value := range backend1 { diff --git a/server/server_configuration.go b/server/server_configuration.go index eec23f8f3..164048bcd 100644 --- a/server/server_configuration.go +++ b/server/server_configuration.go @@ -590,13 +590,17 @@ func (s *Server) buildServerEntryPoints() map[string]*serverEntryPoint { serverEntryPoints[entryPointName].certs.SniStrict = entryPoint.Configuration.TLS.SniStrict if entryPoint.Configuration.TLS.DefaultCertificate != nil { - cert, err := tls.LoadX509KeyPair(entryPoint.Configuration.TLS.DefaultCertificate.CertFile.String(), entryPoint.Configuration.TLS.DefaultCertificate.KeyFile.String()) + cert, err := buildDefaultCertificate(entryPoint.Configuration.TLS.DefaultCertificate) if err != nil { + log.Error(err) + continue } - serverEntryPoints[entryPointName].certs.DefaultCertificate = &cert + serverEntryPoints[entryPointName].certs.DefaultCertificate = cert } else { cert, err := generate.DefaultCertificate() if err != nil { + log.Errorf("failed to generate default certificate: %v", err) + continue } serverEntryPoints[entryPointName].certs.DefaultCertificate = cert } @@ -611,6 +615,24 @@ func (s *Server) buildServerEntryPoints() map[string]*serverEntryPoint { return serverEntryPoints } +func buildDefaultCertificate(defaultCertificate *traefiktls.Certificate) (*tls.Certificate, error) { + certFile, err := defaultCertificate.CertFile.Read() + if err != nil { + return nil, fmt.Errorf("failed to get cert file content: %v", err) + } + + keyFile, err := defaultCertificate.KeyFile.Read() + if err != nil { + return nil, fmt.Errorf("failed to get key file content: %v", err) + } + + cert, err := tls.X509KeyPair(certFile, keyFile) + if err != nil { + return nil, fmt.Errorf("failed to load X509 key pair: %v", err) + } + return &cert, nil +} + func (s *Server) buildDefaultHTTPRouter() *mux.Router { rt := mux.NewRouter() rt.NotFoundHandler = s.wrapHTTPHandlerWithAccessLog(http.HandlerFunc(http.NotFound), "backend not found") From 9e26f0b058223096e3f1da2ccbdaed2fcacb870a Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Sat, 29 Sep 2018 00:16:03 +0200 Subject: [PATCH 11/23] Prepare release v1.7.1 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89b83a958..67c99eaca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log +## [v1.7.1](https://github.com/containous/traefik/tree/v1.7.1) (2018-09-28) +[All Commits](https://github.com/containous/traefik/compare/v1.7.0...v1.7.1) + +**Bug fixes:** +- **[acme,cluster]** Don't remove static certs from config when cluster mode ([#3946](https://github.com/containous/traefik/pull/3946) by [Juliens](https://github.com/Juliens)) +- **[acme]** Fix TLS ALPN cluster mode. ([#3934](https://github.com/containous/traefik/pull/3934) by [ldez](https://github.com/ldez)) +- **[acme]** Don't challenge ACME when host rule on another entry point ([#3923](https://github.com/containous/traefik/pull/3923) by [Juliens](https://github.com/Juliens)) +- **[tls]** Use the first static certificate as a fallback when no default is given ([#3948](https://github.com/containous/traefik/pull/3948) by [Juliens](https://github.com/Juliens)) + ## [v1.7.0](https://github.com/containous/traefik/tree/v1.7.0) (2018-09-24) [Commits](https://github.com/containous/traefik/compare/v1.7.0-rc1...v1.7.0) [Commits pre RC](https://github.com/containous/traefik/compare/v1.6.0-rc1...v1.7.0-rc1) From 147e79ea073c98fcf58d11ccbe723aae0c948e3b Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 1 Oct 2018 16:56:03 +0200 Subject: [PATCH 12/23] TLS, ACME, cluster and several entrypoints. --- server/server.go | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/server/server.go b/server/server.go index cacad7fca..74c3beeb4 100644 --- a/server/server.go +++ b/server/server.go @@ -462,21 +462,19 @@ func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefiktls.TL } } - if s.globalConfiguration.ACME != nil { - if entryPointName == s.globalConfiguration.ACME.EntryPoint { - checkOnDemandDomain := func(domain string) bool { - routeMatch := &mux.RouteMatch{} - match := router.GetHandler().Match(&http.Request{URL: &url.URL{}, Host: domain}, routeMatch) - if match && routeMatch.Route != nil { - return true - } - return false + if s.globalConfiguration.ACME != nil && entryPointName == s.globalConfiguration.ACME.EntryPoint { + checkOnDemandDomain := func(domain string) bool { + routeMatch := &mux.RouteMatch{} + match := router.GetHandler().Match(&http.Request{URL: &url.URL{}, Host: domain}, routeMatch) + if match && routeMatch.Route != nil { + return true } + return false + } - err := s.globalConfiguration.ACME.CreateClusterConfig(s.leadership, config, s.serverEntryPoints[entryPointName].certs.DynamicCerts, checkOnDemandDomain) - if err != nil { - return nil, err - } + err := s.globalConfiguration.ACME.CreateClusterConfig(s.leadership, config, s.serverEntryPoints[entryPointName].certs.DynamicCerts, checkOnDemandDomain) + if err != nil { + return nil, err } } else { config.GetCertificate = s.serverEntryPoints[entryPointName].getCertificate From 8d8e509fe60f764f910dd9ae09fd2bd8989e9637 Mon Sep 17 00:00:00 2001 From: Fabrice Date: Mon, 1 Oct 2018 08:02:02 -0700 Subject: [PATCH 13/23] Correctly initialize kv store if storage key missing --- cmd/storeconfig/storeconfig.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/storeconfig/storeconfig.go b/cmd/storeconfig/storeconfig.go index 483d6c9c1..9a79ff139 100644 --- a/cmd/storeconfig/storeconfig.go +++ b/cmd/storeconfig/storeconfig.go @@ -86,7 +86,7 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu } accountInitialized, err := keyExists(kv, traefikConfiguration.GlobalConfiguration.ACME.Storage) - if err != nil { + if err != nil && err != store.ErrKeyNotFound { return err } From 61e18364726a3b0f26a0f38863051799115c09cf Mon Sep 17 00:00:00 2001 From: Fabrice Date: Mon, 1 Oct 2018 08:24:03 -0700 Subject: [PATCH 14/23] Return an error if kv store CA cert is invalid --- types/types.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/types/types.go b/types/types.go index a3dd62078..99393afb5 100644 --- a/types/types.go +++ b/types/types.go @@ -528,7 +528,9 @@ func (clientTLS *ClientTLS) CreateTLSConfig() (*tls.Config, error) { } else { ca = []byte(clientTLS.CA) } - caPool.AppendCertsFromPEM(ca) + if !caPool.AppendCertsFromPEM(ca) { + return nil, fmt.Errorf("failed to parse CA") + } if clientTLS.CAOptional { clientAuth = tls.VerifyClientCertIfGiven } else { From f74526a36e57eaeb28936288929198232672f764 Mon Sep 17 00:00:00 2001 From: Dan Fredell Date: Mon, 1 Oct 2018 11:54:04 -0500 Subject: [PATCH 15/23] Document the default accessLog format --- docs/configuration/logs.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/configuration/logs.md b/docs/configuration/logs.md index 06f955fbe..4b9d4a9f2 100644 --- a/docs/configuration/logs.md +++ b/docs/configuration/logs.md @@ -60,12 +60,14 @@ For more information about the CLI, see the documentation about [Traefik command By default the Traefik log is written to stdout in text format. To write the logs into a log file specify the `filePath`: + ```toml [traefikLog] filePath = "/path/to/traefik.log" ``` To write JSON format logs, specify `json` as the format: + ```toml [traefikLog] filePath = "/path/to/traefik.log" @@ -90,6 +92,7 @@ traefikLogsFile = "log/traefik.log" ``` To customize the log level: + ```toml # Log level # @@ -109,17 +112,20 @@ Access logs are written when `[accessLog]` is defined. By default it will write to stdout and produce logs in the textual Common Log Format (CLF), extended with additional fields. To enable access logs using the default settings just add the `[accessLog]` entry: + ```toml [accessLog] ``` To write the logs into a log file specify the `filePath`: + ```toml [accessLog] filePath = "/path/to/access.log" ``` To write JSON format logs, specify `json` as the format: + ```toml [accessLog] filePath = "/path/to/access.log" @@ -127,6 +133,7 @@ format = "json" ``` To write the logs in async, specify `bufferingSize` as the format (must be >0): + ```toml [accessLog] filePath = "/path/to/access.log" @@ -141,6 +148,7 @@ bufferingSize = 100 ``` To filter logs you can specify a set of filters which are logically "OR-connected". Thus, specifying multiple filters will keep more access logs than specifying only one: + ```toml [accessLog] filePath = "/path/to/access.log" @@ -171,6 +179,7 @@ format = "json" ``` To customize logs format: + ```toml [accessLog] filePath = "/path/to/access.log" @@ -218,7 +227,8 @@ format = "json" # ... ``` -#### List of all available fields + +### List of all available fields ```ini StartUTC @@ -266,6 +276,15 @@ Deprecated way (before 1.4): accessLogsFile = "log/access.log" ``` +### CLF - Common Log Format + +By default, Træfik use the CLF (`common`) as access log format. + +```html + - [] " " "" "" "" "" ms +``` + + ## Log Rotation Traefik will close and reopen its log files, assuming they're configured, on receipt of a USR1 signal. From 742029d8a491e61abf42dc2dafcda9ae1d6356b2 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 1 Oct 2018 19:18:03 +0200 Subject: [PATCH 16/23] Global configuration log at start --- anonymize/anonymize_config_test.go | 35 ++++++++++++++++++++++++++++++ api/handler.go | 2 +- cmd/traefik/traefik.go | 15 ++++++++----- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/anonymize/anonymize_config_test.go b/anonymize/anonymize_config_test.go index 3ffe72bce..de449f3c1 100644 --- a/anonymize/anonymize_config_test.go +++ b/anonymize/anonymize_config_test.go @@ -2,12 +2,15 @@ package anonymize import ( "crypto/tls" + "os" "testing" "time" "github.com/containous/flaeg" "github.com/containous/traefik/acme" + "github.com/containous/traefik/api" "github.com/containous/traefik/configuration" + "github.com/containous/traefik/middlewares" "github.com/containous/traefik/provider" acmeprovider "github.com/containous/traefik/provider/acme" "github.com/containous/traefik/provider/boltdb" @@ -25,8 +28,11 @@ import ( "github.com/containous/traefik/provider/mesos" "github.com/containous/traefik/provider/rancher" "github.com/containous/traefik/provider/zk" + "github.com/containous/traefik/safe" traefiktls "github.com/containous/traefik/tls" "github.com/containous/traefik/types" + "github.com/elazarl/go-bindata-assetfs" + "github.com/thoas/stats" ) func TestDo_globalConfiguration(t *testing.T) { @@ -188,6 +194,35 @@ func TestDo_globalConfiguration(t *testing.T) { config.HealthCheck = &configuration.HealthCheckConfig{ Interval: flaeg.Duration(666 * time.Second), } + config.API = &api.Handler{ + EntryPoint: "traefik", + Dashboard: true, + Debug: true, + CurrentConfigurations: &safe.Safe{}, + Statistics: &types.Statistics{ + RecentErrors: 666, + }, + Stats: &stats.Stats{ + Uptime: time.Now(), + Pid: 666, + ResponseCounts: map[string]int{"foo": 1}, + TotalResponseCounts: map[string]int{"bar": 1}, + TotalResponseTime: time.Now(), + }, + StatsRecorder: &middlewares.StatsRecorder{}, + 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.RespondingTimeouts = &configuration.RespondingTimeouts{ ReadTimeout: flaeg.Duration(666 * time.Second), WriteTimeout: flaeg.Duration(666 * time.Second), diff --git a/api/handler.go b/api/handler.go index e3e88b433..370955978 100644 --- a/api/handler.go +++ b/api/handler.go @@ -23,7 +23,7 @@ type Handler struct { Statistics *types.Statistics `description:"Enable more detailed statistics" export:"true"` Stats *thoas_stats.Stats `json:"-"` StatsRecorder *middlewares.StatsRecorder `json:"-"` - DashboardAssets *assetfs.AssetFS + DashboardAssets *assetfs.AssetFS `json:"-"` } var ( diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index 412027507..67469e6fc 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -165,21 +165,26 @@ func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile s globalConfiguration.SetEffectiveConfiguration(configFile) globalConfiguration.ValidateConfiguration() + log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate) + + jsonConf, err := json.Marshal(globalConfiguration) + if err != nil { + log.Error(err) + log.Debugf("Global configuration loaded [struct] %#v", globalConfiguration) + } else { + log.Debugf("Global configuration loaded %s", string(jsonConf)) + } + if globalConfiguration.API != nil && globalConfiguration.API.Dashboard { globalConfiguration.API.DashboardAssets = &assetfs.AssetFS{Asset: genstatic.Asset, AssetInfo: genstatic.AssetInfo, AssetDir: genstatic.AssetDir, Prefix: "static"} } - jsonConf, _ := json.Marshal(globalConfiguration) - log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate) - if globalConfiguration.CheckNewVersion { checkNewVersion() } stats(globalConfiguration) - log.Debugf("Global configuration loaded %s", string(jsonConf)) - providerAggregator := configuration.NewProviderAggregator(globalConfiguration) acmeprovider := globalConfiguration.InitACMEProvider() From f04813fa0208b0394fa74858c2af186e446c753b Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 1 Oct 2018 19:44:03 +0200 Subject: [PATCH 17/23] Whitelist log for deprecated configuration. --- server/server_middlewares.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/server_middlewares.go b/server/server_middlewares.go index 4ab3938f9..bd9b97fa3 100644 --- a/server/server_middlewares.go +++ b/server/server_middlewares.go @@ -55,7 +55,11 @@ func (s *Server) buildMiddlewares(frontendName string, frontend *types.Frontend, return nil, nil, nil, fmt.Errorf("error creating IP Whitelister: %s", err) } if ipWhitelistMiddleware != nil { - log.Debugf("Configured IP Whitelists: %v", frontend.WhiteList.SourceRange) + if frontend.WhiteList != nil { + log.Debugf("Configured IP Whitelists: %v", frontend.WhiteList.SourceRange) + } else { + log.Debugf("Configured IP Whitelists: %v", frontend.WhitelistSourceRange) + } handler := s.tracingMiddleware.NewNegroniHandlerWrapper( "IP whitelist", From 4cb1ae46261ca70a78ec412bdb74f813a7f92d25 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 2 Oct 2018 16:28:04 +0200 Subject: [PATCH 18/23] Colored logs on windows. --- Gopkg.lock | 10 +- .../go-windows-terminal-sequences/license | 9 ++ .../sequences.go | 36 ++++++ vendor/github.com/sirupsen/logrus/entry.go | 107 ++++++++++------- vendor/github.com/sirupsen/logrus/exported.go | 39 +++--- .../github.com/sirupsen/logrus/formatter.go | 20 ++-- .../sirupsen/logrus/json_formatter.go | 33 +++++- vendor/github.com/sirupsen/logrus/logger.go | 90 ++++++++++---- vendor/github.com/sirupsen/logrus/logrus.go | 7 ++ .../sirupsen/logrus/terminal_appengine.go | 13 ++ .../sirupsen/logrus/terminal_bsd.go | 11 +- .../sirupsen/logrus/terminal_check_js.go | 11 ++ .../logrus/terminal_check_notappengine.go | 2 +- .../sirupsen/logrus/terminal_check_windows.go | 20 ++++ .../sirupsen/logrus/terminal_linux.go | 11 +- .../sirupsen/logrus/terminal_windows.go | 18 +++ .../sirupsen/logrus/text_formatter.go | 111 ++++++++++++++---- 17 files changed, 427 insertions(+), 121 deletions(-) create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/license create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_appengine.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_js.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_windows.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_windows.go diff --git a/Gopkg.lock b/Gopkg.lock index fe8ee8cd4..bd4da3543 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -839,6 +839,12 @@ revision = "59fac5042749a5afb9af70e813da1dd5474f0167" version = "1.0.1" +[[projects]] + branch = "master" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + revision = "b729f2633dfe35f4d1d8a32385f6685610ce1cb5" + [[projects]] branch = "master" name = "github.com/kr/logfmt" @@ -1173,8 +1179,8 @@ [[projects]] name = "github.com/sirupsen/logrus" packages = ["."] - revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba" - version = "v1.0.4" + revision = "a67f783a3814b8729bd2dac5780b5f78f8dbd64d" + version = "v1.1.0" [[projects]] name = "github.com/spf13/pflag" diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/license b/vendor/github.com/konsorten/go-windows-terminal-sequences/license new file mode 100644 index 000000000..14127cd83 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/license @@ -0,0 +1,9 @@ +(The MIT License) + +Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go new file mode 100644 index 000000000..ef18d8f97 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go @@ -0,0 +1,36 @@ +// +build windows + +package sequences + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll") + setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode") +) + +func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error { + const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4 + + var mode uint32 + err := syscall.GetConsoleMode(syscall.Stdout, &mode) + if err != nil { + return err + } + + if enable { + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } else { + mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } + + ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode)) + if ret == 0 { + return err + } + + return nil +} diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go index 1fad45e08..4efedddfe 100644 --- a/vendor/github.com/sirupsen/logrus/entry.go +++ b/vendor/github.com/sirupsen/logrus/entry.go @@ -41,14 +41,14 @@ type Entry struct { // Message passed to Debug, Info, Warn, Error, Fatal or Panic Message string - // When formatter is called in entry.log(), an Buffer may be set to entry + // When formatter is called in entry.log(), a Buffer may be set to entry Buffer *bytes.Buffer } func NewEntry(logger *Logger) *Entry { return &Entry{ Logger: logger, - // Default is three fields, give a little extra room + // Default is five fields, give a little extra room Data: make(Fields, 5), } } @@ -83,43 +83,41 @@ func (entry *Entry) WithFields(fields Fields) *Entry { for k, v := range fields { data[k] = v } - return &Entry{Logger: entry.Logger, Data: data} + return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time} +} + +// Overrides the time of the Entry. +func (entry *Entry) WithTime(t time.Time) *Entry { + return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t} } // This function is not declared with a pointer value because otherwise // race conditions will occur when using multiple goroutines func (entry Entry) log(level Level, msg string) { var buffer *bytes.Buffer - entry.Time = time.Now() + + // Default to now, but allow users to override if they want. + // + // We don't have to worry about polluting future calls to Entry#log() + // with this assignment because this function is declared with a + // non-pointer receiver. + if entry.Time.IsZero() { + entry.Time = time.Now() + } + entry.Level = level entry.Message = msg - entry.Logger.mu.Lock() - err := entry.Logger.Hooks.Fire(level, &entry) - entry.Logger.mu.Unlock() - if err != nil { - entry.Logger.mu.Lock() - fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) - entry.Logger.mu.Unlock() - } + entry.fireHooks() + buffer = bufferPool.Get().(*bytes.Buffer) buffer.Reset() defer bufferPool.Put(buffer) entry.Buffer = buffer - serialized, err := entry.Logger.Formatter.Format(&entry) + + entry.write() + entry.Buffer = nil - if err != nil { - entry.Logger.mu.Lock() - fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) - entry.Logger.mu.Unlock() - } else { - entry.Logger.mu.Lock() - _, err = entry.Logger.Out.Write(serialized) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) - } - entry.Logger.mu.Unlock() - } // To avoid Entry#log() returning a value that only would make sense for // panic() to use in Entry#Panic(), we avoid the allocation by checking @@ -129,8 +127,31 @@ func (entry Entry) log(level Level, msg string) { } } +func (entry *Entry) fireHooks() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + err := entry.Logger.Hooks.Fire(entry.Level, entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + } +} + +func (entry *Entry) write() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + } else { + _, err = entry.Logger.Out.Write(serialized) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } + } +} + func (entry *Entry) Debug(args ...interface{}) { - if entry.Logger.level() >= DebugLevel { + if entry.Logger.IsLevelEnabled(DebugLevel) { entry.log(DebugLevel, fmt.Sprint(args...)) } } @@ -140,13 +161,13 @@ func (entry *Entry) Print(args ...interface{}) { } func (entry *Entry) Info(args ...interface{}) { - if entry.Logger.level() >= InfoLevel { + if entry.Logger.IsLevelEnabled(InfoLevel) { entry.log(InfoLevel, fmt.Sprint(args...)) } } func (entry *Entry) Warn(args ...interface{}) { - if entry.Logger.level() >= WarnLevel { + if entry.Logger.IsLevelEnabled(WarnLevel) { entry.log(WarnLevel, fmt.Sprint(args...)) } } @@ -156,20 +177,20 @@ func (entry *Entry) Warning(args ...interface{}) { } func (entry *Entry) Error(args ...interface{}) { - if entry.Logger.level() >= ErrorLevel { + if entry.Logger.IsLevelEnabled(ErrorLevel) { entry.log(ErrorLevel, fmt.Sprint(args...)) } } func (entry *Entry) Fatal(args ...interface{}) { - if entry.Logger.level() >= FatalLevel { + if entry.Logger.IsLevelEnabled(FatalLevel) { entry.log(FatalLevel, fmt.Sprint(args...)) } Exit(1) } func (entry *Entry) Panic(args ...interface{}) { - if entry.Logger.level() >= PanicLevel { + if entry.Logger.IsLevelEnabled(PanicLevel) { entry.log(PanicLevel, fmt.Sprint(args...)) } panic(fmt.Sprint(args...)) @@ -178,13 +199,13 @@ func (entry *Entry) Panic(args ...interface{}) { // Entry Printf family functions func (entry *Entry) Debugf(format string, args ...interface{}) { - if entry.Logger.level() >= DebugLevel { + if entry.Logger.IsLevelEnabled(DebugLevel) { entry.Debug(fmt.Sprintf(format, args...)) } } func (entry *Entry) Infof(format string, args ...interface{}) { - if entry.Logger.level() >= InfoLevel { + if entry.Logger.IsLevelEnabled(InfoLevel) { entry.Info(fmt.Sprintf(format, args...)) } } @@ -194,7 +215,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) { } func (entry *Entry) Warnf(format string, args ...interface{}) { - if entry.Logger.level() >= WarnLevel { + if entry.Logger.IsLevelEnabled(WarnLevel) { entry.Warn(fmt.Sprintf(format, args...)) } } @@ -204,20 +225,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) { } func (entry *Entry) Errorf(format string, args ...interface{}) { - if entry.Logger.level() >= ErrorLevel { + if entry.Logger.IsLevelEnabled(ErrorLevel) { entry.Error(fmt.Sprintf(format, args...)) } } func (entry *Entry) Fatalf(format string, args ...interface{}) { - if entry.Logger.level() >= FatalLevel { + if entry.Logger.IsLevelEnabled(FatalLevel) { entry.Fatal(fmt.Sprintf(format, args...)) } Exit(1) } func (entry *Entry) Panicf(format string, args ...interface{}) { - if entry.Logger.level() >= PanicLevel { + if entry.Logger.IsLevelEnabled(PanicLevel) { entry.Panic(fmt.Sprintf(format, args...)) } } @@ -225,13 +246,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) { // Entry Println family functions func (entry *Entry) Debugln(args ...interface{}) { - if entry.Logger.level() >= DebugLevel { + if entry.Logger.IsLevelEnabled(DebugLevel) { entry.Debug(entry.sprintlnn(args...)) } } func (entry *Entry) Infoln(args ...interface{}) { - if entry.Logger.level() >= InfoLevel { + if entry.Logger.IsLevelEnabled(InfoLevel) { entry.Info(entry.sprintlnn(args...)) } } @@ -241,7 +262,7 @@ func (entry *Entry) Println(args ...interface{}) { } func (entry *Entry) Warnln(args ...interface{}) { - if entry.Logger.level() >= WarnLevel { + if entry.Logger.IsLevelEnabled(WarnLevel) { entry.Warn(entry.sprintlnn(args...)) } } @@ -251,20 +272,20 @@ func (entry *Entry) Warningln(args ...interface{}) { } func (entry *Entry) Errorln(args ...interface{}) { - if entry.Logger.level() >= ErrorLevel { + if entry.Logger.IsLevelEnabled(ErrorLevel) { entry.Error(entry.sprintlnn(args...)) } } func (entry *Entry) Fatalln(args ...interface{}) { - if entry.Logger.level() >= FatalLevel { + if entry.Logger.IsLevelEnabled(FatalLevel) { entry.Fatal(entry.sprintlnn(args...)) } Exit(1) } func (entry *Entry) Panicln(args ...interface{}) { - if entry.Logger.level() >= PanicLevel { + if entry.Logger.IsLevelEnabled(PanicLevel) { entry.Panic(entry.sprintlnn(args...)) } } diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go index 013183eda..fb2a7a1f0 100644 --- a/vendor/github.com/sirupsen/logrus/exported.go +++ b/vendor/github.com/sirupsen/logrus/exported.go @@ -2,6 +2,7 @@ package logrus import ( "io" + "time" ) var ( @@ -15,37 +16,32 @@ func StandardLogger() *Logger { // SetOutput sets the standard logger output. func SetOutput(out io.Writer) { - std.mu.Lock() - defer std.mu.Unlock() - std.Out = out + std.SetOutput(out) } // SetFormatter sets the standard logger formatter. func SetFormatter(formatter Formatter) { - std.mu.Lock() - defer std.mu.Unlock() - std.Formatter = formatter + std.SetFormatter(formatter) } // SetLevel sets the standard logger level. func SetLevel(level Level) { - std.mu.Lock() - defer std.mu.Unlock() std.SetLevel(level) } // GetLevel returns the standard logger level. func GetLevel() Level { - std.mu.Lock() - defer std.mu.Unlock() - return std.level() + return std.GetLevel() +} + +// IsLevelEnabled checks if the log level of the standard logger is greater than the level param +func IsLevelEnabled(level Level) bool { + return std.IsLevelEnabled(level) } // AddHook adds a hook to the standard logger hooks. func AddHook(hook Hook) { - std.mu.Lock() - defer std.mu.Unlock() - std.Hooks.Add(hook) + std.AddHook(hook) } // WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. @@ -72,6 +68,15 @@ func WithFields(fields Fields) *Entry { return std.WithFields(fields) } +// WithTime creats an entry from the standard logger and overrides the time of +// logs generated with it. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithTime(t time.Time) *Entry { + return std.WithTime(t) +} + // Debug logs a message at level Debug on the standard logger. func Debug(args ...interface{}) { std.Debug(args...) @@ -107,7 +112,7 @@ func Panic(args ...interface{}) { std.Panic(args...) } -// Fatal logs a message at level Fatal on the standard logger. +// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func Fatal(args ...interface{}) { std.Fatal(args...) } @@ -147,7 +152,7 @@ func Panicf(format string, args ...interface{}) { std.Panicf(format, args...) } -// Fatalf logs a message at level Fatal on the standard logger. +// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func Fatalf(format string, args ...interface{}) { std.Fatalf(format, args...) } @@ -187,7 +192,7 @@ func Panicln(args ...interface{}) { std.Panicln(args...) } -// Fatalln logs a message at level Fatal on the standard logger. +// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func Fatalln(args ...interface{}) { std.Fatalln(args...) } diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go index b183ff5b1..83c74947b 100644 --- a/vendor/github.com/sirupsen/logrus/formatter.go +++ b/vendor/github.com/sirupsen/logrus/formatter.go @@ -30,16 +30,22 @@ type Formatter interface { // // It's not exported because it's still using Data in an opinionated way. It's to // avoid code duplication between the two default formatters. -func prefixFieldClashes(data Fields) { - if t, ok := data["time"]; ok { - data["fields.time"] = t +func prefixFieldClashes(data Fields, fieldMap FieldMap) { + timeKey := fieldMap.resolve(FieldKeyTime) + if t, ok := data[timeKey]; ok { + data["fields."+timeKey] = t + delete(data, timeKey) } - if m, ok := data["msg"]; ok { - data["fields.msg"] = m + msgKey := fieldMap.resolve(FieldKeyMsg) + if m, ok := data[msgKey]; ok { + data["fields."+msgKey] = m + delete(data, msgKey) } - if l, ok := data["level"]; ok { - data["fields.level"] = l + levelKey := fieldMap.resolve(FieldKeyLevel) + if l, ok := data[levelKey]; ok { + data["fields."+levelKey] = l + delete(data, levelKey) } } diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go index fb01c1b10..d3dadefe6 100644 --- a/vendor/github.com/sirupsen/logrus/json_formatter.go +++ b/vendor/github.com/sirupsen/logrus/json_formatter.go @@ -1,6 +1,7 @@ package logrus import ( + "bytes" "encoding/json" "fmt" ) @@ -33,6 +34,9 @@ type JSONFormatter struct { // DisableTimestamp allows disabling automatic timestamps in output DisableTimestamp bool + // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. + DataKey string + // FieldMap allows users to customize the names of keys for default fields. // As an example: // formatter := &JSONFormatter{ @@ -43,6 +47,9 @@ type JSONFormatter struct { // }, // } FieldMap FieldMap + + // PrettyPrint will indent all json logs + PrettyPrint bool } // Format renders a single log entry @@ -58,7 +65,14 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[k] = v } } - prefixFieldClashes(data) + + if f.DataKey != "" { + newData := make(Fields, 4) + newData[f.DataKey] = data + data = newData + } + + prefixFieldClashes(data, f.FieldMap) timestampFormat := f.TimestampFormat if timestampFormat == "" { @@ -71,9 +85,20 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() - serialized, err := json.Marshal(data) - if err != nil { + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + encoder := json.NewEncoder(b) + if f.PrettyPrint { + encoder.SetIndent("", " ") + } + if err := encoder.Encode(data); err != nil { return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) } - return append(serialized, '\n'), nil + + return b.Bytes(), nil } diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go index fdaf8a653..b67bfcbd3 100644 --- a/vendor/github.com/sirupsen/logrus/logger.go +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -5,12 +5,13 @@ import ( "os" "sync" "sync/atomic" + "time" ) type Logger struct { // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a // file, or leave it default which is `os.Stderr`. You can also set this to - // something more adventorous, such as logging to Kafka. + // something more adventurous, such as logging to Kafka. Out io.Writer // Hooks for the logger instance. These allow firing events based on logging // levels and log entries. For example, to send errors to an error tracking @@ -84,11 +85,12 @@ func (logger *Logger) newEntry() *Entry { } func (logger *Logger) releaseEntry(entry *Entry) { + entry.Data = map[string]interface{}{} logger.entryPool.Put(entry) } // Adds a field to the log entry, note that it doesn't log until you call -// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. +// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. // If you want multiple fields, use `WithFields`. func (logger *Logger) WithField(key string, value interface{}) *Entry { entry := logger.newEntry() @@ -112,8 +114,15 @@ func (logger *Logger) WithError(err error) *Entry { return entry.WithError(err) } +// Overrides the time of the log entry. +func (logger *Logger) WithTime(t time.Time) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithTime(t) +} + func (logger *Logger) Debugf(format string, args ...interface{}) { - if logger.level() >= DebugLevel { + if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() entry.Debugf(format, args...) logger.releaseEntry(entry) @@ -121,7 +130,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) { } func (logger *Logger) Infof(format string, args ...interface{}) { - if logger.level() >= InfoLevel { + if logger.IsLevelEnabled(InfoLevel) { entry := logger.newEntry() entry.Infof(format, args...) logger.releaseEntry(entry) @@ -135,7 +144,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) { } func (logger *Logger) Warnf(format string, args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -143,7 +152,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) { } func (logger *Logger) Warningf(format string, args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -151,7 +160,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) { } func (logger *Logger) Errorf(format string, args ...interface{}) { - if logger.level() >= ErrorLevel { + if logger.IsLevelEnabled(ErrorLevel) { entry := logger.newEntry() entry.Errorf(format, args...) logger.releaseEntry(entry) @@ -159,7 +168,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) { } func (logger *Logger) Fatalf(format string, args ...interface{}) { - if logger.level() >= FatalLevel { + if logger.IsLevelEnabled(FatalLevel) { entry := logger.newEntry() entry.Fatalf(format, args...) logger.releaseEntry(entry) @@ -168,7 +177,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) { } func (logger *Logger) Panicf(format string, args ...interface{}) { - if logger.level() >= PanicLevel { + if logger.IsLevelEnabled(PanicLevel) { entry := logger.newEntry() entry.Panicf(format, args...) logger.releaseEntry(entry) @@ -176,7 +185,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) { } func (logger *Logger) Debug(args ...interface{}) { - if logger.level() >= DebugLevel { + if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() entry.Debug(args...) logger.releaseEntry(entry) @@ -184,7 +193,7 @@ func (logger *Logger) Debug(args ...interface{}) { } func (logger *Logger) Info(args ...interface{}) { - if logger.level() >= InfoLevel { + if logger.IsLevelEnabled(InfoLevel) { entry := logger.newEntry() entry.Info(args...) logger.releaseEntry(entry) @@ -198,7 +207,7 @@ func (logger *Logger) Print(args ...interface{}) { } func (logger *Logger) Warn(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -206,7 +215,7 @@ func (logger *Logger) Warn(args ...interface{}) { } func (logger *Logger) Warning(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -214,7 +223,7 @@ func (logger *Logger) Warning(args ...interface{}) { } func (logger *Logger) Error(args ...interface{}) { - if logger.level() >= ErrorLevel { + if logger.IsLevelEnabled(ErrorLevel) { entry := logger.newEntry() entry.Error(args...) logger.releaseEntry(entry) @@ -222,7 +231,7 @@ func (logger *Logger) Error(args ...interface{}) { } func (logger *Logger) Fatal(args ...interface{}) { - if logger.level() >= FatalLevel { + if logger.IsLevelEnabled(FatalLevel) { entry := logger.newEntry() entry.Fatal(args...) logger.releaseEntry(entry) @@ -231,7 +240,7 @@ func (logger *Logger) Fatal(args ...interface{}) { } func (logger *Logger) Panic(args ...interface{}) { - if logger.level() >= PanicLevel { + if logger.IsLevelEnabled(PanicLevel) { entry := logger.newEntry() entry.Panic(args...) logger.releaseEntry(entry) @@ -239,7 +248,7 @@ func (logger *Logger) Panic(args ...interface{}) { } func (logger *Logger) Debugln(args ...interface{}) { - if logger.level() >= DebugLevel { + if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() entry.Debugln(args...) logger.releaseEntry(entry) @@ -247,7 +256,7 @@ func (logger *Logger) Debugln(args ...interface{}) { } func (logger *Logger) Infoln(args ...interface{}) { - if logger.level() >= InfoLevel { + if logger.IsLevelEnabled(InfoLevel) { entry := logger.newEntry() entry.Infoln(args...) logger.releaseEntry(entry) @@ -261,7 +270,7 @@ func (logger *Logger) Println(args ...interface{}) { } func (logger *Logger) Warnln(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -269,7 +278,7 @@ func (logger *Logger) Warnln(args ...interface{}) { } func (logger *Logger) Warningln(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -277,7 +286,7 @@ func (logger *Logger) Warningln(args ...interface{}) { } func (logger *Logger) Errorln(args ...interface{}) { - if logger.level() >= ErrorLevel { + if logger.IsLevelEnabled(ErrorLevel) { entry := logger.newEntry() entry.Errorln(args...) logger.releaseEntry(entry) @@ -285,7 +294,7 @@ func (logger *Logger) Errorln(args ...interface{}) { } func (logger *Logger) Fatalln(args ...interface{}) { - if logger.level() >= FatalLevel { + if logger.IsLevelEnabled(FatalLevel) { entry := logger.newEntry() entry.Fatalln(args...) logger.releaseEntry(entry) @@ -294,7 +303,7 @@ func (logger *Logger) Fatalln(args ...interface{}) { } func (logger *Logger) Panicln(args ...interface{}) { - if logger.level() >= PanicLevel { + if logger.IsLevelEnabled(PanicLevel) { entry := logger.newEntry() entry.Panicln(args...) logger.releaseEntry(entry) @@ -312,12 +321,47 @@ func (logger *Logger) level() Level { return Level(atomic.LoadUint32((*uint32)(&logger.Level))) } +// SetLevel sets the logger level. func (logger *Logger) SetLevel(level Level) { atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) } +// GetLevel returns the logger level. +func (logger *Logger) GetLevel() Level { + return logger.level() +} + +// AddHook adds a hook to the logger hooks. func (logger *Logger) AddHook(hook Hook) { logger.mu.Lock() defer logger.mu.Unlock() logger.Hooks.Add(hook) } + +// IsLevelEnabled checks if the log level of the logger is greater than the level param +func (logger *Logger) IsLevelEnabled(level Level) bool { + return logger.level() >= level +} + +// SetFormatter sets the logger formatter. +func (logger *Logger) SetFormatter(formatter Formatter) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Formatter = formatter +} + +// SetOutput sets the logger output. +func (logger *Logger) SetOutput(output io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Out = output +} + +// ReplaceHooks replaces the logger hooks and returns the old ones +func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { + logger.mu.Lock() + oldHooks := logger.Hooks + logger.Hooks = hooks + logger.mu.Unlock() + return oldHooks +} diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go index dd3899974..fa0b9dea8 100644 --- a/vendor/github.com/sirupsen/logrus/logrus.go +++ b/vendor/github.com/sirupsen/logrus/logrus.go @@ -140,4 +140,11 @@ type FieldLogger interface { Errorln(args ...interface{}) Fatalln(args ...interface{}) Panicln(args ...interface{}) + + // IsDebugEnabled() bool + // IsInfoEnabled() bool + // IsWarnEnabled() bool + // IsErrorEnabled() bool + // IsFatalEnabled() bool + // IsPanicEnabled() bool } diff --git a/vendor/github.com/sirupsen/logrus/terminal_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_appengine.go new file mode 100644 index 000000000..72f679cdb --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_appengine.go @@ -0,0 +1,13 @@ +// Based on ssh/terminal: +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +package logrus + +import "io" + +func initTerminal(w io.Writer) { +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_bsd.go index d7b3893f3..62ca252d0 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_bsd.go +++ b/vendor/github.com/sirupsen/logrus/terminal_bsd.go @@ -1,10 +1,17 @@ // +build darwin freebsd openbsd netbsd dragonfly -// +build !appengine +// +build !appengine,!js package logrus -import "golang.org/x/sys/unix" +import ( + "io" + + "golang.org/x/sys/unix" +) const ioctlReadTermios = unix.TIOCGETA type Termios unix.Termios + +func initTerminal(w io.Writer) { +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/sirupsen/logrus/terminal_check_js.go new file mode 100644 index 000000000..0c209750a --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_js.go @@ -0,0 +1,11 @@ +// +build js + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go index 116bcb4e3..cf309d6fb 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go @@ -1,4 +1,4 @@ -// +build !appengine +// +build !appengine,!js,!windows package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go new file mode 100644 index 000000000..3b9d2864c --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go @@ -0,0 +1,20 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + var mode uint32 + err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) + return err == nil + default: + return false + } +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_linux.go b/vendor/github.com/sirupsen/logrus/terminal_linux.go index 88d7298e2..18066f08a 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_linux.go +++ b/vendor/github.com/sirupsen/logrus/terminal_linux.go @@ -3,12 +3,19 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !appengine +// +build !appengine,!js package logrus -import "golang.org/x/sys/unix" +import ( + "io" + + "golang.org/x/sys/unix" +) const ioctlReadTermios = unix.TCGETS type Termios unix.Termios + +func initTerminal(w io.Writer) { +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_windows.go b/vendor/github.com/sirupsen/logrus/terminal_windows.go new file mode 100644 index 000000000..b4ef5286c --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_windows.go @@ -0,0 +1,18 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func initTerminal(w io.Writer) { + switch v := w.(type) { + case *os.File: + sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true) + } +} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go index 61b21caea..67fb686c6 100644 --- a/vendor/github.com/sirupsen/logrus/text_formatter.go +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -3,6 +3,7 @@ package logrus import ( "bytes" "fmt" + "os" "sort" "strings" "sync" @@ -20,6 +21,7 @@ const ( var ( baseTimestamp time.Time + emptyFieldMap FieldMap ) func init() { @@ -34,6 +36,9 @@ type TextFormatter struct { // Force disabling colors. DisableColors bool + // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ + EnvironmentOverrideColors bool + // Disable timestamp logging. useful when output is redirected to logging // system that already adds timestamps. DisableTimestamp bool @@ -50,60 +55,119 @@ type TextFormatter struct { // be desired. DisableSorting bool + // The keys sorting function, when uninitialized it uses sort.Strings. + SortingFunc func([]string) + + // Disables the truncation of the level text to 4 characters. + DisableLevelTruncation bool + // QuoteEmptyFields will wrap empty fields in quotes if true QuoteEmptyFields bool // Whether the logger's out is to a terminal isTerminal bool - sync.Once + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &TextFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message"}} + FieldMap FieldMap + + terminalInitOnce sync.Once } func (f *TextFormatter) init(entry *Entry) { if entry.Logger != nil { f.isTerminal = checkIfTerminal(entry.Logger.Out) + + if f.isTerminal { + initTerminal(entry.Logger.Out) + } } } +func (f *TextFormatter) isColored() bool { + isColored := f.ForceColors || f.isTerminal + + if f.EnvironmentOverrideColors { + if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { + isColored = true + } else if ok && force == "0" { + isColored = false + } else if os.Getenv("CLICOLOR") == "0" { + isColored = false + } + } + + return isColored && !f.DisableColors +} + // Format renders a single log entry func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { - var b *bytes.Buffer + prefixFieldClashes(entry.Data, f.FieldMap) + keys := make([]string, 0, len(entry.Data)) for k := range entry.Data { keys = append(keys, k) } - if !f.DisableSorting { - sort.Strings(keys) + fixedKeys := make([]string, 0, 3+len(entry.Data)) + if !f.DisableTimestamp { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) } + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) + if entry.Message != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) + } + + if !f.DisableSorting { + if f.SortingFunc == nil { + sort.Strings(keys) + fixedKeys = append(fixedKeys, keys...) + } else { + if !f.isColored() { + fixedKeys = append(fixedKeys, keys...) + f.SortingFunc(fixedKeys) + } else { + f.SortingFunc(keys) + } + } + } else { + fixedKeys = append(fixedKeys, keys...) + } + + var b *bytes.Buffer if entry.Buffer != nil { b = entry.Buffer } else { b = &bytes.Buffer{} } - prefixFieldClashes(entry.Data) - - f.Do(func() { f.init(entry) }) - - isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors + f.terminalInitOnce.Do(func() { f.init(entry) }) timestampFormat := f.TimestampFormat if timestampFormat == "" { timestampFormat = defaultTimestampFormat } - if isColored { + if f.isColored() { f.printColored(b, entry, keys, timestampFormat) } else { - if !f.DisableTimestamp { - f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) - } - f.appendKeyValue(b, "level", entry.Level.String()) - if entry.Message != "" { - f.appendKeyValue(b, "msg", entry.Message) - } - for _, key := range keys { - f.appendKeyValue(b, key, entry.Data[key]) + for _, key := range fixedKeys { + var value interface{} + switch key { + case f.FieldMap.resolve(FieldKeyTime): + value = entry.Time.Format(timestampFormat) + case f.FieldMap.resolve(FieldKeyLevel): + value = entry.Level.String() + case f.FieldMap.resolve(FieldKeyMsg): + value = entry.Message + default: + value = entry.Data[key] + } + f.appendKeyValue(b, key, value) } } @@ -124,7 +188,14 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin levelColor = blue } - levelText := strings.ToUpper(entry.Level.String())[0:4] + levelText := strings.ToUpper(entry.Level.String()) + if !f.DisableLevelTruncation { + levelText = levelText[0:4] + } + + // Remove a single newline if it already exists in the message to keep + // the behavior of logrus text_formatter the same as the stdlib log package + entry.Message = strings.TrimSuffix(entry.Message, "\n") if f.DisableTimestamp { fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) From 44e06a1a1e0fc5502049e9da0881dcf83ad8d80c Mon Sep 17 00:00:00 2001 From: Oliver Moser Date: Wed, 3 Oct 2018 22:52:02 +0200 Subject: [PATCH 19/23] Trimming whitespace in XFF for IP whitelisting --- whitelist/ip.go | 5 +++-- whitelist/ip_test.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/whitelist/ip.go b/whitelist/ip.go index bfb74e007..89db04cb4 100644 --- a/whitelist/ip.go +++ b/whitelist/ip.go @@ -63,7 +63,8 @@ func (ip *IP) IsAuthorized(req *http.Request) error { for _, xFF := range xFFs { xffs := strings.Split(xFF, ",") for _, xff := range xffs { - ok, err := ip.contains(parseHost(xff)) + xffTrimmed := strings.TrimSpace(xff) + ok, err := ip.contains(parseHost(xffTrimmed)) if err != nil { return err } @@ -72,7 +73,7 @@ func (ip *IP) IsAuthorized(req *http.Request) error { return nil } - invalidMatches = append(invalidMatches, xff) + invalidMatches = append(invalidMatches, xffTrimmed) } } } diff --git a/whitelist/ip_test.go b/whitelist/ip_test.go index 0b0efefc0..b4c43ef51 100644 --- a/whitelist/ip_test.go +++ b/whitelist/ip_test.go @@ -32,7 +32,7 @@ func TestIsAuthorized(t *testing.T) { whiteList: []string{"1.2.3.4/24"}, allowXForwardedFor: true, remoteAddr: "10.2.3.1:123", - xForwardedForValues: []string{"1.2.3.1, 10.2.3.1"}, + xForwardedForValues: []string{"10.2.3.1, 1.2.3.1"}, authorized: true, }, { From d69977c2291f3a83eb209af1af7e7d6349168bbd Mon Sep 17 00:00:00 2001 From: Timo Reimann Date: Thu, 4 Oct 2018 09:26:03 +0200 Subject: [PATCH 20/23] Do not Errorf during file watcher verification test loop. --- provider/file/file_test.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/provider/file/file_test.go b/provider/file/file_test.go index 1e62175ae..eae4f847f 100644 --- a/provider/file/file_test.go +++ b/provider/file/file_test.go @@ -255,16 +255,21 @@ func TestProvideWithWatch(t *testing.T) { } timeout = time.After(time.Second * 1) - success := false - for !success { + var numUpdates, numBackends, numFrontends, numTLSConfs int + for { select { case config := <-configChan: - success = assert.Len(t, config.Configuration.Backends, test.expectedNumBackend) - success = success && assert.Len(t, config.Configuration.Frontends, test.expectedNumFrontend) - success = success && assert.Len(t, config.Configuration.TLS, test.expectedNumTLSConf) + numUpdates++ + numBackends = len(config.Configuration.Backends) + numFrontends = len(config.Configuration.Frontends) + numTLSConfs = len(config.Configuration.TLS) + t.Logf("received update #%d: backends %d/%d, frontends %d/%d, TLS configs %d/%d", numUpdates, numBackends, test.expectedNumBackend, numFrontends, test.expectedNumFrontend, numTLSConfs, test.expectedNumTLSConf) + + if numBackends == test.expectedNumBackend && numFrontends == test.expectedNumFrontend && numTLSConfs == test.expectedNumTLSConf { + return + } case <-timeout: - t.Errorf("timeout while waiting for config") - return + t.Fatal("timeout while waiting for config") } } }) From 31f92001e2e12378160541a41773c1529f4f76d4 Mon Sep 17 00:00:00 2001 From: Daniel Tomcej Date: Thu, 4 Oct 2018 02:58:03 -0500 Subject: [PATCH 21/23] Add Template-ability check to Kubernetes API Fields --- provider/kubernetes/annotations.go | 9 ++++++ provider/kubernetes/kubernetes.go | 31 ++++++++++++++---- provider/kubernetes/kubernetes_test.go | 45 ++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/provider/kubernetes/annotations.go b/provider/kubernetes/annotations.go index e85211b2f..03805a4a7 100644 --- a/provider/kubernetes/annotations.go +++ b/provider/kubernetes/annotations.go @@ -1,6 +1,8 @@ package kubernetes import ( + "strconv" + "github.com/containous/traefik/provider/label" ) @@ -106,6 +108,13 @@ func getStringValue(annotations map[string]string, annotation string, defaultVal return label.GetStringValue(annotations, annotationName, defaultValue) } +func getStringSafeValue(annotations map[string]string, annotation string, defaultValue string) (string, error) { + annotationName := getAnnotationName(annotations, annotation) + value := label.GetStringValue(annotations, annotationName, defaultValue) + _, err := strconv.Unquote(`"` + value + `"`) + return value, err +} + func getBoolValue(annotations map[string]string, annotation string, defaultValue bool) bool { annotationName := getAnnotationName(annotations, annotation) return label.GetBoolValue(annotations, annotationName, defaultValue) diff --git a/provider/kubernetes/kubernetes.go b/provider/kubernetes/kubernetes.go index 54af7caad..8f3d1d01a 100644 --- a/provider/kubernetes/kubernetes.go +++ b/provider/kubernetes/kubernetes.go @@ -179,8 +179,11 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) } for _, i := range ingresses { - annotationIngressClass := getAnnotationName(i.Annotations, annotationKubernetesIngressClass) - ingressClass := i.Annotations[annotationIngressClass] + ingressClass, err := getStringSafeValue(i.Annotations, annotationKubernetesIngressClass, "") + if err != nil { + log.Errorf("Misconfigured ingress class for ingress %s/%s: %v", i.Namespace, i.Name, err) + continue + } if !p.shouldProcessIngress(ingressClass) { continue @@ -221,6 +224,19 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) for _, pa := range r.HTTP.Paths { priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0) + + err := templateSafeString(r.Host) + if err != nil { + log.Errorf("failed to validate host %q for ingress %s/%s: %v", r.Host, i.Namespace, i.Name, err) + continue + } + + err = templateSafeString(pa.Path) + if err != nil { + log.Errorf("failed to validate path %q for ingress %s/%s: %v", pa.Path, i.Namespace, i.Name, err) + continue + } + baseName := r.Host + pa.Path if priority > 0 { baseName = strconv.Itoa(priority) + "-" + baseName @@ -882,15 +898,13 @@ func getFrontendRedirect(i *extensionsv1beta1.Ingress, baseName, path string) *t } } - redirectRegex := getStringValue(i.Annotations, annotationKubernetesRedirectRegex, "") - _, err := strconv.Unquote(`"` + redirectRegex + `"`) + redirectRegex, err := getStringSafeValue(i.Annotations, annotationKubernetesRedirectRegex, "") if err != nil { log.Debugf("Skipping Redirect on Ingress %s/%s due to invalid regex: %s", i.Namespace, i.Name, redirectRegex) return nil } - redirectReplacement := getStringValue(i.Annotations, annotationKubernetesRedirectReplacement, "") - _, err = strconv.Unquote(`"` + redirectReplacement + `"`) + redirectReplacement, err := getStringSafeValue(i.Annotations, annotationKubernetesRedirectReplacement, "") if err != nil { log.Debugf("Skipping Redirect on Ingress %s/%s due to invalid replacement: %q", i.Namespace, i.Name, redirectRegex) return nil @@ -1053,3 +1067,8 @@ func getRateLimit(i *extensionsv1beta1.Ingress) *types.RateLimit { return rateLimit } + +func templateSafeString(value string) error { + _, err := strconv.Unquote(`"` + value + `"`) + return err +} diff --git a/provider/kubernetes/kubernetes_test.go b/provider/kubernetes/kubernetes_test.go index 754e21841..329ebcde5 100644 --- a/provider/kubernetes/kubernetes_test.go +++ b/provider/kubernetes/kubernetes_test.go @@ -3431,3 +3431,48 @@ func TestAddGlobalBackendEndpointAPIError(t *testing.T) { err := provider.addGlobalBackend(client, ingresses, config) assert.Error(t, err) } + +func TestTemplateBreakingIngresssValues(t *testing.T) { + ingresses := []*extensionsv1beta1.Ingress{ + buildIngress( + iNamespace("testing"), + iAnnotation(annotationKubernetesIngressClass, "testing-\"foo\""), + iRules( + iRule( + iHost("foo"), + iPaths(onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))))), + ), + ), + buildIngress( + iNamespace("testing"), + iRules( + iRule( + iHost("testing-\"foo\""), + iPaths(onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))))), + ), + ), + buildIngress( + iNamespace("testing"), + iRules( + iRule( + iHost("foo"), + iPaths(onePath(iPath("/testing-\"foo\""), iBackend("service1", intstr.FromInt(80))))), + ), + ), + } + + client := clientMock{ + ingresses: ingresses, + } + provider := Provider{} + + actual, err := provider.loadIngresses(client) + require.NoError(t, err, "error loading ingresses") + + expected := buildConfiguration( + backends(), + frontends(), + ) + + assert.Equal(t, expected, actual) +} From ec86149b1e105547f96729ea2e362835e892b466 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Thu, 4 Oct 2018 10:20:03 +0200 Subject: [PATCH 22/23] Rule parsing error. --- rules/rules.go | 3 +++ rules/rules_test.go | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/rules/rules.go b/rules/rules.go index 093d031d1..44332261b 100644 --- a/rules/rules.go +++ b/rules/rules.go @@ -269,6 +269,9 @@ func (r *Rules) Parse(expression string) (*mux.Route, error) { if r.err != nil { return r.err } + if resultRoute == nil { + return fmt.Errorf("invalid expression: %s", expression) + } if resultRoute.GetError() != nil { return resultRoute.GetError() } diff --git a/rules/rules_test.go b/rules/rules_test.go index 0db618218..7239ad750 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -218,11 +218,17 @@ func TestHostRegexp(t *testing.T) { } } -type fakeHandler struct { - name string -} +func TestParseInvalidSyntax(t *testing.T) { + router := mux.NewRouter() + router.StrictSlash(true) -func (h *fakeHandler) ServeHTTP(http.ResponseWriter, *http.Request) {} + rules := &Rules{Route: &types.ServerRoute{Route: router.NewRoute()}} + expression01 := "Path: /path1;Query:param_one=true, /path2" + + routeFoo, err := rules.Parse(expression01) + require.Error(t, err) + assert.Nil(t, routeFoo) +} func TestPathPrefix(t *testing.T) { testCases := []struct { @@ -287,3 +293,9 @@ func TestPathPrefix(t *testing.T) { }) } } + +type fakeHandler struct { + name string +} + +func (h *fakeHandler) ServeHTTP(http.ResponseWriter, *http.Request) {} From a9deeb321bfc90104964edad0b9949bff7388e82 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Doumenjou Date: Thu, 4 Oct 2018 15:34:02 +0200 Subject: [PATCH 23/23] Prepare release v1.7.2 --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67c99eaca..62ef5602b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Change Log +## [v1.7.2](https://github.com/containous/traefik/tree/v1.7.2) (2018-10-04) +[All Commits](https://github.com/containous/traefik/compare/v1.7.1...v1.7.2) + +**Bug fixes:** +- **[acme,cluster,kv]** TLS, ACME, cluster and several entrypoints. ([#3962](https://github.com/containous/traefik/pull/3962) by [ldez](https://github.com/ldez)) +- **[cluster,kv]** Correctly initialize kv store if storage key missing ([#3958](https://github.com/containous/traefik/pull/3958) by [jfrabaute](https://github.com/jfrabaute)) +- **[cluster,kv]** Return an error if kv store CA cert is invalid ([#3956](https://github.com/containous/traefik/pull/3956) by [jfrabaute](https://github.com/jfrabaute)) +- **[file]** Do not Errorf during file watcher verification test loop. ([#3938](https://github.com/containous/traefik/pull/3938) by [timoreimann](https://github.com/timoreimann)) +- **[k8s]** Add Template-ability check to Kubernetes API Fields ([#3964](https://github.com/containous/traefik/pull/3964) by [dtomcej](https://github.com/dtomcej)) +- **[logs]** Colored logs on windows. ([#3966](https://github.com/containous/traefik/pull/3966) by [ldez](https://github.com/ldez)) +- **[middleware]** Whitelist log for deprecated configuration. ([#3963](https://github.com/containous/traefik/pull/3963) by [ldez](https://github.com/ldez)) +- **[middleware]** Trimming whitespace in XFF for IP whitelisting ([#3971](https://github.com/containous/traefik/pull/3971) by [olmoser](https://github.com/olmoser)) +- **[rules]** Rule parsing error. ([#3976](https://github.com/containous/traefik/pull/3976) by [ldez](https://github.com/ldez)) +- Global configuration log at start ([#3954](https://github.com/containous/traefik/pull/3954) by [ldez](https://github.com/ldez)) + +**Documentation:** +- **[logs]** Document the default accessLog format ([#3942](https://github.com/containous/traefik/pull/3942) by [dfredell](https://github.com/dfredell)) + ## [v1.7.1](https://github.com/containous/traefik/tree/v1.7.1) (2018-09-28) [All Commits](https://github.com/containous/traefik/compare/v1.7.0...v1.7.1)