Stickiness cookie name
This commit is contained in:
parent
ed2eb7b5a6
commit
a9d4b09bdb
24 changed files with 434 additions and 224 deletions
|
@ -385,10 +385,6 @@ func (p *CatalogProvider) getBackendName(node *api.ServiceEntry, index int) stri
|
||||||
return serviceName
|
return serviceName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) getAttribute(name string, tags []string, defaultValue string) string {
|
|
||||||
return p.getTag(p.getPrefixedName(name), tags, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *CatalogProvider) getBasicAuth(tags []string) []string {
|
func (p *CatalogProvider) getBasicAuth(tags []string) []string {
|
||||||
list := p.getAttribute("frontend.auth.basic", tags, "")
|
list := p.getAttribute("frontend.auth.basic", tags, "")
|
||||||
if list != "" {
|
if list != "" {
|
||||||
|
@ -397,6 +393,27 @@ func (p *CatalogProvider) getBasicAuth(tags []string) []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) hasStickinessLabel(tags []string) bool {
|
||||||
|
stickinessTag := p.getTag(types.LabelBackendLoadbalancerStickiness, tags, "")
|
||||||
|
|
||||||
|
stickyTag := p.getTag(types.LabelBackendLoadbalancerSticky, tags, "")
|
||||||
|
if len(stickyTag) > 0 {
|
||||||
|
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
}
|
||||||
|
|
||||||
|
stickiness := len(stickinessTag) > 0 && strings.EqualFold(strings.TrimSpace(stickinessTag), "true")
|
||||||
|
sticky := len(stickyTag) > 0 && strings.EqualFold(strings.TrimSpace(stickyTag), "true")
|
||||||
|
return stickiness || sticky
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) getStickinessCookieName(tags []string) string {
|
||||||
|
return p.getTag(types.LabelBackendLoadbalancerStickinessCookieName, tags, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) getAttribute(name string, tags []string, defaultValue string) string {
|
||||||
|
return p.getTag(p.getPrefixedName(name), tags, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) hasTag(name string, tags []string) bool {
|
func (p *CatalogProvider) hasTag(name string, tags []string) bool {
|
||||||
// Very-very unlikely that a Consul tag would ever start with '=!='
|
// Very-very unlikely that a Consul tag would ever start with '=!='
|
||||||
tag := p.getTag(name, tags, "=!=")
|
tag := p.getTag(name, tags, "=!=")
|
||||||
|
@ -443,8 +460,10 @@ func (p *CatalogProvider) buildConfig(catalog []catalogUpdate) *types.Configurat
|
||||||
"getFrontendRule": p.getFrontendRule,
|
"getFrontendRule": p.getFrontendRule,
|
||||||
"getBackendName": p.getBackendName,
|
"getBackendName": p.getBackendName,
|
||||||
"getBackendAddress": p.getBackendAddress,
|
"getBackendAddress": p.getBackendAddress,
|
||||||
"getAttribute": p.getAttribute,
|
|
||||||
"getBasicAuth": p.getBasicAuth,
|
"getBasicAuth": p.getBasicAuth,
|
||||||
|
"hasStickinessLabel": p.hasStickinessLabel,
|
||||||
|
"getStickinessCookieName": p.getStickinessCookieName,
|
||||||
|
"getAttribute": p.getAttribute,
|
||||||
"getTag": p.getTag,
|
"getTag": p.getTag,
|
||||||
"hasTag": p.hasTag,
|
"hasTag": p.hasTag,
|
||||||
"getEntryPoints": p.getEntryPoints,
|
"getEntryPoints": p.getEntryPoints,
|
||||||
|
|
|
@ -275,7 +275,8 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
||||||
"hasMaxConnLabels": p.hasMaxConnLabels,
|
"hasMaxConnLabels": p.hasMaxConnLabels,
|
||||||
"getMaxConnAmount": p.getMaxConnAmount,
|
"getMaxConnAmount": p.getMaxConnAmount,
|
||||||
"getMaxConnExtractorFunc": p.getMaxConnExtractorFunc,
|
"getMaxConnExtractorFunc": p.getMaxConnExtractorFunc,
|
||||||
"getSticky": p.getSticky,
|
"getStickinessCookieName": p.getStickinessCookieName,
|
||||||
|
"hasStickinessLabel": p.hasStickinessLabel,
|
||||||
"getIsBackendLBSwarm": p.getIsBackendLBSwarm,
|
"getIsBackendLBSwarm": p.getIsBackendLBSwarm,
|
||||||
"hasServices": p.hasServices,
|
"hasServices": p.hasServices,
|
||||||
"getServiceNames": p.getServiceNames,
|
"getServiceNames": p.getServiceNames,
|
||||||
|
@ -328,10 +329,8 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasCircuitBreakerLabel(container dockerData) bool {
|
func (p *Provider) hasCircuitBreakerLabel(container dockerData) bool {
|
||||||
if _, err := getLabel(container, types.LabelBackendCircuitbreakerExpression); err != nil {
|
_, err := getLabel(container, types.LabelBackendCircuitbreakerExpression)
|
||||||
return false
|
return err == nil
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regexp used to extract the name of the service and the name of the property for this service
|
// Regexp used to extract the name of the service and the name of the property for this service
|
||||||
|
@ -645,11 +644,22 @@ func (p *Provider) getWeight(container dockerData) string {
|
||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getSticky(container dockerData) string {
|
func (p *Provider) hasStickinessLabel(container dockerData) bool {
|
||||||
if label, err := getLabel(container, types.LabelBackendLoadbalancerSticky); err == nil {
|
_, errStickiness := getLabel(container, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
|
||||||
|
label, errSticky := getLabel(container, types.LabelBackendLoadbalancerSticky)
|
||||||
|
if len(label) > 0 {
|
||||||
|
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errStickiness == nil || (errSticky == nil && strings.EqualFold(strings.TrimSpace(label), "true"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getStickinessCookieName(container dockerData) string {
|
||||||
|
if label, err := getLabel(container, types.LabelBackendLoadbalancerStickinessCookieName); err == nil {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "false"
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getIsBackendLBSwarm(container dockerData) string {
|
func (p *Provider) getIsBackendLBSwarm(container dockerData) string {
|
||||||
|
|
|
@ -162,12 +162,12 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
})
|
})
|
||||||
|
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
aws, err := p.createClient()
|
awsClient, err := p.createClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleCanceled(ctx, err)
|
return handleCanceled(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration, err := p.loadDynamoConfig(aws)
|
configuration, err := p.loadDynamoConfig(awsClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleCanceled(ctx, err)
|
return handleCanceled(ctx, err)
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
log.Debug("Watching Provider...")
|
log.Debug("Watching Provider...")
|
||||||
select {
|
select {
|
||||||
case <-reload.C:
|
case <-reload.C:
|
||||||
configuration, err := p.loadDynamoConfig(aws)
|
configuration, err := p.loadDynamoConfig(awsClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleCanceled(ctx, err)
|
return handleCanceled(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,12 +122,12 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
})
|
})
|
||||||
|
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
aws, err := p.createClient()
|
awsClient, err := p.createClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration, err := p.loadECSConfig(ctx, aws)
|
configuration, err := p.loadECSConfig(ctx, awsClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleCanceled(ctx, err)
|
return handleCanceled(ctx, err)
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-reload.C:
|
case <-reload.C:
|
||||||
configuration, err := p.loadECSConfig(ctx, aws)
|
configuration, err := p.loadECSConfig(ctx, awsClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleCanceled(ctx, err)
|
return handleCanceled(ctx, err)
|
||||||
}
|
}
|
||||||
|
@ -183,8 +183,9 @@ func (p *Provider) loadECSConfig(ctx context.Context, client *awsClient) (*types
|
||||||
"filterFrontends": p.filterFrontends,
|
"filterFrontends": p.filterFrontends,
|
||||||
"getFrontendRule": p.getFrontendRule,
|
"getFrontendRule": p.getFrontendRule,
|
||||||
"getBasicAuth": p.getBasicAuth,
|
"getBasicAuth": p.getBasicAuth,
|
||||||
"getLoadBalancerSticky": p.getLoadBalancerSticky,
|
|
||||||
"getLoadBalancerMethod": p.getLoadBalancerMethod,
|
"getLoadBalancerMethod": p.getLoadBalancerMethod,
|
||||||
|
"hasStickinessLabel": p.hasStickinessLabel,
|
||||||
|
"getStickinessCookieName": p.getStickinessCookieName,
|
||||||
}
|
}
|
||||||
|
|
||||||
instances, err := p.listInstances(ctx, client)
|
instances, err := p.listInstances(ctx, client)
|
||||||
|
@ -477,14 +478,27 @@ func (p *Provider) getBasicAuth(i ecsInstance) []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getLoadBalancerSticky(instances []ecsInstance) string {
|
func getFirstInstanceLabel(instances []ecsInstance, labelName string) string {
|
||||||
if len(instances) > 0 {
|
if len(instances) > 0 {
|
||||||
label := instances[0].label(types.LabelBackendLoadbalancerSticky)
|
return instances[0].label(labelName)
|
||||||
if label != "" {
|
|
||||||
return label
|
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return "false"
|
|
||||||
|
func (p *Provider) hasStickinessLabel(instances []ecsInstance) bool {
|
||||||
|
stickinessLabel := getFirstInstanceLabel(instances, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
|
||||||
|
stickyLabel := getFirstInstanceLabel(instances, types.LabelBackendLoadbalancerSticky)
|
||||||
|
if len(stickyLabel) > 0 {
|
||||||
|
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
}
|
||||||
|
stickiness := len(stickinessLabel) > 0 && strings.EqualFold(strings.TrimSpace(stickinessLabel), "true")
|
||||||
|
sticky := len(stickyLabel) > 0 && strings.EqualFold(strings.TrimSpace(stickyLabel), "true")
|
||||||
|
return stickiness || sticky
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getStickinessCookieName(instances []ecsInstance) string {
|
||||||
|
return getFirstInstanceLabel(instances, types.LabelBackendLoadbalancerStickinessCookieName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getLoadBalancerMethod(instances []ecsInstance) string {
|
func (p *Provider) getLoadBalancerMethod(instances []ecsInstance) string {
|
||||||
|
|
|
@ -18,6 +18,7 @@ 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"
|
||||||
|
@ -160,7 +161,6 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
templateObjects.Backends[r.Host+pa.Path] = &types.Backend{
|
templateObjects.Backends[r.Host+pa.Path] = &types.Backend{
|
||||||
Servers: make(map[string]types.Server),
|
Servers: make(map[string]types.Server),
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -247,8 +247,14 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Method = "drr"
|
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Method = "drr"
|
||||||
}
|
}
|
||||||
|
|
||||||
if service.Annotations[types.LabelBackendLoadbalancerSticky] == "true" {
|
if len(service.Annotations[types.LabelBackendLoadbalancerSticky]) > 0 {
|
||||||
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Sticky = true
|
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
|
}
|
||||||
|
|
||||||
|
if service.Annotations[types.LabelBackendLoadbalancerSticky] == "true" || service.Annotations[types.LabelBackendLoadbalancerStickiness] == "true" {
|
||||||
|
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Stickiness = &types.Stickiness{
|
||||||
|
CookieName: cookie.GenerateName(r.Host + pa.Path),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol := "http"
|
protocol := "http"
|
||||||
|
|
|
@ -243,7 +243,6 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -256,7 +255,6 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -273,7 +271,6 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -489,7 +486,6 @@ func TestGetPassHostHeader(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -591,7 +587,6 @@ func TestOnlyReferencesServicesFromOwnNamespace(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -771,7 +766,6 @@ func TestLoadNamespacedIngresses(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -779,7 +773,6 @@ func TestLoadNamespacedIngresses(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -996,7 +989,6 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1004,7 +996,6 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1012,7 +1003,6 @@ func TestLoadMultipleNamespacedIngresses(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1118,7 +1108,6 @@ func TestHostlessIngress(t *testing.T) {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1320,7 +1309,6 @@ func TestServiceAnnotations(t *testing.T) {
|
||||||
},
|
},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "drr",
|
Method: "drr",
|
||||||
Sticky: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"bar": {
|
"bar": {
|
||||||
|
@ -1337,7 +1325,9 @@ func TestServiceAnnotations(t *testing.T) {
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
Sticky: true,
|
Stickiness: &types.Stickiness{
|
||||||
|
CookieName: "_4155f",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1601,7 +1591,6 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1614,7 +1603,6 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1627,7 +1615,6 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1640,7 +1627,6 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1653,7 +1639,6 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1807,7 +1792,6 @@ func TestPriorityHeaderValue(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1909,7 +1893,6 @@ func TestInvalidPassHostHeaderValue(t *testing.T) {
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Sticky: false,
|
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -2192,14 +2175,12 @@ func TestMissingResources(t *testing.T) {
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
Sticky: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"missing_service": {
|
"missing_service": {
|
||||||
Servers: map[string]types.Server{},
|
Servers: map[string]types.Server{},
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
Sticky: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"missing_endpoints": {
|
"missing_endpoints": {
|
||||||
|
@ -2207,7 +2188,6 @@ func TestMissingResources(t *testing.T) {
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
Sticky: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"missing_endpoint_subsets": {
|
"missing_endpoint_subsets": {
|
||||||
|
@ -2215,7 +2195,6 @@ func TestMissingResources(t *testing.T) {
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
LoadBalancer: &types.LoadBalancer{
|
LoadBalancer: &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
Sticky: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -144,6 +144,8 @@ func (p *Provider) loadConfig() *types.Configuration {
|
||||||
"Get": p.get,
|
"Get": p.get,
|
||||||
"SplitGet": p.splitGet,
|
"SplitGet": p.splitGet,
|
||||||
"Last": p.last,
|
"Last": p.last,
|
||||||
|
"hasStickinessLabel": p.hasStickinessLabel,
|
||||||
|
"getStickinessCookieName": p.getStickinessCookieName,
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration, err := p.GetConfiguration("templates/kv.tmpl", KvFuncMap, templateObjects)
|
configuration, err := p.GetConfiguration("templates/kv.tmpl", KvFuncMap, templateObjects)
|
||||||
|
@ -239,3 +241,17 @@ func (p *Provider) checkConstraints(keys ...string) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) hasStickinessLabel(rootPath string) bool {
|
||||||
|
stickiness, err := p.kvclient.Exists(rootPath + "/loadbalancer/stickiness")
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getStickinessCookieName(rootPath string) string {
|
||||||
|
return p.get("", rootPath, "/loadbalancer", "/stickiness", "/cookiename")
|
||||||
|
}
|
||||||
|
|
|
@ -188,7 +188,8 @@ func (p *Provider) loadMarathonConfig() *types.Configuration {
|
||||||
"getMaxConnAmount": p.getMaxConnAmount,
|
"getMaxConnAmount": p.getMaxConnAmount,
|
||||||
"getLoadBalancerMethod": p.getLoadBalancerMethod,
|
"getLoadBalancerMethod": p.getLoadBalancerMethod,
|
||||||
"getCircuitBreakerExpression": p.getCircuitBreakerExpression,
|
"getCircuitBreakerExpression": p.getCircuitBreakerExpression,
|
||||||
"getSticky": p.getSticky,
|
"getStickinessCookieName": p.getStickinessCookieName,
|
||||||
|
"hasStickinessLabel": p.hasStickinessLabel,
|
||||||
"hasHealthCheckLabels": p.hasHealthCheckLabels,
|
"hasHealthCheckLabels": p.hasHealthCheckLabels,
|
||||||
"getHealthCheckPath": p.getHealthCheckPath,
|
"getHealthCheckPath": p.getHealthCheckPath,
|
||||||
"getHealthCheckInterval": p.getHealthCheckInterval,
|
"getHealthCheckInterval": p.getHealthCheckInterval,
|
||||||
|
@ -428,11 +429,22 @@ func (p *Provider) getProtocol(application marathon.Application, serviceName str
|
||||||
return "http"
|
return "http"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getSticky(application marathon.Application) string {
|
func (p *Provider) hasStickinessLabel(application marathon.Application) bool {
|
||||||
if sticky, ok := p.getAppLabel(application, types.LabelBackendLoadbalancerSticky); ok {
|
_, okStickiness := p.getAppLabel(application, types.LabelBackendLoadbalancerStickiness)
|
||||||
return sticky
|
|
||||||
|
label, okSticky := p.getAppLabel(application, types.LabelBackendLoadbalancerSticky)
|
||||||
|
if len(label) > 0 {
|
||||||
|
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
return "false"
|
|
||||||
|
return okStickiness || (okSticky && strings.EqualFold(strings.TrimSpace(label), "true"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getStickinessCookieName(application marathon.Application) string {
|
||||||
|
if label, ok := p.getAppLabel(application, types.LabelBackendLoadbalancerStickinessCookieName); ok {
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getPassHostHeader(application marathon.Application, serviceName string) string {
|
func (p *Provider) getPassHostHeader(application marathon.Application, serviceName string) string {
|
||||||
|
|
|
@ -855,21 +855,36 @@ func TestMarathonGetProtocol(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarathonGetSticky(t *testing.T) {
|
func TestMarathonHasStickinessLabel(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
desc string
|
desc string
|
||||||
application marathon.Application
|
application marathon.Application
|
||||||
expected string
|
expected bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "label missing",
|
desc: "label missing",
|
||||||
application: application(),
|
application: application(),
|
||||||
expected: "false",
|
expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "label existing",
|
desc: "label existing and value equals 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)",
|
||||||
|
application: application(label(types.LabelBackendLoadbalancerSticky, "false")),
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "label existing and value equals true",
|
||||||
|
application: application(label(types.LabelBackendLoadbalancerStickiness, "true")),
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "label existing and value equals false ",
|
||||||
|
application: application(label(types.LabelBackendLoadbalancerStickiness, "true")),
|
||||||
|
expected: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,7 +893,7 @@ func TestMarathonGetSticky(t *testing.T) {
|
||||||
t.Run(c.desc, func(t *testing.T) {
|
t.Run(c.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
provider := &Provider{}
|
provider := &Provider{}
|
||||||
actual := provider.getSticky(c.application)
|
actual := provider.hasStickinessLabel(c.application)
|
||||||
if actual != c.expected {
|
if actual != c.expected {
|
||||||
t.Errorf("actual %q, expected %q", actual, c.expected)
|
t.Errorf("actual %q, expected %q", actual, c.expected)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ type BaseProvider struct {
|
||||||
// MatchConstraints must match with EVERY single contraint
|
// MatchConstraints must match with EVERY single contraint
|
||||||
// returns first constraint that do not match or nil
|
// returns first constraint that do not match or nil
|
||||||
func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint) {
|
func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint) {
|
||||||
// if there is no tags and no contraints, filtering is disabled
|
// if there is no tags and no constraints, filtering is disabled
|
||||||
if len(tags) == 0 && len(p.Constraints) == 0 {
|
if len(tags) == 0 && len(p.Constraints) == 0 {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,11 +112,22 @@ func (p *Provider) getCircuitBreakerExpression(service rancherData) string {
|
||||||
return "NetworkErrorRatio() > 1"
|
return "NetworkErrorRatio() > 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getSticky(service rancherData) string {
|
func (p *Provider) hasStickinessLabel(service rancherData) bool {
|
||||||
if _, err := getServiceLabel(service, types.LabelBackendLoadbalancerSticky); err == nil {
|
_, errStickiness := getServiceLabel(service, types.LabelBackendLoadbalancerStickiness)
|
||||||
return "true"
|
|
||||||
|
label, errSticky := getServiceLabel(service, types.LabelBackendLoadbalancerSticky)
|
||||||
|
if len(label) > 0 {
|
||||||
|
log.Warn("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
||||||
}
|
}
|
||||||
return "false"
|
|
||||||
|
return errStickiness == nil || (errSticky == nil && strings.EqualFold(strings.TrimSpace(label), "true"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getStickinessCookieName(service rancherData, backendName string) string {
|
||||||
|
if label, err := getServiceLabel(service, types.LabelBackendLoadbalancerStickinessCookieName); err == nil {
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getBackend(service rancherData) string {
|
func (p *Provider) getBackend(service rancherData) string {
|
||||||
|
@ -222,7 +233,8 @@ func (p *Provider) loadRancherConfig(services []rancherData) *types.Configuratio
|
||||||
"hasMaxConnLabels": p.hasMaxConnLabels,
|
"hasMaxConnLabels": p.hasMaxConnLabels,
|
||||||
"getMaxConnAmount": p.getMaxConnAmount,
|
"getMaxConnAmount": p.getMaxConnAmount,
|
||||||
"getMaxConnExtractorFunc": p.getMaxConnExtractorFunc,
|
"getMaxConnExtractorFunc": p.getMaxConnExtractorFunc,
|
||||||
"getSticky": p.getSticky,
|
"hasStickinessLabel": p.hasStickinessLabel,
|
||||||
|
"getStickinessCookieName": p.getStickinessCookieName,
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter services
|
// filter services
|
||||||
|
|
57
server/cookie/cookie.go
Normal file
57
server/cookie/cookie.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package cookie
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const cookieNameLength = 6
|
||||||
|
|
||||||
|
// GetName of a cookie
|
||||||
|
func GetName(cookieName string, backendName string) string {
|
||||||
|
if len(cookieName) != 0 {
|
||||||
|
return sanitizeName(cookieName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return GenerateName(backendName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateName Generate a hashed name
|
||||||
|
func GenerateName(backendName string) string {
|
||||||
|
data := []byte("_TRAEFIK_BACKEND_" + backendName)
|
||||||
|
|
||||||
|
hash := sha1.New()
|
||||||
|
_, err := hash.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
// Impossible case
|
||||||
|
log.Errorf("Fail to create cookie name: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("_%x", hash.Sum(nil))[:cookieNameLength]
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanitizeName According to [RFC 2616](https://www.ietf.org/rfc/rfc2616.txt) section 2.2
|
||||||
|
func sanitizeName(backend string) string {
|
||||||
|
sanitizer := func(r rune) rune {
|
||||||
|
switch r {
|
||||||
|
case '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '`', '|', '~':
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case 'a' <= r && r <= 'z':
|
||||||
|
fallthrough
|
||||||
|
case 'A' <= r && r <= 'Z':
|
||||||
|
fallthrough
|
||||||
|
case '0' <= r && r <= '9':
|
||||||
|
return r
|
||||||
|
default:
|
||||||
|
return '_'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Map(sanitizer, backend)
|
||||||
|
}
|
83
server/cookie/cookie_test.go
Normal file
83
server/cookie/cookie_test.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package cookie
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetName(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
cookieName string
|
||||||
|
backendName string
|
||||||
|
expectedCookieName string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "with backend name, without cookie name",
|
||||||
|
cookieName: "",
|
||||||
|
backendName: "/my/BACKEND-v1.0~rc1",
|
||||||
|
expectedCookieName: "_5f7bc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "without backend name, with cookie name",
|
||||||
|
cookieName: "/my/BACKEND-v1.0~rc1",
|
||||||
|
backendName: "",
|
||||||
|
expectedCookieName: "_my_BACKEND-v1.0~rc1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "with backend name, with cookie name",
|
||||||
|
cookieName: "containous",
|
||||||
|
backendName: "treafik",
|
||||||
|
expectedCookieName: "containous",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cookieName := GetName(test.cookieName, test.backendName)
|
||||||
|
|
||||||
|
assert.Equal(t, test.expectedCookieName, cookieName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_sanitizeName(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
srcName string
|
||||||
|
expectedName string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "with /",
|
||||||
|
srcName: "/my/BACKEND-v1.0~rc1",
|
||||||
|
expectedName: "_my_BACKEND-v1.0~rc1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "some chars",
|
||||||
|
srcName: "!#$%&'()*+-./:<=>?@[]^_`{|}~",
|
||||||
|
expectedName: "!#$%&'__*+-._________^_`_|_~",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cookieName := sanitizeName(test.srcName)
|
||||||
|
|
||||||
|
assert.Equal(t, test.expectedName, cookieName, "Cookie name")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateName(t *testing.T) {
|
||||||
|
cookieName := GenerateName("containous")
|
||||||
|
|
||||||
|
assert.Len(t, "_8a7bc", 6)
|
||||||
|
assert.Equal(t, "_8a7bc", cookieName)
|
||||||
|
}
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -31,6 +30,7 @@ import (
|
||||||
mauth "github.com/containous/traefik/middlewares/auth"
|
mauth "github.com/containous/traefik/middlewares/auth"
|
||||||
"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"
|
||||||
"github.com/streamrail/concurrent-map"
|
"github.com/streamrail/concurrent-map"
|
||||||
thoas_stats "github.com/thoas/stats"
|
thoas_stats "github.com/thoas/stats"
|
||||||
|
@ -335,11 +335,11 @@ func (server *Server) listenProviders(stop chan bool) {
|
||||||
lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time)
|
lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time)
|
||||||
providersThrottleDuration := time.Duration(server.globalConfiguration.ProvidersThrottleDuration)
|
providersThrottleDuration := time.Duration(server.globalConfiguration.ProvidersThrottleDuration)
|
||||||
if time.Now().After(lastReceivedConfigurationValue.Add(providersThrottleDuration)) {
|
if time.Now().After(lastReceivedConfigurationValue.Add(providersThrottleDuration)) {
|
||||||
log.Debugf("Last %s config received more than %s, OK", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration.String())
|
log.Debugf("Last %s config received more than %s, OK", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration)
|
||||||
// last config received more than n s ago
|
// last config received more than n s ago
|
||||||
server.configurationValidatedChan <- configMsg
|
server.configurationValidatedChan <- configMsg
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Last %s config received less than %s, waiting...", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration.String())
|
log.Debugf("Last %s config received less than %s, waiting...", configMsg.ProviderName, server.globalConfiguration.ProvidersThrottleDuration)
|
||||||
safe.Go(func() {
|
safe.Go(func() {
|
||||||
<-time.After(providersThrottleDuration)
|
<-time.After(providersThrottleDuration)
|
||||||
lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time)
|
lastReceivedConfigurationValue := lastReceivedConfiguration.Get().(time.Time)
|
||||||
|
@ -826,11 +826,10 @@ func (server *Server) loadConfig(configurations types.Configurations, globalConf
|
||||||
continue frontend
|
continue frontend
|
||||||
}
|
}
|
||||||
|
|
||||||
stickySession := config.Backends[frontend.Backend].LoadBalancer.Sticky
|
|
||||||
cookieName := getCookieName(frontend.Backend)
|
|
||||||
var sticky *roundrobin.StickySession
|
var sticky *roundrobin.StickySession
|
||||||
|
var cookieName string
|
||||||
if stickySession {
|
if stickiness := config.Backends[frontend.Backend].LoadBalancer.Stickiness; stickiness != nil {
|
||||||
|
cookieName = cookie.GetName(stickiness.CookieName, frontend.Backend)
|
||||||
sticky = roundrobin.NewStickySession(cookieName)
|
sticky = roundrobin.NewStickySession(cookieName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,7 +838,7 @@ func (server *Server) loadConfig(configurations types.Configurations, globalConf
|
||||||
case types.Drr:
|
case types.Drr:
|
||||||
log.Debugf("Creating load-balancer drr")
|
log.Debugf("Creating load-balancer drr")
|
||||||
rebalancer, _ := roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger))
|
rebalancer, _ := roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger))
|
||||||
if stickySession {
|
if sticky != nil {
|
||||||
log.Debugf("Sticky session with cookie %v", cookieName)
|
log.Debugf("Sticky session with cookie %v", cookieName)
|
||||||
rebalancer, _ = roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger), roundrobin.RebalancerStickySession(sticky))
|
rebalancer, _ = roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger), roundrobin.RebalancerStickySession(sticky))
|
||||||
}
|
}
|
||||||
|
@ -856,7 +855,7 @@ func (server *Server) loadConfig(configurations types.Configurations, globalConf
|
||||||
lb = middlewares.NewEmptyBackendHandler(rebalancer, lb)
|
lb = middlewares.NewEmptyBackendHandler(rebalancer, lb)
|
||||||
case types.Wrr:
|
case types.Wrr:
|
||||||
log.Debugf("Creating load-balancer wrr")
|
log.Debugf("Creating load-balancer wrr")
|
||||||
if stickySession {
|
if sticky != nil {
|
||||||
log.Debugf("Sticky session with cookie %v", cookieName)
|
log.Debugf("Sticky session with cookie %v", cookieName)
|
||||||
if server.accessLoggerMiddleware != nil {
|
if server.accessLoggerMiddleware != nil {
|
||||||
rr, _ = roundrobin.New(saveFrontend, roundrobin.EnableStickySession(sticky))
|
rr, _ = roundrobin.New(saveFrontend, roundrobin.EnableStickySession(sticky))
|
||||||
|
@ -1150,16 +1149,31 @@ 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 {
|
||||||
|
log.Warn("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 {
|
||||||
|
backend.LoadBalancer.Stickiness = &types.Stickiness{}
|
||||||
|
}
|
||||||
|
} 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 sticky bool
|
|
||||||
|
var stickiness *types.Stickiness
|
||||||
if backend.LoadBalancer != nil {
|
if backend.LoadBalancer != nil {
|
||||||
sticky = backend.LoadBalancer.Sticky
|
if backend.LoadBalancer.Stickiness != nil {
|
||||||
|
stickiness = backend.LoadBalancer.Stickiness
|
||||||
|
} else if backend.LoadBalancer.Sticky {
|
||||||
|
if backend.LoadBalancer.Stickiness == nil {
|
||||||
|
stickiness = &types.Stickiness{}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
backend.LoadBalancer = &types.LoadBalancer{
|
backend.LoadBalancer = &types.LoadBalancer{
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
Sticky: sticky,
|
Stickiness: stickiness,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1209,28 +1223,3 @@ func (server *Server) buildRetryMiddleware(handler http.Handler, globalConfig co
|
||||||
|
|
||||||
return middlewares.NewRetry(retryAttempts, handler, retryListeners)
|
return middlewares.NewRetry(retryAttempts, handler, retryListeners)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCookieName returns a cookie name from the given backend, sanitizing
|
|
||||||
// characters that do not satisfy the requirements of RFC 2616.
|
|
||||||
func getCookieName(backend string) string {
|
|
||||||
const cookiePrefix = "_TRAEFIK_BACKEND_"
|
|
||||||
sanitizer := func(r rune) rune {
|
|
||||||
switch r {
|
|
||||||
case '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '`', '|', '~':
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case r >= 'a' && r <= 'z':
|
|
||||||
fallthrough
|
|
||||||
case r >= 'A' && r <= 'Z':
|
|
||||||
fallthrough
|
|
||||||
case r >= '0' && r <= '9':
|
|
||||||
return r
|
|
||||||
default:
|
|
||||||
return '_'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cookiePrefix + strings.Map(sanitizer, backend)
|
|
||||||
}
|
|
||||||
|
|
|
@ -425,49 +425,46 @@ func TestConfigureBackends(t *testing.T) {
|
||||||
desc string
|
desc string
|
||||||
lb *types.LoadBalancer
|
lb *types.LoadBalancer
|
||||||
wantMethod string
|
wantMethod string
|
||||||
wantSticky bool
|
wantStickiness *types.Stickiness
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "valid load balancer method with sticky enabled",
|
desc: "valid load balancer method with sticky enabled",
|
||||||
lb: &types.LoadBalancer{
|
lb: &types.LoadBalancer{
|
||||||
Method: validMethod,
|
Method: validMethod,
|
||||||
Sticky: true,
|
Stickiness: &types.Stickiness{},
|
||||||
},
|
},
|
||||||
wantMethod: validMethod,
|
wantMethod: validMethod,
|
||||||
wantSticky: true,
|
wantStickiness: &types.Stickiness{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "valid load balancer method with sticky disabled",
|
desc: "valid load balancer method with sticky disabled",
|
||||||
lb: &types.LoadBalancer{
|
lb: &types.LoadBalancer{
|
||||||
Method: validMethod,
|
Method: validMethod,
|
||||||
Sticky: false,
|
Stickiness: nil,
|
||||||
},
|
},
|
||||||
wantMethod: validMethod,
|
wantMethod: validMethod,
|
||||||
wantSticky: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "invalid load balancer method with sticky enabled",
|
desc: "invalid load balancer method with sticky enabled",
|
||||||
lb: &types.LoadBalancer{
|
lb: &types.LoadBalancer{
|
||||||
Method: "Invalid",
|
Method: "Invalid",
|
||||||
Sticky: true,
|
Stickiness: &types.Stickiness{},
|
||||||
},
|
},
|
||||||
wantMethod: defaultMethod,
|
wantMethod: defaultMethod,
|
||||||
wantSticky: true,
|
wantStickiness: &types.Stickiness{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "invalid load balancer method with sticky disabled",
|
desc: "invalid load balancer method with sticky disabled",
|
||||||
lb: &types.LoadBalancer{
|
lb: &types.LoadBalancer{
|
||||||
Method: "Invalid",
|
Method: "Invalid",
|
||||||
Sticky: false,
|
Stickiness: nil,
|
||||||
},
|
},
|
||||||
wantMethod: defaultMethod,
|
wantMethod: defaultMethod,
|
||||||
wantSticky: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "missing load balancer",
|
desc: "missing load balancer",
|
||||||
lb: nil,
|
lb: nil,
|
||||||
wantMethod: defaultMethod,
|
wantMethod: defaultMethod,
|
||||||
wantSticky: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +483,7 @@ func TestConfigureBackends(t *testing.T) {
|
||||||
|
|
||||||
wantLB := types.LoadBalancer{
|
wantLB := types.LoadBalancer{
|
||||||
Method: test.wantMethod,
|
Method: test.wantMethod,
|
||||||
Sticky: test.wantSticky,
|
Stickiness: test.wantStickiness,
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(*backend.LoadBalancer, wantLB) {
|
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))
|
t.Errorf("got backend load-balancer\n%v\nwant\n%v\n", spew.Sdump(backend.LoadBalancer), spew.Sdump(wantLB))
|
||||||
|
@ -659,13 +656,6 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetCookieName(t *testing.T) {
|
|
||||||
want := "_TRAEFIK_BACKEND__my_BACKEND-v1.0~rc1"
|
|
||||||
if got := getCookieName("/my/BACKEND-v1.0~rc1"); got != want {
|
|
||||||
t.Errorf("got sticky cookie name %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildDynamicConfig(dynamicConfigBuilders ...func(*types.Configuration)) *types.Configuration {
|
func buildDynamicConfig(dynamicConfigBuilders ...func(*types.Configuration)) *types.Configuration {
|
||||||
config := &types.Configuration{
|
config := &types.Configuration{
|
||||||
Frontends: make(map[string]*types.Frontend),
|
Frontends: make(map[string]*types.Frontend),
|
||||||
|
@ -726,6 +716,10 @@ func withServer(name, url string) func(backend *types.Backend) {
|
||||||
|
|
||||||
func withLoadBalancer(method string, sticky bool) func(*types.Backend) {
|
func withLoadBalancer(method string, sticky bool) func(*types.Backend) {
|
||||||
return func(be *types.Backend) {
|
return func(be *types.Backend) {
|
||||||
be.LoadBalancer = &types.LoadBalancer{Method: method, Sticky: sticky}
|
if sticky {
|
||||||
|
be.LoadBalancer = &types.LoadBalancer{Method: method, Stickiness: &types.Stickiness{CookieName: "test"}}
|
||||||
|
} else {
|
||||||
|
be.LoadBalancer = &types.LoadBalancer{Method: method}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,12 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
[backends."backend-{{$service}}".loadbalancer]
|
[backends."backend-{{$service}}".loadbalancer]
|
||||||
sticky = {{getAttribute "backend.loadbalancer.sticky" .Attributes "false"}}
|
|
||||||
method = "{{getAttribute "backend.loadbalancer" .Attributes "wrr"}}"
|
method = "{{getAttribute "backend.loadbalancer" .Attributes "wrr"}}"
|
||||||
|
sticky = {{getAttribute "backend.loadbalancer.sticky" .Attributes "false"}}
|
||||||
|
{{if hasStickinessLabel .Attributes}}
|
||||||
|
[Backends."backend-{{$service}}".LoadBalancer.Stickiness]
|
||||||
|
cookieName = {{getStickinessCookieName .Attributes}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if hasMaxconnAttributes .Attributes}}
|
{{if hasMaxconnAttributes .Attributes}}
|
||||||
[backends."backend-{{$service}}".maxconn]
|
[backends."backend-{{$service}}".maxconn]
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
{{if hasLoadBalancerLabel $backend}}
|
{{if hasLoadBalancerLabel $backend}}
|
||||||
[backends.backend-{{$backendName}}.loadbalancer]
|
[backends.backend-{{$backendName}}.loadbalancer]
|
||||||
method = "{{getLoadBalancerMethod $backend}}"
|
method = "{{getLoadBalancerMethod $backend}}"
|
||||||
sticky = {{getSticky $backend}}
|
{{if hasStickinessLabel $backend}}
|
||||||
|
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
||||||
|
cookieName = {{getStickinessCookieName $backend}}
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasMaxConnLabels $backend}}
|
{{if hasMaxConnLabels $backend}}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
[backends]{{range $serviceName, $instances := .Services}}
|
[backends]{{range $serviceName, $instances := .Services}}
|
||||||
[backends.backend-{{ $serviceName }}.loadbalancer]
|
[backends.backend-{{ $serviceName }}.loadbalancer]
|
||||||
sticky = {{ getLoadBalancerSticky $instances}}
|
|
||||||
method = "{{ getLoadBalancerMethod $instances}}"
|
method = "{{ getLoadBalancerMethod $instances}}"
|
||||||
|
{{if hasStickinessLabel $instances}}
|
||||||
|
[Backends.backend-{{ $serviceName }}.LoadBalancer.Stickiness]
|
||||||
|
cookieName = {{getStickinessCookieName $instances}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{range $index, $i := $instances}}
|
{{range $index, $i := $instances}}
|
||||||
[backends.backend-{{ $i.Name }}.servers.server-{{ $i.Name }}{{ $i.ID }}]
|
[backends.backend-{{ $i.Name }}.servers.server-{{ $i.Name }}{{ $i.ID }}]
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
[backends."{{$backendName}}".loadbalancer]
|
[backends."{{$backendName}}".loadbalancer]
|
||||||
method = "{{$backend.LoadBalancer.Method}}"
|
method = "{{$backend.LoadBalancer.Method}}"
|
||||||
{{if $backend.LoadBalancer.Sticky}}
|
{{if $backend.LoadBalancer.Stickiness}}
|
||||||
sticky = true
|
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
||||||
|
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}}"]
|
||||||
|
|
|
@ -3,25 +3,29 @@
|
||||||
|
|
||||||
[backends]{{range $backends}}
|
[backends]{{range $backends}}
|
||||||
{{$backend := .}}
|
{{$backend := .}}
|
||||||
|
{{$backendName := Last $backend}}
|
||||||
{{$servers := ListServers $backend }}
|
{{$servers := ListServers $backend }}
|
||||||
|
|
||||||
{{$circuitBreaker := Get "" . "/circuitbreaker/" "expression"}}
|
{{$circuitBreaker := Get "" . "/circuitbreaker/" "expression"}}
|
||||||
{{with $circuitBreaker}}
|
{{with $circuitBreaker}}
|
||||||
[backends."{{Last $backend}}".circuitBreaker]
|
[backends."{{$backendName}}".circuitBreaker]
|
||||||
expression = "{{$circuitBreaker}}"
|
expression = "{{$circuitBreaker}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{$loadBalancer := Get "" . "/loadbalancer/" "method"}}
|
{{$loadBalancer := Get "" . "/loadbalancer/" "method"}}
|
||||||
{{$sticky := Get "false" . "/loadbalancer/" "sticky"}}
|
|
||||||
{{with $loadBalancer}}
|
{{with $loadBalancer}}
|
||||||
[backends."{{Last $backend}}".loadBalancer]
|
[backends."{{$backendName}}".loadBalancer]
|
||||||
method = "{{$loadBalancer}}"
|
method = "{{$loadBalancer}}"
|
||||||
sticky = {{$sticky}}
|
sticky = {{ Get "false" . "/loadbalancer/" "sticky" }}
|
||||||
|
{{if hasStickinessLabel $backend}}
|
||||||
|
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
||||||
|
cookieName = {{getStickinessCookieName $backend}}
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{$healthCheck := Get "" . "/healthcheck/" "path"}}
|
{{$healthCheck := Get "" . "/healthcheck/" "path"}}
|
||||||
{{with $healthCheck}}
|
{{with $healthCheck}}
|
||||||
[backends."{{Last $backend}}".healthCheck]
|
[backends."{{$backendName}}".healthCheck]
|
||||||
path = "{{$healthCheck}}"
|
path = "{{$healthCheck}}"
|
||||||
interval = "{{ Get "30s" $backend "/healthcheck/" "interval" }}"
|
interval = "{{ Get "30s" $backend "/healthcheck/" "interval" }}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -30,14 +34,14 @@
|
||||||
{{$maxConnExtractorFunc := Get "" . "/maxconn/" "extractorfunc"}}
|
{{$maxConnExtractorFunc := Get "" . "/maxconn/" "extractorfunc"}}
|
||||||
{{with $maxConnAmt}}
|
{{with $maxConnAmt}}
|
||||||
{{with $maxConnExtractorFunc}}
|
{{with $maxConnExtractorFunc}}
|
||||||
[backends."{{Last $backend}}".maxConn]
|
[backends."{{$backendName}}".maxConn]
|
||||||
amount = {{$maxConnAmt}}
|
amount = {{$maxConnAmt}}
|
||||||
extractorFunc = "{{$maxConnExtractorFunc}}"
|
extractorFunc = "{{$maxConnExtractorFunc}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range $servers}}
|
{{range $servers}}
|
||||||
[backends."{{Last $backend}}".servers."{{Last .}}"]
|
[backends."{{$backendName}}".servers."{{Last .}}"]
|
||||||
url = "{{Get "" . "/url"}}"
|
url = "{{Get "" . "/url"}}"
|
||||||
weight = {{Get "0" . "/weight"}}
|
weight = {{Get "0" . "/weight"}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -20,7 +20,10 @@
|
||||||
{{ if hasLoadBalancerLabels $app }}
|
{{ if hasLoadBalancerLabels $app }}
|
||||||
[backends."backend{{getBackend $app $serviceName }}".loadbalancer]
|
[backends."backend{{getBackend $app $serviceName }}".loadbalancer]
|
||||||
method = "{{getLoadBalancerMethod $app }}"
|
method = "{{getLoadBalancerMethod $app }}"
|
||||||
sticky = {{getSticky $app}}
|
{{if hasStickinessLabel $app}}
|
||||||
|
[Backends."backend{{getBackend $app $serviceName }}".LoadBalancer.Stickiness]
|
||||||
|
cookieName = {{getStickinessCookieName $app}}
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{ if hasCircuitBreakerLabels $app }}
|
{{ if hasCircuitBreakerLabels $app }}
|
||||||
[backends."backend{{getBackend $app $serviceName }}".circuitbreaker]
|
[backends."backend{{getBackend $app $serviceName }}".circuitbreaker]
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
{{if hasLoadBalancerLabel $backend}}
|
{{if hasLoadBalancerLabel $backend}}
|
||||||
[backends.backend-{{$backendName}}.loadbalancer]
|
[backends.backend-{{$backendName}}.loadbalancer]
|
||||||
method = "{{getLoadBalancerMethod $backend}}"
|
method = "{{getLoadBalancerMethod $backend}}"
|
||||||
sticky = {{getSticky $backend}}
|
{{if hasStickinessLabel $backend}}
|
||||||
|
[Backends."{{$backendName}}".LoadBalancer.Stickiness]
|
||||||
|
cookieName = {{getStickinessCookieName $backend}}
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if hasMaxConnLabels $backend}}
|
{{if hasMaxConnLabels $backend}}
|
||||||
|
|
|
@ -2,58 +2,35 @@ package types
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
|
// Traefik labels
|
||||||
const (
|
const (
|
||||||
// LabelPrefix Traefik label
|
|
||||||
LabelPrefix = "traefik."
|
LabelPrefix = "traefik."
|
||||||
// LabelDomain Traefik label
|
|
||||||
LabelDomain = LabelPrefix + "domain"
|
LabelDomain = LabelPrefix + "domain"
|
||||||
// LabelEnable Traefik label
|
|
||||||
LabelEnable = LabelPrefix + "enable"
|
LabelEnable = LabelPrefix + "enable"
|
||||||
// LabelPort Traefik label
|
|
||||||
LabelPort = LabelPrefix + "port"
|
LabelPort = LabelPrefix + "port"
|
||||||
// LabelPortIndex Traefik label
|
|
||||||
LabelPortIndex = LabelPrefix + "portIndex"
|
LabelPortIndex = LabelPrefix + "portIndex"
|
||||||
// LabelProtocol Traefik label
|
|
||||||
LabelProtocol = LabelPrefix + "protocol"
|
LabelProtocol = LabelPrefix + "protocol"
|
||||||
// LabelTags Traefik label
|
|
||||||
LabelTags = LabelPrefix + "tags"
|
LabelTags = LabelPrefix + "tags"
|
||||||
// LabelWeight Traefik label
|
|
||||||
LabelWeight = LabelPrefix + "weight"
|
LabelWeight = LabelPrefix + "weight"
|
||||||
// LabelFrontendAuthBasic Traefik label
|
|
||||||
LabelFrontendAuthBasic = LabelPrefix + "frontend.auth.basic"
|
LabelFrontendAuthBasic = LabelPrefix + "frontend.auth.basic"
|
||||||
// LabelFrontendEntryPoints Traefik label
|
|
||||||
LabelFrontendEntryPoints = LabelPrefix + "frontend.entryPoints"
|
LabelFrontendEntryPoints = LabelPrefix + "frontend.entryPoints"
|
||||||
// LabelFrontendPassHostHeader Traefik label
|
|
||||||
LabelFrontendPassHostHeader = LabelPrefix + "frontend.passHostHeader"
|
LabelFrontendPassHostHeader = LabelPrefix + "frontend.passHostHeader"
|
||||||
// LabelFrontendPriority Traefik label
|
|
||||||
LabelFrontendPriority = LabelPrefix + "frontend.priority"
|
LabelFrontendPriority = LabelPrefix + "frontend.priority"
|
||||||
// LabelFrontendRule Traefik label
|
|
||||||
LabelFrontendRule = LabelPrefix + "frontend.rule"
|
LabelFrontendRule = LabelPrefix + "frontend.rule"
|
||||||
// LabelFrontendRuleType Traefik label
|
|
||||||
LabelFrontendRuleType = LabelPrefix + "frontend.rule.type"
|
LabelFrontendRuleType = LabelPrefix + "frontend.rule.type"
|
||||||
// LabelTraefikFrontendValue Traefik label
|
|
||||||
LabelTraefikFrontendValue = LabelPrefix + "frontend.value"
|
LabelTraefikFrontendValue = LabelPrefix + "frontend.value"
|
||||||
// LabelTraefikFrontendWhitelistSourceRange Traefik label
|
|
||||||
LabelTraefikFrontendWhitelistSourceRange = LabelPrefix + "frontend.whitelistSourceRange"
|
LabelTraefikFrontendWhitelistSourceRange = LabelPrefix + "frontend.whitelistSourceRange"
|
||||||
// LabelBackend Traefik label
|
|
||||||
LabelBackend = LabelPrefix + "backend"
|
LabelBackend = LabelPrefix + "backend"
|
||||||
// LabelBackendID Traefik label
|
|
||||||
LabelBackendID = LabelPrefix + "backend.id"
|
LabelBackendID = LabelPrefix + "backend.id"
|
||||||
// LabelTraefikBackendCircuitbreaker Traefik label
|
|
||||||
LabelTraefikBackendCircuitbreaker = LabelPrefix + "backend.circuitbreaker"
|
LabelTraefikBackendCircuitbreaker = LabelPrefix + "backend.circuitbreaker"
|
||||||
// LabelBackendCircuitbreakerExpression Traefik label
|
|
||||||
LabelBackendCircuitbreakerExpression = LabelPrefix + "backend.circuitbreaker.expression"
|
LabelBackendCircuitbreakerExpression = LabelPrefix + "backend.circuitbreaker.expression"
|
||||||
// LabelBackendHealthcheckPath Traefik label
|
|
||||||
LabelBackendHealthcheckPath = LabelPrefix + "backend.healthcheck.path"
|
LabelBackendHealthcheckPath = LabelPrefix + "backend.healthcheck.path"
|
||||||
// LabelBackendHealthcheckInterval Traefik label
|
|
||||||
LabelBackendHealthcheckInterval = LabelPrefix + "backend.healthcheck.interval"
|
LabelBackendHealthcheckInterval = LabelPrefix + "backend.healthcheck.interval"
|
||||||
// LabelBackendLoadbalancerMethod Traefik label
|
|
||||||
LabelBackendLoadbalancerMethod = LabelPrefix + "backend.loadbalancer.method"
|
LabelBackendLoadbalancerMethod = LabelPrefix + "backend.loadbalancer.method"
|
||||||
// LabelBackendLoadbalancerSticky Traefik label
|
|
||||||
LabelBackendLoadbalancerSticky = LabelPrefix + "backend.loadbalancer.sticky"
|
LabelBackendLoadbalancerSticky = LabelPrefix + "backend.loadbalancer.sticky"
|
||||||
// LabelBackendMaxconnAmount Traefik label
|
LabelBackendLoadbalancerStickiness = LabelPrefix + "backend.loadbalancer.stickiness"
|
||||||
|
LabelBackendLoadbalancerStickinessCookieName = LabelPrefix + "backend.loadbalancer.stickiness.cookieName"
|
||||||
LabelBackendMaxconnAmount = LabelPrefix + "backend.maxconn.amount"
|
LabelBackendMaxconnAmount = LabelPrefix + "backend.maxconn.amount"
|
||||||
// LabelBackendMaxconnExtractorfunc Traefik label
|
|
||||||
LabelBackendMaxconnExtractorfunc = LabelPrefix + "backend.maxconn.extractorfunc"
|
LabelBackendMaxconnExtractorfunc = LabelPrefix + "backend.maxconn.extractorfunc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,13 @@ type MaxConn struct {
|
||||||
// LoadBalancer holds load balancing configuration.
|
// LoadBalancer holds load balancing configuration.
|
||||||
type LoadBalancer struct {
|
type LoadBalancer struct {
|
||||||
Method string `json:"method,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
Sticky bool `json:"sticky,omitempty"`
|
Sticky bool `json:"sticky,omitempty"` // Deprecated: use Stickiness instead
|
||||||
|
Stickiness *Stickiness `json:"stickiness,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stickiness holds sticky session configuration.
|
||||||
|
type Stickiness struct {
|
||||||
|
CookieName string `json:"cookieName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CircuitBreaker holds circuit breaker configuration.
|
// CircuitBreaker holds circuit breaker configuration.
|
||||||
|
|
Loading…
Reference in a new issue