Stickiness cookie name.
This commit is contained in:
parent
cba0898e4f
commit
8cb3f0835a
21 changed files with 525 additions and 148 deletions
|
@ -398,7 +398,7 @@ func (p *CatalogProvider) hasStickinessLabel(tags []string) bool {
|
||||||
|
|
||||||
stickyTag := p.getTag(types.LabelBackendLoadbalancerSticky, tags, "")
|
stickyTag := p.getTag(types.LabelBackendLoadbalancerSticky, tags, "")
|
||||||
if len(stickyTag) > 0 {
|
if len(stickyTag) > 0 {
|
||||||
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
|
|
||||||
stickiness := len(stickinessTag) > 0 && strings.EqualFold(strings.TrimSpace(stickinessTag), "true")
|
stickiness := len(stickinessTag) > 0 && strings.EqualFold(strings.TrimSpace(stickinessTag), "true")
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/BurntSushi/ty/fun"
|
"github.com/BurntSushi/ty/fun"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConsulCatalogGetFrontendRule(t *testing.T) {
|
func TestConsulCatalogGetFrontendRule(t *testing.T) {
|
||||||
|
@ -891,3 +892,69 @@ func TestConsulCatalogGetBasicAuth(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConsulCatalogHasStickinessLabel(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
tags []string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "label missing",
|
||||||
|
tags: []string{},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=true",
|
||||||
|
tags: []string{
|
||||||
|
"traefik.backend.loadbalancer.sticky=true",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness=true",
|
||||||
|
tags: []string{
|
||||||
|
"traefik.backend.loadbalancer.stickiness=true",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=true and stickiness=true",
|
||||||
|
tags: []string{
|
||||||
|
"traefik.backend.loadbalancer.sticky=true",
|
||||||
|
"traefik.backend.loadbalancer.stickiness=true",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=false and stickiness=true",
|
||||||
|
tags: []string{
|
||||||
|
"traefik.backend.loadbalancer.sticky=true",
|
||||||
|
"traefik.backend.loadbalancer.stickiness=false",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=true and stickiness=false",
|
||||||
|
tags: []string{
|
||||||
|
"traefik.backend.loadbalancer.sticky=true",
|
||||||
|
"traefik.backend.loadbalancer.stickiness=false",
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := &CatalogProvider{
|
||||||
|
Prefix: "traefik",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
actual := provider.hasStickinessLabel(test.tags)
|
||||||
|
assert.Equal(t, actual, test.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -645,14 +645,16 @@ func (p *Provider) getWeight(container dockerData) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasStickinessLabel(container dockerData) bool {
|
func (p *Provider) hasStickinessLabel(container dockerData) bool {
|
||||||
_, errStickiness := getLabel(container, types.LabelBackendLoadbalancerStickiness)
|
labelStickiness, errStickiness := getLabel(container, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
|
||||||
label, errSticky := getLabel(container, types.LabelBackendLoadbalancerSticky)
|
labelSticky, errSticky := getLabel(container, types.LabelBackendLoadbalancerSticky)
|
||||||
if len(label) > 0 {
|
if len(labelSticky) > 0 {
|
||||||
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errStickiness == nil || (errSticky == nil && strings.EqualFold(strings.TrimSpace(label), "true"))
|
stickiness := errStickiness == nil && len(labelStickiness) > 0 && strings.EqualFold(strings.TrimSpace(labelStickiness), "true")
|
||||||
|
sticky := errSticky == nil && len(labelSticky) > 0 && strings.EqualFold(strings.TrimSpace(labelSticky), "true")
|
||||||
|
return stickiness || sticky
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getStickinessCookieName(container dockerData) string {
|
func (p *Provider) getStickinessCookieName(container dockerData) string {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
docker "github.com/docker/docker/api/types"
|
docker "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDockerGetFrontendName(t *testing.T) {
|
func TestDockerGetFrontendName(t *testing.T) {
|
||||||
|
@ -1051,3 +1052,80 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDockerHasStickinessLabel(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
container docker.ContainerJSON
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "no sticky/stickiness-label",
|
||||||
|
container: containerJSON(),
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky true",
|
||||||
|
container: containerJSON(labels(map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "true",
|
||||||
|
})),
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky false",
|
||||||
|
container: containerJSON(labels(map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "false",
|
||||||
|
})),
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness true",
|
||||||
|
container: containerJSON(labels(map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "true",
|
||||||
|
})),
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness false",
|
||||||
|
container: containerJSON(labels(map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "false",
|
||||||
|
})),
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky true + stickiness false",
|
||||||
|
container: containerJSON(labels(map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "true",
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "false",
|
||||||
|
})),
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky false + stickiness true",
|
||||||
|
container: containerJSON(labels(map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "false",
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "true",
|
||||||
|
})),
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky false + stickiness false",
|
||||||
|
container: containerJSON(labels(map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "false",
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "false",
|
||||||
|
})),
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
dockerData := parseContainer(test.container)
|
||||||
|
provider := &Provider{}
|
||||||
|
actual := provider.hasStickinessLabel(dockerData)
|
||||||
|
assert.Equal(t, actual, test.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -490,7 +490,7 @@ func (p *Provider) hasStickinessLabel(instances []ecsInstance) bool {
|
||||||
|
|
||||||
stickyLabel := getFirstInstanceLabel(instances, types.LabelBackendLoadbalancerSticky)
|
stickyLabel := getFirstInstanceLabel(instances, types.LabelBackendLoadbalancerSticky)
|
||||||
if len(stickyLabel) > 0 {
|
if len(stickyLabel) > 0 {
|
||||||
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
stickiness := len(stickinessLabel) > 0 && strings.EqualFold(strings.TrimSpace(stickinessLabel), "true")
|
stickiness := len(stickinessLabel) > 0 && strings.EqualFold(strings.TrimSpace(stickinessLabel), "true")
|
||||||
sticky := len(stickyLabel) > 0 && strings.EqualFold(strings.TrimSpace(stickyLabel), "true")
|
sticky := len(stickyLabel) > 0 && strings.EqualFold(strings.TrimSpace(stickyLabel), "true")
|
||||||
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/server/cookie"
|
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||||
|
@ -185,8 +184,8 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
witelistSourceRangeAnnotation := i.Annotations[annotationKubernetesWhitelistSourceRange]
|
whitelistSourceRangeAnnotation := i.Annotations[annotationKubernetesWhitelistSourceRange]
|
||||||
whitelistSourceRange := provider.SplitAndTrimString(witelistSourceRangeAnnotation)
|
whitelistSourceRange := provider.SplitAndTrimString(whitelistSourceRangeAnnotation)
|
||||||
|
|
||||||
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
||||||
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
||||||
|
@ -250,12 +249,12 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(service.Annotations[types.LabelBackendLoadbalancerSticky]) > 0 {
|
if len(service.Annotations[types.LabelBackendLoadbalancerSticky]) > 0 {
|
||||||
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
|
|
||||||
if service.Annotations[types.LabelBackendLoadbalancerSticky] == "true" || service.Annotations[types.LabelBackendLoadbalancerStickiness] == "true" {
|
if service.Annotations[types.LabelBackendLoadbalancerSticky] == "true" || service.Annotations[types.LabelBackendLoadbalancerStickiness] == "true" {
|
||||||
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Stickiness = &types.Stickiness{
|
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Stickiness = &types.Stickiness{
|
||||||
CookieName: cookie.GenerateName(r.Host + pa.Path),
|
CookieName: r.Host + pa.Path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1326,7 +1326,7 @@ func TestServiceAnnotations(t *testing.T) {
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
Stickiness: &types.Stickiness{
|
Stickiness: &types.Stickiness{
|
||||||
CookieName: "_4155f",
|
CookieName: "bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -243,13 +243,17 @@ func (p *Provider) checkConstraints(keys ...string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasStickinessLabel(rootPath string) bool {
|
func (p *Provider) hasStickinessLabel(rootPath string) bool {
|
||||||
stickiness, err := p.kvclient.Exists(rootPath + "/loadbalancer/stickiness")
|
stickyValue := p.get("false", rootPath, "/loadbalancer", "/sticky")
|
||||||
if err != nil {
|
|
||||||
log.Debugf("Error occurs when check stickiness: %v", err)
|
|
||||||
}
|
|
||||||
sticky := p.get("false", rootPath, "/loadbalancer", "/sticky")
|
|
||||||
|
|
||||||
return stickiness || (len(sticky) != 0 && strings.EqualFold(strings.TrimSpace(sticky), "true"))
|
sticky := len(stickyValue) != 0 && strings.EqualFold(strings.TrimSpace(stickyValue), "true")
|
||||||
|
if sticky {
|
||||||
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", "loadbalancer/sticky", "loadbalancer/stickiness")
|
||||||
|
}
|
||||||
|
|
||||||
|
stickinessValue := p.get("false", rootPath, "/loadbalancer", "/stickiness")
|
||||||
|
stickiness := len(stickinessValue) > 0 && strings.EqualFold(strings.TrimSpace(stickinessValue), "true")
|
||||||
|
|
||||||
|
return stickiness || sticky
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getStickinessCookieName(rootPath string) string {
|
func (p *Provider) getStickinessCookieName(rootPath string) string {
|
||||||
|
|
110
provider/kv/kv_mock_test.go
Normal file
110
provider/kv/kv_mock_test.go
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package kv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/types"
|
||||||
|
"github.com/docker/libkv/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KvMock struct {
|
||||||
|
Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *KvMock) loadConfig() *types.Configuration {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override Get/List to return a error
|
||||||
|
type KvError struct {
|
||||||
|
Get error
|
||||||
|
List error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extremely limited mock store so we can test initialization
|
||||||
|
type Mock struct {
|
||||||
|
Error KvError
|
||||||
|
KVPairs []*store.KVPair
|
||||||
|
WatchTreeMethod func() <-chan []*store.KVPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mock) Put(key string, value []byte, opts *store.WriteOptions) error {
|
||||||
|
return errors.New("Put not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mock) Get(key string) (*store.KVPair, error) {
|
||||||
|
if err := s.Error.Get; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, kvPair := range s.KVPairs {
|
||||||
|
if kvPair.Key == key {
|
||||||
|
return kvPair, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, store.ErrKeyNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mock) Delete(key string) error {
|
||||||
|
return errors.New("Delete not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists mock
|
||||||
|
func (s *Mock) Exists(key string) (bool, error) {
|
||||||
|
if err := s.Error.Get; err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for _, kvPair := range s.KVPairs {
|
||||||
|
if strings.HasPrefix(kvPair.Key, key) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, store.ErrKeyNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch mock
|
||||||
|
func (s *Mock) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) {
|
||||||
|
return nil, errors.New("Watch not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchTree mock
|
||||||
|
func (s *Mock) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) {
|
||||||
|
return s.WatchTreeMethod(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLock mock
|
||||||
|
func (s *Mock) NewLock(key string, options *store.LockOptions) (store.Locker, error) {
|
||||||
|
return nil, errors.New("NewLock not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// List mock
|
||||||
|
func (s *Mock) List(prefix string) ([]*store.KVPair, error) {
|
||||||
|
if err := s.Error.List; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kv := []*store.KVPair{}
|
||||||
|
for _, kvPair := range s.KVPairs {
|
||||||
|
if strings.HasPrefix(kvPair.Key, prefix) && !strings.ContainsAny(strings.TrimPrefix(kvPair.Key, prefix), "/") {
|
||||||
|
kv = append(kv, kvPair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTree mock
|
||||||
|
func (s *Mock) DeleteTree(prefix string) error {
|
||||||
|
return errors.New("DeleteTree not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtomicPut mock
|
||||||
|
func (s *Mock) AtomicPut(key string, value []byte, previous *store.KVPair, opts *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
|
return false, nil, errors.New("AtomicPut not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtomicDelete mock
|
||||||
|
func (s *Mock) AtomicDelete(key string, previous *store.KVPair) (bool, error) {
|
||||||
|
return false, errors.New("AtomicDelete not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close mock
|
||||||
|
func (s *Mock) Close() {}
|
|
@ -1,10 +1,8 @@
|
||||||
package kv
|
package kv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -237,14 +235,6 @@ func TestKvLast(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type KvMock struct {
|
|
||||||
Provider
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *KvMock) loadConfig() *types.Configuration {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKvWatchTree(t *testing.T) {
|
func TestKvWatchTree(t *testing.T) {
|
||||||
returnedChans := make(chan chan []*store.KVPair)
|
returnedChans := make(chan chan []*store.KVPair)
|
||||||
provider := &KvMock{
|
provider := &KvMock{
|
||||||
|
@ -288,91 +278,6 @@ func TestKvWatchTree(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override Get/List to return a error
|
|
||||||
type KvError struct {
|
|
||||||
Get error
|
|
||||||
List error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extremely limited mock store so we can test initialization
|
|
||||||
type Mock struct {
|
|
||||||
Error KvError
|
|
||||||
KVPairs []*store.KVPair
|
|
||||||
WatchTreeMethod func() <-chan []*store.KVPair
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Mock) Put(key string, value []byte, opts *store.WriteOptions) error {
|
|
||||||
return errors.New("Put not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Mock) Get(key string) (*store.KVPair, error) {
|
|
||||||
if err := s.Error.Get; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, kvPair := range s.KVPairs {
|
|
||||||
if kvPair.Key == key {
|
|
||||||
return kvPair, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, store.ErrKeyNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Mock) Delete(key string) error {
|
|
||||||
return errors.New("Delete not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exists mock
|
|
||||||
func (s *Mock) Exists(key string) (bool, error) {
|
|
||||||
return false, errors.New("Exists not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch mock
|
|
||||||
func (s *Mock) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) {
|
|
||||||
return nil, errors.New("Watch not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchTree mock
|
|
||||||
func (s *Mock) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) {
|
|
||||||
return s.WatchTreeMethod(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLock mock
|
|
||||||
func (s *Mock) NewLock(key string, options *store.LockOptions) (store.Locker, error) {
|
|
||||||
return nil, errors.New("NewLock not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// List mock
|
|
||||||
func (s *Mock) List(prefix string) ([]*store.KVPair, error) {
|
|
||||||
if err := s.Error.List; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
kv := []*store.KVPair{}
|
|
||||||
for _, kvPair := range s.KVPairs {
|
|
||||||
if strings.HasPrefix(kvPair.Key, prefix) && !strings.ContainsAny(strings.TrimPrefix(kvPair.Key, prefix), "/") {
|
|
||||||
kv = append(kv, kvPair)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kv, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteTree mock
|
|
||||||
func (s *Mock) DeleteTree(prefix string) error {
|
|
||||||
return errors.New("DeleteTree not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtomicPut mock
|
|
||||||
func (s *Mock) AtomicPut(key string, value []byte, previous *store.KVPair, opts *store.WriteOptions) (bool, *store.KVPair, error) {
|
|
||||||
return false, nil, errors.New("AtomicPut not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtomicDelete mock
|
|
||||||
func (s *Mock) AtomicDelete(key string, previous *store.KVPair) (bool, error) {
|
|
||||||
return false, errors.New("AtomicDelete not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close mock
|
|
||||||
func (s *Mock) Close() {}
|
|
||||||
|
|
||||||
func TestKVLoadConfig(t *testing.T) {
|
func TestKVLoadConfig(t *testing.T) {
|
||||||
provider := &Provider{
|
provider := &Provider{
|
||||||
Prefix: "traefik",
|
Prefix: "traefik",
|
||||||
|
@ -463,3 +368,97 @@ func TestKVLoadConfig(t *testing.T) {
|
||||||
t.Fatalf("expected %+v, got %+v", expected.Frontends, actual.Frontends)
|
t.Fatalf("expected %+v, got %+v", expected.Frontends, actual.Frontends)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKVHasStickinessLabel(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
KVPairs []*store.KVPair
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "without option",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "with cookie name without stickiness=true",
|
||||||
|
KVPairs: []*store.KVPair{
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/stickiness/cookiename",
|
||||||
|
Value: []byte("foo"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness=true",
|
||||||
|
KVPairs: []*store.KVPair{
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/stickiness",
|
||||||
|
Value: []byte("true"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness=true and sticky=true",
|
||||||
|
KVPairs: []*store.KVPair{
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/stickiness",
|
||||||
|
Value: []byte("true"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/sticky",
|
||||||
|
Value: []byte("true"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness=false and sticky=true",
|
||||||
|
KVPairs: []*store.KVPair{
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/stickiness",
|
||||||
|
Value: []byte("false"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/sticky",
|
||||||
|
Value: []byte("true"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness=true and sticky=false",
|
||||||
|
KVPairs: []*store.KVPair{
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/stickiness",
|
||||||
|
Value: []byte("true"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "loadbalancer/sticky",
|
||||||
|
Value: []byte("false"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
p := &Provider{
|
||||||
|
kvclient: &Mock{
|
||||||
|
KVPairs: test.KVPairs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := p.hasStickinessLabel("")
|
||||||
|
|
||||||
|
if actual != test.expected {
|
||||||
|
t.Fatalf("expected %v, got %v", test.expected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -430,14 +430,16 @@ func (p *Provider) getProtocol(application marathon.Application, serviceName str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasStickinessLabel(application marathon.Application) bool {
|
func (p *Provider) hasStickinessLabel(application marathon.Application) bool {
|
||||||
_, okStickiness := p.getAppLabel(application, types.LabelBackendLoadbalancerStickiness)
|
labelStickiness, okStickiness := p.getAppLabel(application, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
|
||||||
label, okSticky := p.getAppLabel(application, types.LabelBackendLoadbalancerSticky)
|
labelSticky, okSticky := p.getAppLabel(application, types.LabelBackendLoadbalancerSticky)
|
||||||
if len(label) > 0 {
|
if len(labelSticky) > 0 {
|
||||||
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
|
|
||||||
return okStickiness || (okSticky && strings.EqualFold(strings.TrimSpace(label), "true"))
|
stickiness := okStickiness && len(labelStickiness) > 0 && strings.EqualFold(strings.TrimSpace(labelStickiness), "true")
|
||||||
|
sticky := okSticky && len(labelSticky) > 0 && strings.EqualFold(strings.TrimSpace(labelSticky), "true")
|
||||||
|
return stickiness || sticky
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getStickinessCookieName(application marathon.Application) string {
|
func (p *Provider) getStickinessCookieName(application marathon.Application) string {
|
||||||
|
|
|
@ -856,7 +856,7 @@ func TestMarathonGetProtocol(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarathonHasStickinessLabel(t *testing.T) {
|
func TestMarathonHasStickinessLabel(t *testing.T) {
|
||||||
cases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
application marathon.Application
|
application marathon.Application
|
||||||
expected bool
|
expected bool
|
||||||
|
@ -867,35 +867,50 @@ func TestMarathonHasStickinessLabel(t *testing.T) {
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "label existing and value equals true (deprecated)",
|
desc: "sticky=true (deprecated)",
|
||||||
application: application(label(types.LabelBackendLoadbalancerSticky, "true")),
|
application: application(label(types.LabelBackendLoadbalancerSticky, "true")),
|
||||||
expected: true,
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "label existing and value equals false (deprecated)",
|
desc: "sticky=false (deprecated)",
|
||||||
application: application(label(types.LabelBackendLoadbalancerSticky, "false")),
|
application: application(label(types.LabelBackendLoadbalancerSticky, "false")),
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "label existing and value equals true",
|
desc: "stickiness=true",
|
||||||
application: application(label(types.LabelBackendLoadbalancerStickiness, "true")),
|
application: application(label(types.LabelBackendLoadbalancerStickiness, "true")),
|
||||||
expected: true,
|
expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "label existing and value equals false ",
|
desc: "stickiness=false ",
|
||||||
application: application(label(types.LabelBackendLoadbalancerStickiness, "true")),
|
application: application(label(types.LabelBackendLoadbalancerStickiness, "true")),
|
||||||
expected: true,
|
expected: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=false stickiness=true ",
|
||||||
|
application: application(
|
||||||
|
label(types.LabelBackendLoadbalancerStickiness, "true"),
|
||||||
|
label(types.LabelBackendLoadbalancerSticky, "false")),
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=true stickiness=false ",
|
||||||
|
application: application(
|
||||||
|
label(types.LabelBackendLoadbalancerStickiness, "false"),
|
||||||
|
label(types.LabelBackendLoadbalancerSticky, "true")),
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, test := range testCases {
|
||||||
c := c
|
test := test
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
provider := &Provider{}
|
provider := &Provider{}
|
||||||
actual := provider.hasStickinessLabel(c.application)
|
actual := provider.hasStickinessLabel(test.application)
|
||||||
if actual != c.expected {
|
if actual != test.expected {
|
||||||
t.Errorf("actual %q, expected %q", actual, c.expected)
|
t.Errorf("actual %q, expected %q", actual, test.expected)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,14 +113,16 @@ func (p *Provider) getCircuitBreakerExpression(service rancherData) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasStickinessLabel(service rancherData) bool {
|
func (p *Provider) hasStickinessLabel(service rancherData) bool {
|
||||||
_, errStickiness := getServiceLabel(service, types.LabelBackendLoadbalancerStickiness)
|
labelStickiness, errStickiness := getServiceLabel(service, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
|
||||||
label, errSticky := getServiceLabel(service, types.LabelBackendLoadbalancerSticky)
|
labelSticky, errSticky := getServiceLabel(service, types.LabelBackendLoadbalancerSticky)
|
||||||
if len(label) > 0 {
|
if len(labelSticky) > 0 {
|
||||||
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errStickiness == nil || (errSticky == nil && strings.EqualFold(strings.TrimSpace(label), "true"))
|
stickiness := errStickiness == nil && len(labelStickiness) > 0 && strings.EqualFold(strings.TrimSpace(labelStickiness), "true")
|
||||||
|
sticky := errSticky == nil && len(labelSticky) > 0 && strings.EqualFold(strings.TrimSpace(labelSticky), "true")
|
||||||
|
return stickiness || sticky
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getStickinessCookieName(service rancherData, backendName string) string {
|
func (p *Provider) getStickinessCookieName(service rancherData, backendName string) string {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRancherServiceFilter(t *testing.T) {
|
func TestRancherServiceFilter(t *testing.T) {
|
||||||
|
@ -597,3 +598,97 @@ func TestRancherLoadRancherConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRancherHasStickinessLabel(t *testing.T) {
|
||||||
|
provider := &Provider{
|
||||||
|
Domain: "rancher.localhost",
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
service rancherData
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "no labels",
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=true",
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
Labels: map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "stickiness=true",
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
Labels: map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=true and stickiness=true",
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
Labels: map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "true",
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=false and stickiness=false",
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
Labels: map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "false",
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "false",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=true and stickiness=false",
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
Labels: map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "true",
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "false",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sticky=false and stickiness=true",
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
Labels: map[string]string{
|
||||||
|
types.LabelBackendLoadbalancerSticky: "false",
|
||||||
|
types.LabelBackendLoadbalancerStickiness: "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
actual := provider.hasStickinessLabel(test.service)
|
||||||
|
assert.Equal(t, actual, test.expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1166,26 +1166,30 @@ func (server *Server) configureFrontends(frontends map[string]*types.Frontend) {
|
||||||
func (*Server) configureBackends(backends map[string]*types.Backend) {
|
func (*Server) configureBackends(backends map[string]*types.Backend) {
|
||||||
for backendName, backend := range backends {
|
for backendName, backend := range backends {
|
||||||
if backend.LoadBalancer != nil && backend.LoadBalancer.Sticky {
|
if backend.LoadBalancer != nil && backend.LoadBalancer.Sticky {
|
||||||
log.Warn("Deprecated configuration found: %s. Please use %s.", "backend.LoadBalancer.Sticky", "backend.LoadBalancer.Stickiness")
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", "backend.LoadBalancer.Sticky", "backend.LoadBalancer.Stickiness")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := types.NewLoadBalancerMethod(backend.LoadBalancer)
|
_, err := types.NewLoadBalancerMethod(backend.LoadBalancer)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if backend.LoadBalancer != nil && backend.LoadBalancer.Stickiness == nil && backend.LoadBalancer.Sticky {
|
if backend.LoadBalancer != nil && backend.LoadBalancer.Stickiness == nil && backend.LoadBalancer.Sticky {
|
||||||
backend.LoadBalancer.Stickiness = &types.Stickiness{}
|
backend.LoadBalancer.Stickiness = &types.Stickiness{
|
||||||
|
CookieName: "_TRAEFIK_BACKEND",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Validation of load balancer method for backend %s failed: %s. Using default method wrr.", backendName, err)
|
log.Debugf("Validation of load balancer method for backend %s failed: %s. Using default method wrr.", backendName, err)
|
||||||
|
|
||||||
var stickiness *types.Stickiness
|
var stickiness *types.Stickiness
|
||||||
if backend.LoadBalancer != nil {
|
if backend.LoadBalancer != nil {
|
||||||
if backend.LoadBalancer.Stickiness != nil {
|
|
||||||
stickiness = backend.LoadBalancer.Stickiness
|
|
||||||
} else if backend.LoadBalancer.Sticky {
|
|
||||||
if backend.LoadBalancer.Stickiness == nil {
|
if backend.LoadBalancer.Stickiness == nil {
|
||||||
stickiness = &types.Stickiness{}
|
if backend.LoadBalancer.Sticky {
|
||||||
|
stickiness = &types.Stickiness{
|
||||||
|
CookieName: "_TRAEFIK_BACKEND",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
stickiness = backend.LoadBalancer.Stickiness
|
||||||
|
}
|
||||||
}
|
}
|
||||||
backend.LoadBalancer = &types.LoadBalancer{
|
backend.LoadBalancer = &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
sticky = {{getAttribute "backend.loadbalancer.sticky" .Attributes "false"}}
|
sticky = {{getAttribute "backend.loadbalancer.sticky" .Attributes "false"}}
|
||||||
{{if hasStickinessLabel .Attributes}}
|
{{if hasStickinessLabel .Attributes}}
|
||||||
[Backends."backend-{{$service}}".LoadBalancer.Stickiness]
|
[Backends."backend-{{$service}}".LoadBalancer.Stickiness]
|
||||||
cookieName = {{getStickinessCookieName .Attributes}}
|
cookieName = "{{getStickinessCookieName .Attributes}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasMaxconnAttributes .Attributes}}
|
{{if hasMaxconnAttributes .Attributes}}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
method = "{{getLoadBalancerMethod $backend}}"
|
method = "{{getLoadBalancerMethod $backend}}"
|
||||||
{{if hasStickinessLabel $backend}}
|
{{if hasStickinessLabel $backend}}
|
||||||
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
||||||
cookieName = {{getStickinessCookieName $backend}}
|
cookieName = "{{getStickinessCookieName $backend}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
method = "{{ getLoadBalancerMethod $instances}}"
|
method = "{{ getLoadBalancerMethod $instances}}"
|
||||||
{{if hasStickinessLabel $instances}}
|
{{if hasStickinessLabel $instances}}
|
||||||
[Backends.backend-{{ $serviceName }}.LoadBalancer.Stickiness]
|
[Backends.backend-{{ $serviceName }}.LoadBalancer.Stickiness]
|
||||||
cookieName = {{getStickinessCookieName $instances}}
|
cookieName = "{{getStickinessCookieName $instances}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range $index, $i := $instances}}
|
{{range $index, $i := $instances}}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
method = "{{$backend.LoadBalancer.Method}}"
|
method = "{{$backend.LoadBalancer.Method}}"
|
||||||
{{if $backend.LoadBalancer.Stickiness}}
|
{{if $backend.LoadBalancer.Stickiness}}
|
||||||
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
||||||
cookieName = {{$backend.LoadBalancer.Stickiness.CookieName}}
|
cookieName = "{{$backend.LoadBalancer.Stickiness.CookieName}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range $serverName, $server := $backend.Servers}}
|
{{range $serverName, $server := $backend.Servers}}
|
||||||
[backends."{{$backendName}}".servers."{{$serverName}}"]
|
[backends."{{$backendName}}".servers."{{$serverName}}"]
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
method = "{{getLoadBalancerMethod $app }}"
|
method = "{{getLoadBalancerMethod $app }}"
|
||||||
{{if hasStickinessLabel $app}}
|
{{if hasStickinessLabel $app}}
|
||||||
[Backends."backend{{getBackend $app $serviceName }}".LoadBalancer.Stickiness]
|
[Backends."backend{{getBackend $app $serviceName }}".LoadBalancer.Stickiness]
|
||||||
cookieName = {{getStickinessCookieName $app}}
|
cookieName = "{{getStickinessCookieName $app}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{ if hasCircuitBreakerLabels $app }}
|
{{ if hasCircuitBreakerLabels $app }}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
method = "{{getLoadBalancerMethod $backend}}"
|
method = "{{getLoadBalancerMethod $backend}}"
|
||||||
{{if hasStickinessLabel $backend}}
|
{{if hasStickinessLabel $backend}}
|
||||||
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
||||||
cookieName = {{getStickinessCookieName $backend}}
|
cookieName = "{{getStickinessCookieName $backend}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue