diff --git a/integration/consul_test.go b/integration/consul_test.go index a6c1c192f..52cc4f13e 100644 --- a/integration/consul_test.go +++ b/integration/consul_test.go @@ -585,21 +585,14 @@ func (s *ConsulSuite) TestSNIDynamicTlsConfig(c *check.C) { }) c.Assert(err, checker.IsNil) - // wait for traefik - err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7hG")) - c.Assert(err, checker.IsNil) - req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client := &http.Client{Transport: tr1} req.Host = tr1.TLSClientConfig.ServerName req.Header.Set("Host", tr1.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - var resp *http.Response - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr1, try.HasCn("snitest.com")) c.Assert(err, checker.IsNil) - cn := resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "snitest.com") // now we configure the second keypair in consul and the request for host "snitest.org" will use the second keypair for key, value := range tlsconfigure2 { @@ -614,18 +607,12 @@ func (s *ConsulSuite) TestSNIDynamicTlsConfig(c *check.C) { }) c.Assert(err, checker.IsNil) - // waiting for traefik to pull configuration - err = try.GetRequest("http://127.0.0.1:8081/api/providers", 30*time.Second, try.BodyContains("MIIEogIBAAKCAQEAvG9kL+vF57+MICehzbqcQAUlAOSl5r")) - c.Assert(err, checker.IsNil) - req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client = &http.Client{Transport: tr2} req.Host = tr2.TLSClientConfig.ServerName req.Header.Set("Host", tr2.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr2, try.HasCn("snitest.org")) c.Assert(err, checker.IsNil) - cn = resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "snitest.org") } diff --git a/integration/etcd3_test.go b/integration/etcd3_test.go index 00dc755ed..d769e937d 100644 --- a/integration/etcd3_test.go +++ b/integration/etcd3_test.go @@ -532,21 +532,14 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - // wait for Træfik - err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains(string("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h"))) - c.Assert(err, checker.IsNil) - req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client := &http.Client{Transport: tr1} req.Host = tr1.TLSClientConfig.ServerName req.Header.Set("Host", tr1.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - var resp *http.Response - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr1, try.HasCn("snitest.com")) c.Assert(err, checker.IsNil) - cn := resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "snitest.com") // now we configure the second keypair in etcd and the request for host "snitest.org" will use the second keypair @@ -562,20 +555,14 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) { }) c.Assert(err, checker.IsNil) - // waiting for Træfik to pull configuration - err = try.GetRequest("http://127.0.0.1:8081/api/providers", 30*time.Second, try.BodyContains("MIIEogIBAAKCAQEAvG9kL+vF57+MICehzbqcQAUlAOSl5r")) - c.Assert(err, checker.IsNil) - req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client = &http.Client{Transport: tr2} req.Host = tr2.TLSClientConfig.ServerName req.Header.Set("Host", tr2.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr2, try.HasCn("snitest.org")) c.Assert(err, checker.IsNil) - cn = resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "snitest.org") } func (s *Etcd3Suite) TestDeleteSNIDynamicTlsConfig(c *check.C) { @@ -646,21 +633,14 @@ func (s *Etcd3Suite) TestDeleteSNIDynamicTlsConfig(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - // wait for Træfik - err = try.GetRequest(traefikWebEtcdURL+"api/providers", 60*time.Second, try.BodyContains(string("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h"))) - c.Assert(err, checker.IsNil) - req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client := &http.Client{Transport: tr1} req.Host = tr1.TLSClientConfig.ServerName req.Header.Set("Host", tr1.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - var resp *http.Response - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr1, try.HasCn("snitest.com")) c.Assert(err, checker.IsNil) - cn := resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "snitest.com") // now we delete the tls cert/key pairs,so the endpoint show use default cert/key pair for key := range tlsconfigure1 { @@ -668,18 +648,12 @@ func (s *Etcd3Suite) TestDeleteSNIDynamicTlsConfig(c *check.C) { c.Assert(err, checker.IsNil) } - // waiting for Træfik to pull configuration - err = try.GetRequest(traefikWebEtcdURL+"api/providers", 30*time.Second, try.BodyNotContains("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h")) - c.Assert(err, checker.IsNil) - req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client = &http.Client{Transport: tr1} req.Host = tr1.TLSClientConfig.ServerName req.Header.Set("Host", tr1.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr1, try.HasCn("TRAEFIK DEFAULT CERT")) c.Assert(err, checker.IsNil) - cn = resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "TRAEFIK DEFAULT CERT") } diff --git a/integration/etcd_test.go b/integration/etcd_test.go index 6e6133f86..9ae0e303f 100644 --- a/integration/etcd_test.go +++ b/integration/etcd_test.go @@ -548,21 +548,14 @@ func (s *EtcdSuite) TestSNIDynamicTlsConfig(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - // wait for Træfik - err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains(string("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h"))) - c.Assert(err, checker.IsNil) - req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client := &http.Client{Transport: tr1} req.Host = tr1.TLSClientConfig.ServerName req.Header.Set("Host", tr1.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - var resp *http.Response - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr1, try.HasCn("snitest.com")) c.Assert(err, checker.IsNil) - cn := resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "snitest.com") // now we configure the second keypair in etcd and the request for host "snitest.org" will use the second keypair @@ -578,18 +571,12 @@ func (s *EtcdSuite) TestSNIDynamicTlsConfig(c *check.C) { }) c.Assert(err, checker.IsNil) - // waiting for Træfik to pull configuration - err = try.GetRequest("http://127.0.0.1:8081/api/providers", 30*time.Second, try.BodyContains("MIIEogIBAAKCAQEAvG9kL+vF57+MICehzbqcQAUlAOSl5r")) - c.Assert(err, checker.IsNil) - req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil) c.Assert(err, checker.IsNil) - client = &http.Client{Transport: tr2} req.Host = tr2.TLSClientConfig.ServerName req.Header.Set("Host", tr2.TLSClientConfig.ServerName) req.Header.Set("Accept", "*/*") - resp, err = client.Do(req) + + err = try.RequestWithTransport(req, 30*time.Second, tr2, try.HasCn("snitest.org")) c.Assert(err, checker.IsNil) - cn = resp.TLS.PeerCertificates[0].Subject.CommonName - c.Assert(cn, checker.Equals, "snitest.org") } diff --git a/integration/fixtures/file/dir/simple2.toml b/integration/fixtures/file/dir/simple2.toml index e02f63550..dcbcffc57 100644 --- a/integration/fixtures/file/dir/simple2.toml +++ b/integration/fixtures/file/dir/simple2.toml @@ -2,7 +2,7 @@ [backends] [backends.backend2] [backends.backend2.servers.server1] - url = "http://172.17.0.2:80" + url = "http://172.17.0.123:80" weight = 1 [frontends] diff --git a/integration/try/condition.go b/integration/try/condition.go index 999b6256e..537859d53 100644 --- a/integration/try/condition.go +++ b/integration/try/condition.go @@ -88,6 +88,31 @@ func HasBody() ResponseCondition { } } +// HasCn returns a retry condition function. +// The condition returns an error if the cn is not correct. +func HasCn(cn string) ResponseCondition { + return func(res *http.Response) error { + if res.TLS == nil { + return errors.New("response doesn't have TLS") + } + + if len(res.TLS.PeerCertificates) == 0 { + return errors.New("response TLS doesn't have peer certificates") + } + + if res.TLS.PeerCertificates[0] == nil { + return errors.New("first peer certificate is nil") + } + + commonName := res.TLS.PeerCertificates[0].Subject.CommonName + if cn != commonName { + return fmt.Errorf("common name don't match: %s != %s", cn, commonName) + } + + return nil + } +} + // StatusCodeIs returns a retry condition function. // The condition returns an error if the given response's status code is not the // given HTTP status code. diff --git a/integration/try/try.go b/integration/try/try.go index f201cd0d8..0f75cbdaf 100644 --- a/integration/try/try.go +++ b/integration/try/try.go @@ -31,7 +31,7 @@ func Sleep(d time.Duration) { // response body needs to be closed or not. Callers are expected to close on // their own if the function returns a nil error. func Response(req *http.Request, timeout time.Duration) (*http.Response, error) { - return doTryRequest(req, timeout) + return doTryRequest(req, timeout, nil) } // ResponseUntilStatusCode is like Request, but returns the response for further @@ -40,7 +40,7 @@ func Response(req *http.Request, timeout time.Duration) (*http.Response, error) // response body needs to be closed or not. Callers are expected to close on // their own if the function returns a nil error. func ResponseUntilStatusCode(req *http.Request, timeout time.Duration, statusCode int) (*http.Response, error) { - return doTryRequest(req, timeout, StatusCodeIs(statusCode)) + return doTryRequest(req, timeout, nil, StatusCodeIs(statusCode)) } // GetRequest is like Do, but runs a request against the given URL and applies @@ -48,7 +48,7 @@ func ResponseUntilStatusCode(req *http.Request, timeout time.Duration, statusCod // ResponseCondition may be nil, in which case only the request against the URL must // succeed. func GetRequest(url string, timeout time.Duration, conditions ...ResponseCondition) error { - resp, err := doTryGet(url, timeout, conditions...) + resp, err := doTryGet(url, timeout, nil, conditions...) if resp != nil && resp.Body != nil { defer resp.Body.Close() @@ -62,7 +62,21 @@ func GetRequest(url string, timeout time.Duration, conditions ...ResponseConditi // ResponseCondition may be nil, in which case only the request against the URL must // succeed. func Request(req *http.Request, timeout time.Duration, conditions ...ResponseCondition) error { - resp, err := doTryRequest(req, timeout, conditions...) + resp, err := doTryRequest(req, timeout, nil, conditions...) + + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + + return err +} + +// RequestWithTransport is like Do, but runs a request against the given URL and applies +// the condition on the response. +// ResponseCondition may be nil, in which case only the request against the URL must +// succeed. +func RequestWithTransport(req *http.Request, timeout time.Duration, transport *http.Transport, conditions ...ResponseCondition) error { + resp, err := doTryRequest(req, timeout, transport, conditions...) if resp != nil && resp.Body != nil { defer resp.Body.Close() @@ -112,24 +126,27 @@ func Do(timeout time.Duration, operation DoCondition) error { } } -func doTryGet(url string, timeout time.Duration, conditions ...ResponseCondition) (*http.Response, error) { +func doTryGet(url string, timeout time.Duration, transport *http.Transport, conditions ...ResponseCondition) (*http.Response, error) { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, err } - return doTryRequest(req, timeout, conditions...) + return doTryRequest(req, timeout, transport, conditions...) } -func doTryRequest(request *http.Request, timeout time.Duration, conditions ...ResponseCondition) (*http.Response, error) { - return doRequest(Do, timeout, request, conditions...) +func doTryRequest(request *http.Request, timeout time.Duration, transport *http.Transport, conditions ...ResponseCondition) (*http.Response, error) { + return doRequest(Do, timeout, request, transport, conditions...) } -func doRequest(action timedAction, timeout time.Duration, request *http.Request, conditions ...ResponseCondition) (*http.Response, error) { +func doRequest(action timedAction, timeout time.Duration, request *http.Request, transport *http.Transport, conditions ...ResponseCondition) (*http.Response, error) { var resp *http.Response return resp, action(timeout, func() error { var err error client := http.DefaultClient + if transport != nil { + client.Transport = transport + } resp, err = client.Do(request) if err != nil { diff --git a/types/types.go b/types/types.go index 1ab95ac86..b92557afb 100644 --- a/types/types.go +++ b/types/types.go @@ -254,7 +254,7 @@ type Configurations map[string]*Configuration type Configuration struct { Backends map[string]*Backend `json:"backends,omitempty"` Frontends map[string]*Frontend `json:"frontends,omitempty"` - TLS []*traefiktls.Configuration `json:"tls,omitempty"` + TLS []*traefiktls.Configuration `json:"-"` } // ConfigMessage hold configuration information exchanged between parts of traefik.