diff --git a/provider/rancher/api.go b/provider/rancher/api.go index dff55a361..728e9d88c 100644 --- a/provider/rancher/api.go +++ b/provider/rancher/api.go @@ -78,7 +78,7 @@ func (p *Provider) apiProvide(configurationChan chan<- types.ConfigMessage, pool var rancherData = parseAPISourcedRancherData(stacks, services, container) - configuration := p.loadRancherConfig(rancherData) + configuration := p.buildConfiguration(rancherData) configurationChan <- types.ConfigMessage{ ProviderName: "rancher", Configuration: configuration, @@ -99,7 +99,7 @@ func (p *Provider) apiProvide(configurationChan chan<- types.ConfigMessage, pool rancherData := parseAPISourcedRancherData(stacks, services, container) - configuration := p.loadRancherConfig(rancherData) + configuration := p.buildConfiguration(rancherData) if configuration != nil { configurationChan <- types.ConfigMessage{ ProviderName: "rancher", @@ -131,7 +131,7 @@ func (p *Provider) apiProvide(configurationChan chan<- types.ConfigMessage, pool func listRancherStacks(client *rancher.RancherClient) []*rancher.Stack { - var stackList = []*rancher.Stack{} + var stackList []*rancher.Stack stacks, err := client.Stack.List(withoutPagination) @@ -148,7 +148,7 @@ func listRancherStacks(client *rancher.RancherClient) []*rancher.Stack { func listRancherServices(client *rancher.RancherClient) []*rancher.Service { - var servicesList = []*rancher.Service{} + var servicesList []*rancher.Service services, err := client.Service.List(withoutPagination) @@ -165,7 +165,7 @@ func listRancherServices(client *rancher.RancherClient) []*rancher.Service { func listRancherContainer(client *rancher.RancherClient) []*rancher.Container { - containerList := []*rancher.Container{} + var containerList []*rancher.Container container, err := client.Container.List(withoutPagination) @@ -205,7 +205,7 @@ func parseAPISourcedRancherData(stacks []*rancher.Stack, services []*rancher.Ser continue } - rancherData := rancherData{ + rData := rancherData{ Name: service.Name + "/" + stack.Name, Health: service.HealthState, State: service.State, @@ -217,7 +217,7 @@ func parseAPISourcedRancherData(stacks []*rancher.Stack, services []*rancher.Ser log.Warnf("Rancher Service Labels are missing. Stack: %s, service: %s", stack.Name, service.Name) } else { for key, value := range service.LaunchConfig.Labels { - rancherData.Labels[key] = value.(string) + rData.Labels[key] = value.(string) } } @@ -235,14 +235,14 @@ func parseAPISourcedRancherData(stacks []*rancher.Stack, services []*rancher.Ser } if len(endpoints) > 0 { - rancherData.Containers = append(rancherData.Containers, endpoints[0].IpAddress) + rData.Containers = append(rData.Containers, endpoints[0].IpAddress) } } else { - rancherData.Containers = append(rancherData.Containers, container.PrimaryIpAddress) + rData.Containers = append(rData.Containers, container.PrimaryIpAddress) } } } - rancherDataList = append(rancherDataList, rancherData) + rancherDataList = append(rancherDataList, rData) } } diff --git a/provider/rancher/config.go b/provider/rancher/config.go new file mode 100644 index 000000000..1b88e1a4c --- /dev/null +++ b/provider/rancher/config.go @@ -0,0 +1,170 @@ +package rancher + +import ( + "math" + "strings" + "text/template" + + "github.com/BurntSushi/ty/fun" + "github.com/containous/traefik/log" + "github.com/containous/traefik/provider" + "github.com/containous/traefik/provider/label" + "github.com/containous/traefik/types" +) + +func (p *Provider) buildConfiguration(services []rancherData) *types.Configuration { + + var RancherFuncMap = template.FuncMap{ + "getPort": getFuncString(label.TraefikPort, ""), + "getBackend": getBackend, + "getWeight": getFuncString(label.TraefikWeight, label.DefaultWeight), + "getDomain": getFuncString(label.TraefikDomain, p.Domain), + "getProtocol": getFuncString(label.TraefikProtocol, label.DefaultProtocol), + "getPassHostHeader": getFuncString(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), + "getPriority": getFuncString(label.TraefikFrontendPriority, label.DefaultFrontendPriority), + "getEntryPoints": getFuncSliceString(label.TraefikFrontendEntryPoints), + "getBasicAuth": getFuncSliceString(label.TraefikFrontendAuthBasic), + "getFrontendRule": p.getFrontendRule, + "hasCircuitBreakerLabel": hasFunc(label.TraefikBackendCircuitBreakerExpression), + "getCircuitBreakerExpression": getFuncString(label.TraefikBackendCircuitBreakerExpression, label.DefaultCircuitBreakerExpression), + "hasLoadBalancerLabel": hasLoadBalancerLabel, // OK + "getLoadBalancerMethod": getFuncString(label.TraefikFrontendRedirect, label.DefaultBackendLoadBalancerMethod), + "hasMaxConnLabels": hasMaxConnLabels, // OK + "getMaxConnAmount": getFuncInt64(label.TraefikBackendMaxConnAmount, math.MaxInt64), + "getMaxConnExtractorFunc": getFuncString(label.TraefikBackendMaxConnExtractorFunc, label.DefaultBackendMaxconnExtractorFunc), + "getSticky": getSticky, // deprecated + "hasStickinessLabel": hasFunc(label.TraefikBackendLoadBalancerStickiness), + "getStickinessCookieName": getFuncString(label.TraefikBackendLoadBalancerStickinessCookieName, label.DefaultBackendLoadbalancerStickinessCookieName), + "getRedirect": getFuncString(label.TraefikFrontendRedirect, label.DefaultFrontendRedirect), + } + + // filter services + filteredServices := fun.Filter(p.serviceFilter, services).([]rancherData) + + frontends := map[string]rancherData{} + backends := map[string]rancherData{} + + for _, service := range filteredServices { + frontendName := p.getFrontendName(service) + frontends[frontendName] = service + backendName := getBackend(service) + backends[backendName] = service + } + + templateObjects := struct { + Frontends map[string]rancherData + Backends map[string]rancherData + Domain string + }{ + frontends, + backends, + p.Domain, + } + + configuration, err := p.GetConfiguration("templates/rancher.tmpl", RancherFuncMap, templateObjects) + if err != nil { + log.Error(err) + } + + return configuration +} + +func (p *Provider) serviceFilter(service rancherData) bool { + + if service.Labels[label.TraefikPort] == "" { + log.Debugf("Filtering service %s without traefik.port label", service.Name) + return false + } + + if !label.IsEnabled(service.Labels, p.ExposedByDefault) { + log.Debugf("Filtering disabled service %s", service.Name) + return false + } + + constraintTags := label.GetSliceStringValue(service.Labels, label.TraefikTags) + if ok, failingConstraint := p.MatchConstraints(constraintTags); !ok { + if failingConstraint != nil { + log.Debugf("Filtering service %s with constraint %s", service.Name, failingConstraint.String()) + } + return false + } + + // Only filter services by Health (HealthState) and State if EnableServiceHealthFilter is true + if p.EnableServiceHealthFilter { + + if service.Health != "" && service.Health != healthy && service.Health != updatingHealthy { + log.Debugf("Filtering service %s with healthState of %s", service.Name, service.Health) + return false + } + + if service.State != "" && service.State != active && service.State != updatingActive && service.State != upgraded { + log.Debugf("Filtering service %s with state of %s", service.Name, service.State) + return false + } + } + + return true +} + +func (p *Provider) getFrontendRule(service rancherData) string { + defaultRule := "Host:" + strings.ToLower(strings.Replace(service.Name, "/", ".", -1)) + "." + p.Domain + return label.GetStringValue(service.Labels, label.TraefikFrontendRule, defaultRule) +} + +func (p *Provider) getFrontendName(service rancherData) string { + return provider.Normalize(p.getFrontendRule(service)) +} + +// TODO: Deprecated +// Deprecated replaced by Stickiness +func getSticky(service rancherData) string { + if label.Has(service.Labels, label.TraefikBackendLoadBalancerSticky) { + log.Warnf("Deprecated configuration found: %s. Please use %s.", label.TraefikBackendLoadBalancerSticky, label.TraefikBackendLoadBalancerStickiness) + } + return label.GetStringValue(service.Labels, label.TraefikBackendLoadBalancerSticky, "false") +} + +func hasLoadBalancerLabel(service rancherData) bool { + method := label.Has(service.Labels, label.TraefikBackendLoadBalancerMethod) + sticky := label.Has(service.Labels, label.TraefikBackendLoadBalancerSticky) + stickiness := label.Has(service.Labels, label.TraefikBackendLoadBalancerStickiness) + cookieName := label.Has(service.Labels, label.TraefikBackendLoadBalancerStickinessCookieName) + return method || sticky || stickiness || cookieName +} + +func hasMaxConnLabels(service rancherData) bool { + mca := label.Has(service.Labels, label.TraefikBackendMaxConnAmount) + mcef := label.Has(service.Labels, label.TraefikBackendMaxConnExtractorFunc) + return mca && mcef +} + +func getBackend(service rancherData) string { + backend := label.GetStringValue(service.Labels, label.TraefikBackend, service.Name) + return provider.Normalize(backend) +} + +// Label functions + +func getFuncString(labelName string, defaultValue string) func(service rancherData) string { + return func(service rancherData) string { + return label.GetStringValue(service.Labels, labelName, defaultValue) + } +} + +func getFuncInt64(labelName string, defaultValue int64) func(service rancherData) int64 { + return func(service rancherData) int64 { + return label.GetInt64Value(service.Labels, labelName, defaultValue) + } +} + +func getFuncSliceString(labelName string) func(service rancherData) []string { + return func(service rancherData) []string { + return label.GetSliceStringValue(service.Labels, labelName) + } +} + +func hasFunc(labelName string) func(service rancherData) bool { + return func(service rancherData) bool { + return label.Has(service.Labels, labelName) + } +} diff --git a/provider/rancher/rancher_test.go b/provider/rancher/config_test.go similarity index 50% rename from provider/rancher/rancher_test.go rename to provider/rancher/config_test.go index 60f2eab12..8aa2c70c5 100644 --- a/provider/rancher/rancher_test.go +++ b/provider/rancher/config_test.go @@ -1,9 +1,9 @@ package rancher import ( - "strings" "testing" + "github.com/containous/traefik/provider/label" "github.com/containous/traefik/types" "github.com/stretchr/testify/assert" ) @@ -26,7 +26,7 @@ func TestProviderServiceFilter(t *testing.T) { desc: "missing Port labels, don't respect constraint", service: rancherData{ Labels: map[string]string{ - types.LabelEnable: "true", + label.TraefikEnable: "true", }, Health: "healthy", State: "active", @@ -37,8 +37,8 @@ func TestProviderServiceFilter(t *testing.T) { desc: "don't respect constraint", service: rancherData{ Labels: map[string]string{ - types.LabelPort: "80", - types.LabelEnable: "false", + label.TraefikPort: "80", + label.TraefikEnable: "false", }, Health: "healthy", State: "active", @@ -49,9 +49,9 @@ func TestProviderServiceFilter(t *testing.T) { desc: "unhealthy", service: rancherData{ Labels: map[string]string{ - types.LabelTags: "cheese", - types.LabelPort: "80", - types.LabelEnable: "true", + label.TraefikTags: "cheese", + label.TraefikPort: "80", + label.TraefikEnable: "true", }, Health: "unhealthy", State: "active", @@ -62,9 +62,9 @@ func TestProviderServiceFilter(t *testing.T) { desc: "inactive", service: rancherData{ Labels: map[string]string{ - types.LabelTags: "not-cheesy", - types.LabelPort: "80", - types.LabelEnable: "true", + label.TraefikTags: "not-cheesy", + label.TraefikPort: "80", + label.TraefikEnable: "true", }, Health: "healthy", State: "inactive", @@ -75,9 +75,9 @@ func TestProviderServiceFilter(t *testing.T) { desc: "healthy & active, tag: cheese", service: rancherData{ Labels: map[string]string{ - types.LabelTags: "cheese", - types.LabelPort: "80", - types.LabelEnable: "true", + label.TraefikTags: "cheese", + label.TraefikPort: "80", + label.TraefikEnable: "true", }, Health: "healthy", State: "active", @@ -88,9 +88,9 @@ func TestProviderServiceFilter(t *testing.T) { desc: "healthy & active, tag: chose", service: rancherData{ Labels: map[string]string{ - types.LabelTags: "chose", - types.LabelPort: "80", - types.LabelEnable: "true", + label.TraefikTags: "chose", + label.TraefikPort: "80", + label.TraefikEnable: "true", }, Health: "healthy", State: "active", @@ -101,9 +101,9 @@ func TestProviderServiceFilter(t *testing.T) { desc: "healthy & upgraded", service: rancherData{ Labels: map[string]string{ - types.LabelTags: "cheeeeese", - types.LabelPort: "80", - types.LabelEnable: "true", + label.TraefikTags: "cheeeeese", + label.TraefikPort: "80", + label.TraefikEnable: "true", }, Health: "healthy", State: "upgraded", @@ -187,7 +187,7 @@ func TestProviderGetFrontendName(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelFrontendRule: "Headers:User-Agent,bat/0.1.0", + label.TraefikFrontendRule: "Headers:User-Agent,bat/0.1.0", }, }, expected: "Headers-User-Agent-bat-0-1-0", @@ -197,7 +197,7 @@ func TestProviderGetFrontendName(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelFrontendRule: "Host:foo.bar", + label.TraefikFrontendRule: "Host:foo.bar", }, }, expected: "Host-foo-bar", @@ -207,7 +207,7 @@ func TestProviderGetFrontendName(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelFrontendRule: "Path:/test", + label.TraefikFrontendRule: "Path:/test", }, }, expected: "Path-test", @@ -217,7 +217,7 @@ func TestProviderGetFrontendName(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelFrontendRule: "PathPrefix:/test2", + label.TraefikFrontendRule: "PathPrefix:/test2", }, }, expected: "PathPrefix-test2", @@ -262,7 +262,7 @@ func TestProviderGetFrontendRule(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelFrontendRule: "Host:foo.bar.com", + label.TraefikFrontendRule: "Host:foo.bar.com", }, }, expected: "Host:foo.bar.com", @@ -272,7 +272,7 @@ func TestProviderGetFrontendRule(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelFrontendRule: "Path:/test", + label.TraefikFrontendRule: "Path:/test", }, }, expected: "Path:/test", @@ -282,7 +282,7 @@ func TestProviderGetFrontendRule(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelFrontendRule: "PathPrefix:/test2", + label.TraefikFrontendRule: "PathPrefix:/test2", }, }, expected: "PathPrefix:/test2", @@ -300,9 +300,7 @@ func TestProviderGetFrontendRule(t *testing.T) { } } -func TestProviderGetBackend(t *testing.T) { - provider := &Provider{Domain: "rancher.localhost"} - +func TestGetBackend(t *testing.T) { testCases := []struct { desc string service rancherData @@ -320,7 +318,7 @@ func TestProviderGetBackend(t *testing.T) { service: rancherData{ Name: "test-service", Labels: map[string]string{ - types.LabelBackend: "foobar", + label.TraefikBackend: "foobar", }, }, @@ -333,283 +331,12 @@ func TestProviderGetBackend(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - actual := provider.getBackend(test.service) + actual := getBackend(test.service) assert.Equal(t, test.expected, actual) }) } } -func TestProviderGetWeight(t *testing.T) { - provider := &Provider{Domain: "rancher.localhost"} - - testCases := []struct { - desc string - service rancherData - expected string - }{ - { - desc: "without label", - service: rancherData{ - Name: "test-service", - }, - expected: "0", - }, - { - desc: "with label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelWeight: "5", - }, - }, - expected: "5", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := provider.getWeight(test.service) - assert.Equal(t, test.expected, actual) - }) - } -} - -func TestProviderGetPort(t *testing.T) { - provider := &Provider{Domain: "rancher.localhost"} - - testCases := []struct { - desc string - service rancherData - expected string - }{ - { - desc: "without label", - service: rancherData{ - Name: "test-service", - }, - expected: "", - }, - { - desc: "with label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelPort: "1337", - }, - }, - expected: "1337", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := provider.getPort(test.service) - assert.Equal(t, test.expected, actual) - }) - } -} - -func TestProviderGetDomain(t *testing.T) { - provider := &Provider{Domain: "rancher.localhost"} - - testCases := []struct { - desc string - service rancherData - expected string - }{ - { - desc: "without label", - service: rancherData{ - Name: "test-service", - }, - expected: "rancher.localhost", - }, - { - desc: "with label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelDomain: "foo.bar", - }, - }, - expected: "foo.bar", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := provider.getDomain(test.service) - assert.Equal(t, test.expected, actual) - }) - } -} - -func TestProviderGetProtocol(t *testing.T) { - provider := &Provider{Domain: "rancher.localhost"} - - testCases := []struct { - desc string - service rancherData - expected string - }{ - { - desc: "without label", - service: rancherData{ - Name: "test-service", - }, - expected: "http", - }, - { - desc: "with label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelProtocol: "https", - }, - }, - expected: "https", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := provider.getProtocol(test.service) - assert.Equal(t, test.expected, actual) - }) - } -} - -func TestProviderGetPassHostHeader(t *testing.T) { - provider := &Provider{Domain: "rancher.localhost"} - - testCases := []struct { - desc string - service rancherData - expected string - }{ - { - desc: "without label", - service: rancherData{ - Name: "test-service", - }, - expected: "true", - }, - { - desc: "with label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelFrontendPassHostHeader: "false", - }, - }, - expected: "false", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := provider.getPassHostHeader(test.service) - assert.Equal(t, test.expected, actual) - }) - } -} - -func TestProviderGetRedirect(t *testing.T) { - provider := &Provider{Domain: "rancher.localhost"} - - testCases := []struct { - desc string - service rancherData - expected string - }{ - { - desc: "without label", - service: rancherData{ - Name: "test-service", - }, - expected: "", - }, - { - desc: "with label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelFrontendRedirect: "https", - }, - }, - expected: "https", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := provider.getRedirect(test.service) - assert.Equal(t, test.expected, actual) - }) - } -} - -func TestProviderGetLabel(t *testing.T) { - testCases := []struct { - desc string - service rancherData - expected string - }{ - { - desc: "without label", - service: rancherData{ - Name: "test-service", - }, - expected: "label not found", - }, - { - desc: "with label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - "foo": "bar", - }, - }, - expected: "", - }, - } - - for _, test := range testCases { - test := test - t.Run("", func(t *testing.T) { - t.Parallel() - - label, err := getServiceLabel(test.service, "foo") - - if test.expected != "" { - if err == nil || !strings.Contains(err.Error(), test.expected) { - t.Fatalf("expected an error with %q, got %v", test.expected, err) - } - } else { - assert.Equal(t, "bar", label) - } - }) - } -} - func TestProviderLoadRancherConfig(t *testing.T) { provider := &Provider{ Domain: "rancher.localhost", @@ -634,9 +361,9 @@ func TestProviderLoadRancherConfig(t *testing.T) { { Name: "test/service", Labels: map[string]string{ - types.LabelPort: "80", - types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", - types.LabelFrontendRedirect: "https", + label.TraefikPort: "80", + label.TraefikFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", + label.TraefikFrontendRedirect: "https", }, Health: "healthy", Containers: []string{"127.0.0.1"}, @@ -677,58 +404,10 @@ func TestProviderLoadRancherConfig(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - actualConfig := provider.loadRancherConfig(test.services) + actualConfig := provider.buildConfiguration(test.services) assert.EqualValues(t, test.expectedBackends, actualConfig.Backends) assert.EqualValues(t, test.expectedFrontends, actualConfig.Frontends) }) } } - -func TestProviderHasStickinessLabel(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: "stickiness=true", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelBackendLoadbalancerStickiness: "true", - }, - }, - expected: true, - }, - { - desc: "stickiness=true", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - types.LabelBackendLoadbalancerStickiness: "false", - }, - }, - expected: false, - }, - } - - 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) - }) - } -} diff --git a/provider/rancher/metadata.go b/provider/rancher/metadata.go index 01ac2e48c..743c06d61 100644 --- a/provider/rancher/metadata.go +++ b/provider/rancher/metadata.go @@ -45,7 +45,7 @@ func (p *Provider) metadataProvide(configurationChan chan<- types.ConfigMessage, } rancherData := parseMetadataSourcedRancherData(stacks) - configuration := p.loadRancherConfig(rancherData) + configuration := p.buildConfiguration(rancherData) configurationChan <- types.ConfigMessage{ ProviderName: "rancher", Configuration: configuration, diff --git a/provider/rancher/rancher.go b/provider/rancher/rancher.go index 6c84b9379..cddb95da4 100644 --- a/provider/rancher/rancher.go +++ b/provider/rancher/rancher.go @@ -2,18 +2,26 @@ package rancher import ( "fmt" - "math" - "strconv" - "strings" - "text/template" - "github.com/BurntSushi/ty/fun" "github.com/containous/traefik/log" "github.com/containous/traefik/provider" "github.com/containous/traefik/safe" "github.com/containous/traefik/types" ) +const ( + // Health + healthy = "healthy" + updatingHealthy = "updating-healthy" + + // State + active = "active" + running = "running" + upgraded = "upgraded" + updatingActive = "updating-active" + updatingRunning = "updating-running" +) + var _ provider.Provider = (*Provider)(nil) // Provider holds configurations of the provider. @@ -40,180 +48,6 @@ func (r rancherData) String() string { return fmt.Sprintf("{name:%s, labels:%v, containers: %v, health: %s, state: %s}", r.Name, r.Labels, r.Containers, r.Health, r.State) } -// Frontend Labels -func (p *Provider) getPassHostHeader(service rancherData) string { - if passHostHeader, err := getServiceLabel(service, types.LabelFrontendPassHostHeader); err == nil { - return passHostHeader - } - return "true" -} - -func (p *Provider) getPriority(service rancherData) string { - if priority, err := getServiceLabel(service, types.LabelFrontendPriority); err == nil { - return priority - } - return "0" -} - -func (p *Provider) getEntryPoints(service rancherData) []string { - if entryPoints, err := getServiceLabel(service, types.LabelFrontendEntryPoints); err == nil { - return strings.Split(entryPoints, ",") - } - return []string{} -} - -func (p *Provider) getFrontendRule(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelFrontendRule); err == nil { - return label - } - return "Host:" + strings.ToLower(strings.Replace(service.Name, "/", ".", -1)) + "." + p.Domain -} - -func (p *Provider) getBasicAuth(service rancherData) []string { - if basicAuth, err := getServiceLabel(service, types.LabelFrontendAuthBasic); err == nil { - return strings.Split(basicAuth, ",") - } - return []string{} -} - -func (p *Provider) getRedirect(service rancherData) string { - if redirect, err := getServiceLabel(service, types.LabelFrontendRedirect); err == nil { - return redirect - } - return "" -} - -func (p *Provider) getFrontendName(service rancherData) string { - // Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78 - return provider.Normalize(p.getFrontendRule(service)) -} - -// Backend Labels -func (p *Provider) getLoadBalancerMethod(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelBackendLoadbalancerMethod); err == nil { - return label - } - return "wrr" -} - -func (p *Provider) hasLoadBalancerLabel(service rancherData) bool { - _, errMethod := getServiceLabel(service, types.LabelBackendLoadbalancerMethod) - _, errSticky := getServiceLabel(service, types.LabelBackendLoadbalancerSticky) - _, errStickiness := getServiceLabel(service, types.LabelBackendLoadbalancerStickiness) - _, errCookieName := getServiceLabel(service, types.LabelBackendLoadbalancerStickinessCookieName) - - return errMethod == nil || errSticky == nil || errStickiness == nil || errCookieName == nil -} - -func (p *Provider) hasCircuitBreakerLabel(service rancherData) bool { - if _, err := getServiceLabel(service, types.LabelBackendCircuitbreakerExpression); err != nil { - return false - } - return true -} - -func (p *Provider) getCircuitBreakerExpression(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelBackendCircuitbreakerExpression); err == nil { - return label - } - return "NetworkErrorRatio() > 1" -} - -func (p *Provider) getSticky(service rancherData) string { - if _, err := getServiceLabel(service, types.LabelBackendLoadbalancerSticky); err == nil { - log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness) - return "true" - } - return "false" -} - -func (p *Provider) hasStickinessLabel(service rancherData) bool { - labelStickiness, errStickiness := getServiceLabel(service, types.LabelBackendLoadbalancerStickiness) - - return errStickiness == nil && len(labelStickiness) > 0 && strings.EqualFold(strings.TrimSpace(labelStickiness), "true") -} - -func (p *Provider) getStickinessCookieName(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelBackendLoadbalancerStickinessCookieName); err == nil { - return label - } - return "" -} - -func (p *Provider) getBackend(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelBackend); err == nil { - return provider.Normalize(label) - } - return provider.Normalize(service.Name) -} - -// General Application Stuff -func (p *Provider) getPort(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelPort); err == nil { - return label - } - return "" -} - -func (p *Provider) getProtocol(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelProtocol); err == nil { - return label - } - return "http" -} - -func (p *Provider) getWeight(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelWeight); err == nil { - return label - } - return "0" -} - -func (p *Provider) getDomain(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelDomain); err == nil { - return label - } - return p.Domain -} - -func (p *Provider) hasMaxConnLabels(service rancherData) bool { - if _, err := getServiceLabel(service, types.LabelBackendMaxconnAmount); err != nil { - return false - } - if _, err := getServiceLabel(service, types.LabelBackendMaxconnExtractorfunc); err != nil { - return false - } - return true -} - -func (p *Provider) getMaxConnAmount(service rancherData) int64 { - if label, err := getServiceLabel(service, types.LabelBackendMaxconnAmount); err == nil { - i, errConv := strconv.ParseInt(label, 10, 64) - if errConv != nil { - log.Errorf("Unable to parse %s %s", types.LabelBackendMaxconnAmount, label) - return math.MaxInt64 - } - return i - } - return math.MaxInt64 -} - -func (p *Provider) getMaxConnExtractorFunc(service rancherData) string { - if label, err := getServiceLabel(service, types.LabelBackendMaxconnExtractorfunc); err == nil { - return label - } - return "request.host" -} - -func getServiceLabel(service rancherData, label string) (string, error) { - for key, value := range service.Labels { - if key == label { - return value, nil - } - } - return "", fmt.Errorf("label not found: %s", label) -} - // Provide allows either the Rancher API or metadata service provider to // seed configuration into Traefik using the given configuration channel. func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error { @@ -223,120 +57,16 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s return p.metadataProvide(configurationChan, pool, constraints) } -func (p *Provider) loadRancherConfig(services []rancherData) *types.Configuration { - - var RancherFuncMap = template.FuncMap{ - "getPort": p.getPort, - "getBackend": p.getBackend, - "getWeight": p.getWeight, - "getDomain": p.getDomain, - "getProtocol": p.getProtocol, - "getPassHostHeader": p.getPassHostHeader, - "getPriority": p.getPriority, - "getEntryPoints": p.getEntryPoints, - "getBasicAuth": p.getBasicAuth, - "getFrontendRule": p.getFrontendRule, - "hasCircuitBreakerLabel": p.hasCircuitBreakerLabel, - "getCircuitBreakerExpression": p.getCircuitBreakerExpression, - "hasLoadBalancerLabel": p.hasLoadBalancerLabel, - "getLoadBalancerMethod": p.getLoadBalancerMethod, - "hasMaxConnLabels": p.hasMaxConnLabels, - "getMaxConnAmount": p.getMaxConnAmount, - "getMaxConnExtractorFunc": p.getMaxConnExtractorFunc, - "getSticky": p.getSticky, - "hasStickinessLabel": p.hasStickinessLabel, - "getStickinessCookieName": p.getStickinessCookieName, - "getRedirect": p.getRedirect, - } - - // filter services - filteredServices := fun.Filter(p.serviceFilter, services).([]rancherData) - - frontends := map[string]rancherData{} - backends := map[string]rancherData{} - - for _, service := range filteredServices { - frontendName := p.getFrontendName(service) - frontends[frontendName] = service - backendName := p.getBackend(service) - backends[backendName] = service - } - - templateObjects := struct { - Frontends map[string]rancherData - Backends map[string]rancherData - Domain string - }{ - frontends, - backends, - p.Domain, - } - - configuration, err := p.GetConfiguration("templates/rancher.tmpl", RancherFuncMap, templateObjects) - if err != nil { - log.Error(err) - } - - return configuration - -} - func containerFilter(name, healthState, state string) bool { - if healthState != "" && healthState != "healthy" && healthState != "updating-healthy" { + if healthState != "" && healthState != healthy && healthState != updatingHealthy { log.Debugf("Filtering container %s with healthState of %s", name, healthState) return false } - if state != "" && state != "running" && state != "updating-running" { + if state != "" && state != running && state != updatingRunning { log.Debugf("Filtering container %s with state of %s", name, state) return false } return true } - -func (p *Provider) serviceFilter(service rancherData) bool { - - if service.Labels[types.LabelPort] == "" { - log.Debugf("Filtering service %s without traefik.port label", service.Name) - return false - } - - if !isServiceEnabled(service, p.ExposedByDefault) { - log.Debugf("Filtering disabled service %s", service.Name) - return false - } - - constraintTags := strings.Split(service.Labels[types.LabelTags], ",") - if ok, failingConstraint := p.MatchConstraints(constraintTags); !ok { - if failingConstraint != nil { - log.Debugf("Filtering service %s with constraint %s", service.Name, failingConstraint.String()) - } - return false - } - - // Only filter services by Health (HealthState) and State if EnableServiceHealthFilter is true - if p.EnableServiceHealthFilter { - - if service.Health != "" && service.Health != "healthy" && service.Health != "updating-healthy" { - log.Debugf("Filtering service %s with healthState of %s", service.Name, service.Health) - return false - } - - if service.State != "" && service.State != "active" && service.State != "updating-active" && service.State != "upgraded" { - log.Debugf("Filtering service %s with state of %s", service.Name, service.State) - return false - } - } - - return true -} - -func isServiceEnabled(service rancherData, exposedByDefault bool) bool { - - if service.Labels[types.LabelEnable] != "" { - var v = service.Labels[types.LabelEnable] - return exposedByDefault && v != "false" || v == "true" - } - return exposedByDefault -}