Maintain sticky flag on LB method validation failure.
We previously did not copy the sticky flag if the load-balancer method validation failed, causing enabled stickiness to be dropped in case of a validation error (which, technically, for us is the same as a load-balancer configuration without an explicitly set method). This change fixes that. A few refactorings and improvements along the way: - Move the frontend and backend configuration steps into separate methods/functions for better testability. - Include the invalid method name in the error value and avoid log duplication. - Add tests for the backend configuration part.
This commit is contained in:
parent
30aa5a82b3
commit
2c45428c8a
3 changed files with 110 additions and 18 deletions
|
@ -254,19 +254,8 @@ func (server *Server) defaultConfigurationValues(configuration *types.Configurat
|
||||||
if configuration == nil || configuration.Frontends == nil {
|
if configuration == nil || configuration.Frontends == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, frontend := range configuration.Frontends {
|
server.configureFrontends(configuration.Frontends)
|
||||||
// default endpoints if not defined in frontends
|
configureBackends(configuration.Backends)
|
||||||
if len(frontend.EntryPoints) == 0 {
|
|
||||||
frontend.EntryPoints = server.globalConfiguration.DefaultEntryPoints
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for backendName, backend := range configuration.Backends {
|
|
||||||
_, err := types.NewLoadBalancerMethod(backend.LoadBalancer)
|
|
||||||
if err != nil {
|
|
||||||
log.Debugf("Load balancer method '%+v' for backend %s: %v. Using default wrr.", backend.LoadBalancer, backendName, err)
|
|
||||||
backend.LoadBalancer = &types.LoadBalancer{Method: "wrr"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) listenConfigurations(stop chan bool) {
|
func (server *Server) listenConfigurations(stop chan bool) {
|
||||||
|
@ -890,3 +879,29 @@ func sortedFrontendNamesForConfig(configuration *types.Configuration) []string {
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (server *Server) configureFrontends(frontends map[string]*types.Frontend) {
|
||||||
|
for _, frontend := range frontends {
|
||||||
|
// default endpoints if not defined in frontends
|
||||||
|
if len(frontend.EntryPoints) == 0 {
|
||||||
|
frontend.EntryPoints = server.globalConfiguration.DefaultEntryPoints
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureBackends(backends map[string]*types.Backend) {
|
||||||
|
for backendName, backend := range backends {
|
||||||
|
_, err := types.NewLoadBalancerMethod(backend.LoadBalancer)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Validation of load balancer method for backend %s failed: %s. Using default method wrr.", backendName, err)
|
||||||
|
var sticky bool
|
||||||
|
if backend.LoadBalancer != nil {
|
||||||
|
sticky = backend.LoadBalancer.Sticky
|
||||||
|
}
|
||||||
|
backend.LoadBalancer = &types.LoadBalancer{
|
||||||
|
Method: "wrr",
|
||||||
|
Sticky: sticky,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/containous/traefik/healthcheck"
|
"github.com/containous/traefik/healthcheck"
|
||||||
"github.com/containous/traefik/testhelpers"
|
"github.com/containous/traefik/testhelpers"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/vulcand/oxy/roundrobin"
|
"github.com/vulcand/oxy/roundrobin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -277,3 +278,80 @@ func TestServerLoadConfigEmptyBasicAuth(t *testing.T) {
|
||||||
t.Fatalf("got error: %s", err)
|
t.Fatalf("got error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigureBackends(t *testing.T) {
|
||||||
|
validMethod := "Drr"
|
||||||
|
defaultMethod := "wrr"
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
lb *types.LoadBalancer
|
||||||
|
wantMethod string
|
||||||
|
wantSticky bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "valid load balancer method with sticky enabled",
|
||||||
|
lb: &types.LoadBalancer{
|
||||||
|
Method: validMethod,
|
||||||
|
Sticky: true,
|
||||||
|
},
|
||||||
|
wantMethod: validMethod,
|
||||||
|
wantSticky: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "valid load balancer method with sticky disabled",
|
||||||
|
lb: &types.LoadBalancer{
|
||||||
|
Method: validMethod,
|
||||||
|
Sticky: false,
|
||||||
|
},
|
||||||
|
wantMethod: validMethod,
|
||||||
|
wantSticky: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid load balancer method with sticky enabled",
|
||||||
|
lb: &types.LoadBalancer{
|
||||||
|
Method: "Invalid",
|
||||||
|
Sticky: true,
|
||||||
|
},
|
||||||
|
wantMethod: defaultMethod,
|
||||||
|
wantSticky: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid load balancer method with sticky disabled",
|
||||||
|
lb: &types.LoadBalancer{
|
||||||
|
Method: "Invalid",
|
||||||
|
Sticky: false,
|
||||||
|
},
|
||||||
|
wantMethod: defaultMethod,
|
||||||
|
wantSticky: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "missing load balancer",
|
||||||
|
lb: nil,
|
||||||
|
wantMethod: defaultMethod,
|
||||||
|
wantSticky: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
backend := &types.Backend{
|
||||||
|
LoadBalancer: test.lb,
|
||||||
|
}
|
||||||
|
|
||||||
|
configureBackends(map[string]*types.Backend{
|
||||||
|
"backend": backend,
|
||||||
|
})
|
||||||
|
|
||||||
|
wantLB := types.LoadBalancer{
|
||||||
|
Method: test.wantMethod,
|
||||||
|
Sticky: test.wantSticky,
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(*backend.LoadBalancer, wantLB) {
|
||||||
|
t.Errorf("got backend load-balancer\n%v\nwant\n%v\n", spew.Sdump(backend.LoadBalancer), spew.Sdump(wantLB))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -81,19 +81,18 @@ var loadBalancerMethodNames = []string{
|
||||||
|
|
||||||
// NewLoadBalancerMethod create a new LoadBalancerMethod from a given LoadBalancer.
|
// NewLoadBalancerMethod create a new LoadBalancerMethod from a given LoadBalancer.
|
||||||
func NewLoadBalancerMethod(loadBalancer *LoadBalancer) (LoadBalancerMethod, error) {
|
func NewLoadBalancerMethod(loadBalancer *LoadBalancer) (LoadBalancerMethod, error) {
|
||||||
|
var method string
|
||||||
if loadBalancer != nil {
|
if loadBalancer != nil {
|
||||||
|
method = loadBalancer.Method
|
||||||
for i, name := range loadBalancerMethodNames {
|
for i, name := range loadBalancerMethodNames {
|
||||||
if strings.EqualFold(name, loadBalancer.Method) {
|
if strings.EqualFold(name, method) {
|
||||||
return LoadBalancerMethod(i), nil
|
return LoadBalancerMethod(i), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Wrr, ErrInvalidLoadBalancerMethod
|
return Wrr, fmt.Errorf("invalid load-balancing method '%s'", method)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrInvalidLoadBalancerMethod is thrown when the specified load balancing method is invalid.
|
|
||||||
var ErrInvalidLoadBalancerMethod = errors.New("Invalid method, using default")
|
|
||||||
|
|
||||||
// Configuration of a provider.
|
// Configuration of a provider.
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Backends map[string]*Backend `json:"backends,omitempty"`
|
Backends map[string]*Backend `json:"backends,omitempty"`
|
||||||
|
|
Loading…
Reference in a new issue