Fix backend reuse
This commit is contained in:
parent
9cf4e730e7
commit
51227241b7
4 changed files with 94 additions and 8 deletions
|
@ -950,7 +950,15 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
redirectHandlers[entryPointName] = handlerToUse
|
||||
}
|
||||
}
|
||||
if backends[entryPointName+providerName+frontend.Backend] == nil {
|
||||
|
||||
frontendHash, err := frontend.Hash()
|
||||
if err != nil {
|
||||
log.Errorf("Error calculating hash value for frontend %s: %v", frontendName, err)
|
||||
log.Errorf("Skipping frontend %s...", frontendName)
|
||||
continue frontend
|
||||
}
|
||||
backendCacheKey := entryPointName + providerName + frontendHash
|
||||
if backends[backendCacheKey] == nil {
|
||||
log.Debugf("Creating backend %s", frontend.Backend)
|
||||
|
||||
roundTripper, err := s.getRoundTripper(entryPointName, globalConfiguration, frontend.PassTLSCert, entryPoint.TLS)
|
||||
|
@ -1045,7 +1053,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
if hcOpts != nil {
|
||||
log.Debugf("Setting up backend health check %s", *hcOpts)
|
||||
hcOpts.Transport = s.defaultForwardingRoundTripper
|
||||
backendsHealthCheck[entryPointName+frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts, frontend.Backend)
|
||||
backendsHealthCheck[backendCacheKey] = healthcheck.NewBackendHealthCheck(*hcOpts, frontend.Backend)
|
||||
}
|
||||
lb = middlewares.NewEmptyBackendHandler(rebalancer, lb)
|
||||
case types.Wrr:
|
||||
|
@ -1067,7 +1075,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
if hcOpts != nil {
|
||||
log.Debugf("Setting up backend health check %s", *hcOpts)
|
||||
hcOpts.Transport = s.defaultForwardingRoundTripper
|
||||
backendsHealthCheck[entryPointName+frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts, frontend.Backend)
|
||||
backendsHealthCheck[backendCacheKey] = healthcheck.NewBackendHealthCheck(*hcOpts, frontend.Backend)
|
||||
}
|
||||
lb = middlewares.NewEmptyBackendHandler(rr, lb)
|
||||
}
|
||||
|
@ -1208,16 +1216,16 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
} else {
|
||||
n.UseHandler(lb)
|
||||
}
|
||||
backends[entryPointName+providerName+frontend.Backend] = n
|
||||
backends[backendCacheKey] = n
|
||||
} else {
|
||||
log.Debugf("Reusing backend %s", frontend.Backend)
|
||||
}
|
||||
if frontend.Priority > 0 {
|
||||
newServerRoute.Route.Priority(frontend.Priority)
|
||||
}
|
||||
s.wireFrontendBackend(newServerRoute, backends[entryPointName+providerName+frontend.Backend])
|
||||
s.wireFrontendBackend(newServerRoute, backends[backendCacheKey])
|
||||
|
||||
err := newServerRoute.Route.GetError()
|
||||
err = newServerRoute.Route.GetError()
|
||||
if err != nil {
|
||||
log.Errorf("Error building route: %s", err)
|
||||
}
|
||||
|
|
|
@ -962,6 +962,65 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReuseBackend(t *testing.T) {
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer testServer.Close()
|
||||
|
||||
globalConfig := configuration.GlobalConfiguration{
|
||||
DefaultEntryPoints: []string{"http"},
|
||||
}
|
||||
|
||||
entryPoints := map[string]EntryPoint{
|
||||
"http": {Configuration: &configuration.EntryPoint{
|
||||
ForwardedHeaders: &configuration.ForwardedHeaders{Insecure: true},
|
||||
}},
|
||||
}
|
||||
|
||||
dynamicConfigs := types.Configurations{
|
||||
"config": th.BuildConfiguration(
|
||||
th.WithFrontends(
|
||||
th.WithFrontend("backend",
|
||||
th.WithFrontendName("frontend0"),
|
||||
th.WithEntryPoints("http"),
|
||||
th.WithRoutes(th.WithRoute("/ok", "Path: /ok"))),
|
||||
th.WithFrontend("backend",
|
||||
th.WithFrontendName("frontend1"),
|
||||
th.WithEntryPoints("http"),
|
||||
th.WithRoutes(th.WithRoute("/unauthorized", "Path: /unauthorized")),
|
||||
th.WithBasicAuth("foo", "bar")),
|
||||
),
|
||||
th.WithBackends(th.WithBackendNew("backend",
|
||||
th.WithLBMethod("wrr"),
|
||||
th.WithServersNew(th.WithServerNew(testServer.URL))),
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
srv := NewServer(globalConfig, nil, entryPoints)
|
||||
|
||||
serverEntryPoints, err := srv.loadConfig(dynamicConfigs, globalConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("error loading config: %s", err)
|
||||
}
|
||||
|
||||
// Test that the /ok path returns a status 200.
|
||||
responseRecorderOk := &httptest.ResponseRecorder{}
|
||||
requestOk := httptest.NewRequest(http.MethodGet, testServer.URL+"/ok", nil)
|
||||
serverEntryPoints["http"].httpRouter.ServeHTTP(responseRecorderOk, requestOk)
|
||||
|
||||
assert.Equal(t, http.StatusOK, responseRecorderOk.Result().StatusCode, "status code")
|
||||
|
||||
// Test that the /unauthorized path returns a 401 because of
|
||||
// the basic authentication defined on the frontend.
|
||||
responseRecorderUnauthorized := &httptest.ResponseRecorder{}
|
||||
requestUnauthorized := httptest.NewRequest(http.MethodGet, testServer.URL+"/unauthorized", nil)
|
||||
serverEntryPoints["http"].httpRouter.ServeHTTP(responseRecorderUnauthorized, requestUnauthorized)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, responseRecorderUnauthorized.Result().StatusCode, "status code")
|
||||
}
|
||||
|
||||
func TestBuildRedirectHandler(t *testing.T) {
|
||||
srv := Server{
|
||||
globalConfiguration: configuration.GlobalConfiguration{},
|
||||
|
|
|
@ -137,6 +137,13 @@ func WithRoute(name string, rule string) func(*types.Route) string {
|
|||
}
|
||||
}
|
||||
|
||||
// WithBasicAuth is a helper to create a configuration
|
||||
func WithBasicAuth(username string, password string) func(*types.Frontend) {
|
||||
return func(fe *types.Frontend) {
|
||||
fe.BasicAuth = []string{username + ":" + password}
|
||||
}
|
||||
}
|
||||
|
||||
// WithLBSticky is a helper to create a configuration
|
||||
func WithLBSticky(cookieName string) func(*types.Backend) {
|
||||
return func(b *types.Backend) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/containous/mux"
|
||||
"github.com/containous/traefik/log"
|
||||
traefiktls "github.com/containous/traefik/tls"
|
||||
"github.com/mitchellh/hashstructure"
|
||||
"github.com/ryanuber/go-glob"
|
||||
)
|
||||
|
||||
|
@ -177,9 +178,9 @@ func (h *Headers) HasSecureHeadersDefined() bool {
|
|||
|
||||
// Frontend holds frontend configuration.
|
||||
type Frontend struct {
|
||||
EntryPoints []string `json:"entryPoints,omitempty"`
|
||||
EntryPoints []string `json:"entryPoints,omitempty" hash:"ignore"`
|
||||
Backend string `json:"backend,omitempty"`
|
||||
Routes map[string]Route `json:"routes,omitempty"`
|
||||
Routes map[string]Route `json:"routes,omitempty" hash:"ignore"`
|
||||
PassHostHeader bool `json:"passHostHeader,omitempty"`
|
||||
PassTLSCert bool `json:"passTLSCert,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
|
@ -192,6 +193,17 @@ type Frontend struct {
|
|||
Redirect *Redirect `json:"redirect,omitempty"`
|
||||
}
|
||||
|
||||
// Hash returns the hash value of a Frontend struct.
|
||||
func (f *Frontend) Hash() (string, error) {
|
||||
hash, err := hashstructure.Hash(f, nil)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strconv.FormatUint(hash, 10), nil
|
||||
}
|
||||
|
||||
// Redirect configures a redirection of an entry point to another, or to an URL
|
||||
type Redirect struct {
|
||||
EntryPoint string `json:"entryPoint,omitempty"`
|
||||
|
|
Loading…
Reference in a new issue