From 7e2ad827aaede7384356d8114bbae8ae6e7457e2 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Tue, 17 Apr 2018 20:58:24 +0200 Subject: [PATCH] fix: used 'traefik.domain' in frontend rule. --- provider/docker/config.go | 8 ++- .../docker/config_container_docker_test.go | 10 ++- .../docker/config_container_swarm_test.go | 7 +- provider/docker/deprecated_container.go | 8 ++- .../deprecated_container_docker_test.go | 10 ++- .../docker/deprecated_container_swarm_test.go | 7 +- provider/ecs/config.go | 4 +- provider/marathon/builder_test.go | 10 +++ provider/marathon/config.go | 9 ++- provider/marathon/config_test.go | 56 +++++++++------- provider/marathon/deprecated_config.go | 5 +- provider/marathon/deprecated_config_test.go | 64 +++++++++++++++++++ provider/mesos/config.go | 4 +- provider/mesos/config_test.go | 47 ++++++++++++++ provider/mesos/deprecated_config.go | 4 +- provider/rancher/config.go | 4 +- provider/rancher/config_test.go | 30 +++------ 17 files changed, 220 insertions(+), 67 deletions(-) diff --git a/provider/docker/config.go b/provider/docker/config.go index 030ac2cef..f2f88d4c8 100644 --- a/provider/docker/config.go +++ b/provider/docker/config.go @@ -182,12 +182,14 @@ func (p *Provider) getFrontendRule(container dockerData, segmentLabels map[strin return value } + domain := label.GetStringValue(segmentLabels, label.TraefikDomain, p.Domain) + if values, err := label.GetStringMultipleStrict(container.Labels, labelDockerComposeProject, labelDockerComposeService); err == nil { - return "Host:" + getSubDomain(values[labelDockerComposeService]+"."+values[labelDockerComposeProject]) + "." + p.Domain + return "Host:" + getSubDomain(values[labelDockerComposeService]+"."+values[labelDockerComposeProject]) + "." + domain } - if len(p.Domain) > 0 { - return "Host:" + getSubDomain(container.ServiceName) + "." + p.Domain + if len(domain) > 0 { + return "Host:" + getSubDomain(container.ServiceName) + "." + domain } return "" diff --git a/provider/docker/config_container_docker_test.go b/provider/docker/config_container_docker_test.go index f1ac3718e..90d910711 100644 --- a/provider/docker/config_container_docker_test.go +++ b/provider/docker/config_container_docker_test.go @@ -802,15 +802,19 @@ func TestDockerGetFrontendRule(t *testing.T) { expected: "Host:foo.docker.localhost", }, { - container: containerJSON(name("bar")), - expected: "Host:bar.docker.localhost", + container: containerJSON(name("foo"), + labels(map[string]string{ + label.TraefikDomain: "traefik.localhost", + })), + expected: "Host:foo.traefik.localhost", }, { container: containerJSON(labels(map[string]string{ label.TraefikFrontendRule: "Host:foo.bar", })), expected: "Host:foo.bar", - }, { + }, + { container: containerJSON(labels(map[string]string{ "com.docker.compose.project": "foo", "com.docker.compose.service": "bar", diff --git a/provider/docker/config_container_swarm_test.go b/provider/docker/config_container_swarm_test.go index 056f47549..ba2fed436 100644 --- a/provider/docker/config_container_swarm_test.go +++ b/provider/docker/config_container_swarm_test.go @@ -554,8 +554,11 @@ func TestSwarmGetFrontendRule(t *testing.T) { networks: map[string]*docker.NetworkResource{}, }, { - service: swarmService(serviceName("bar")), - expected: "Host:bar.docker.localhost", + service: swarmService(serviceName("foo"), + serviceLabels(map[string]string{ + label.TraefikDomain: "traefik.localhost", + })), + expected: "Host:foo.traefik.localhost", networks: map[string]*docker.NetworkResource{}, }, { diff --git a/provider/docker/deprecated_container.go b/provider/docker/deprecated_container.go index ce05082b2..a05af3d60 100644 --- a/provider/docker/deprecated_container.go +++ b/provider/docker/deprecated_container.go @@ -27,12 +27,14 @@ func (p Provider) getFrontendRuleV1(container dockerData) string { return value } + domain := label.GetStringValue(container.Labels, label.TraefikDomain, p.Domain) + if values, err := label.GetStringMultipleStrict(container.Labels, labelDockerComposeProject, labelDockerComposeService); err == nil { - return "Host:" + getSubDomain(values[labelDockerComposeService]+"."+values[labelDockerComposeProject]) + "." + p.Domain + return "Host:" + getSubDomain(values[labelDockerComposeService]+"."+values[labelDockerComposeProject]) + "." + domain } - if len(p.Domain) > 0 { - return "Host:" + getSubDomain(container.ServiceName) + "." + p.Domain + if len(domain) > 0 { + return "Host:" + getSubDomain(container.ServiceName) + "." + domain } return "" diff --git a/provider/docker/deprecated_container_docker_test.go b/provider/docker/deprecated_container_docker_test.go index db275f42d..67771473e 100644 --- a/provider/docker/deprecated_container_docker_test.go +++ b/provider/docker/deprecated_container_docker_test.go @@ -752,15 +752,19 @@ func TestDockerGetFrontendRuleV1(t *testing.T) { expected: "Host:foo.docker.localhost", }, { - container: containerJSON(name("bar")), - expected: "Host:bar.docker.localhost", + container: containerJSON(name("foo"), + labels(map[string]string{ + label.TraefikDomain: "traefik.localhost", + })), + expected: "Host:foo.traefik.localhost", }, { container: containerJSON(labels(map[string]string{ label.TraefikFrontendRule: "Host:foo.bar", })), expected: "Host:foo.bar", - }, { + }, + { container: containerJSON(labels(map[string]string{ "com.docker.compose.project": "foo", "com.docker.compose.service": "bar", diff --git a/provider/docker/deprecated_container_swarm_test.go b/provider/docker/deprecated_container_swarm_test.go index 151e4b10e..7803e91b0 100644 --- a/provider/docker/deprecated_container_swarm_test.go +++ b/provider/docker/deprecated_container_swarm_test.go @@ -527,8 +527,11 @@ func TestSwarmGetFrontendRuleV1(t *testing.T) { networks: map[string]*docker.NetworkResource{}, }, { - service: swarmService(serviceName("bar")), - expected: "Host:bar.docker.localhost", + service: swarmService(serviceName("foo"), + serviceLabels(map[string]string{ + label.TraefikDomain: "traefik.localhost", + })), + expected: "Host:foo.traefik.localhost", networks: map[string]*docker.NetworkResource{}, }, { diff --git a/provider/ecs/config.go b/provider/ecs/config.go index cdb1cef35..0fc8b8792 100644 --- a/provider/ecs/config.go +++ b/provider/ecs/config.go @@ -91,7 +91,9 @@ func (p *Provider) filterInstance(i ecsInstance) bool { } func (p *Provider) getFrontendRule(i ecsInstance) string { - defaultRule := "Host:" + strings.ToLower(strings.Replace(i.Name, "_", "-", -1)) + "." + p.Domain + domain := label.GetStringValue(i.TraefikLabels, label.TraefikDomain, p.Domain) + defaultRule := "Host:" + strings.ToLower(strings.Replace(i.Name, "_", "-", -1)) + "." + domain + return label.GetStringValue(i.TraefikLabels, label.TraefikFrontendRule, defaultRule) } diff --git a/provider/marathon/builder_test.go b/provider/marathon/builder_test.go index 45f6e5dbd..4fb77d8fb 100644 --- a/provider/marathon/builder_test.go +++ b/provider/marathon/builder_test.go @@ -10,6 +10,16 @@ import ( const testTaskName = "taskID" +func withAppData(app marathon.Application, segmentName string) appData { + segmentProperties := label.ExtractTraefikLabels(stringValueMap(app.Labels)) + return appData{ + Application: app, + SegmentLabels: segmentProperties[segmentName], + SegmentName: segmentName, + LinkedApps: nil, + } +} + // Functions related to building applications. func withApplications(apps ...marathon.Application) *marathon.Applications { diff --git a/provider/marathon/config.go b/provider/marathon/config.go index 128d26768..4b90de740 100644 --- a/provider/marathon/config.go +++ b/provider/marathon/config.go @@ -210,10 +210,12 @@ func (p *Provider) getFrontendRule(app appData) string { } } + domain := label.GetStringValue(app.SegmentLabels, label.TraefikDomain, p.Domain) + if len(app.SegmentName) > 0 { - return "Host:" + strings.ToLower(provider.Normalize(app.SegmentName)) + "." + p.getSubDomain(app.ID) + "." + p.Domain + return "Host:" + strings.ToLower(provider.Normalize(app.SegmentName)) + "." + p.getSubDomain(app.ID) + "." + domain } - return "Host:" + p.getSubDomain(app.ID) + "." + p.Domain + return "Host:" + p.getSubDomain(app.ID) + "." + domain } func getPort(task marathon.Task, app appData) string { @@ -345,6 +347,9 @@ func (p *Provider) getServer(app appData, task marathon.Task) (string, *types.Se func (p *Provider) getServerHost(task marathon.Task, app appData) (string, error) { if app.IPAddressPerTask == nil || p.ForceTaskHostname { + if len(task.Host) == 0 { + return "", fmt.Errorf("host is undefined for task %q app %q", task.ID, app.ID) + } return task.Host, nil } diff --git a/provider/marathon/config_test.go b/provider/marathon/config_test.go index 709dd13b8..4e6fdb9d6 100644 --- a/provider/marathon/config_test.go +++ b/provider/marathon/config_test.go @@ -1026,7 +1026,7 @@ func TestGetPort(t *testing.T) { desc string application marathon.Application task marathon.Task - serviceName string + segmentName string expected string }{ { @@ -1108,23 +1108,23 @@ func TestGetPort(t *testing.T) { }, { desc: "multiple task ports with service index available", - application: application(withLabel(label.Prefix+"http.portIndex", "0")), + application: application(withSegmentLabel(label.TraefikPortIndex, "0", "http")), task: task(taskPorts(80, 443)), - serviceName: "http", + segmentName: "http", expected: "80", }, { desc: "multiple task ports with service port available", - application: application(withLabel(label.Prefix+"https.port", "443")), + application: application(withSegmentLabel(label.TraefikPort, "443", "https")), task: task(taskPorts(80, 443)), - serviceName: "https", + segmentName: "https", expected: "443", }, { desc: "multiple task ports with services but default port available", - application: application(withLabel(label.Prefix+"http.weight", "100")), + application: application(withSegmentLabel(label.TraefikWeight, "100", "http")), task: task(taskPorts(80, 443)), - serviceName: "http", + segmentName: "http", expected: "80", }, } @@ -1134,7 +1134,7 @@ func TestGetPort(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - actual := getPortV1(test.task, test.application, test.serviceName) + actual := getPort(test.task, withAppData(test.application, test.segmentName)) assert.Equal(t, test.expected, actual) }) @@ -1145,7 +1145,7 @@ func TestGetFrontendRule(t *testing.T) { testCases := []struct { desc string application marathon.Application - serviceName string + segmentName string expected string marathonLBCompatibility bool }{ @@ -1155,6 +1155,15 @@ func TestGetFrontendRule(t *testing.T) { marathonLBCompatibility: true, expected: "Host:test.marathon.localhost", }, + { + desc: "label domain", + application: application( + appID("test"), + withLabel(label.TraefikDomain, "traefik.localhost"), + ), + marathonLBCompatibility: true, + expected: "Host:test.traefik.localhost", + }, { desc: "HAProxy vhost available and LB compat disabled", application: application( @@ -1172,7 +1181,6 @@ func TestGetFrontendRule(t *testing.T) { }, { desc: "frontend rule available", - application: application( withLabel(label.TraefikFrontendRule, "Host:foo.bar"), withLabel("HAPROXY_0_VHOST", "unused"), @@ -1181,9 +1189,9 @@ func TestGetFrontendRule(t *testing.T) { expected: "Host:foo.bar", }, { - desc: "service label existing", + desc: "segment label frontend rule", application: application(withSegmentLabel(label.TraefikFrontendRule, "Host:foo.bar", "app")), - serviceName: "app", + segmentName: "app", marathonLBCompatibility: true, expected: "Host:foo.bar", }, @@ -1198,7 +1206,7 @@ func TestGetFrontendRule(t *testing.T) { MarathonLBCompatibility: test.marathonLBCompatibility, } - actual := p.getFrontendRuleV1(test.application, test.serviceName) + actual := p.getFrontendRule(withAppData(test.application, test.segmentName)) assert.Equal(t, test.expected, actual) }) @@ -1209,7 +1217,7 @@ func TestGetBackendName(t *testing.T) { testCases := []struct { desc string application marathon.Application - serviceName string + segmentName string expected string }{ { @@ -1223,9 +1231,9 @@ func TestGetBackendName(t *testing.T) { expected: "backendbar", }, { - desc: "service label existing", + desc: "segment label existing", application: application(withSegmentLabel(label.TraefikBackend, "bar", "app")), - serviceName: "app", + segmentName: "app", expected: "backendbar", }, } @@ -1237,7 +1245,7 @@ func TestGetBackendName(t *testing.T) { p := &Provider{} - actual := p.getBackendNameV1(test.application, test.serviceName) + actual := p.getBackendName(withAppData(test.application, test.segmentName)) assert.Equal(t, test.expected, actual) }) @@ -1248,7 +1256,7 @@ func TestGetServers(t *testing.T) { testCases := []struct { desc string application marathon.Application - serviceName string + segmentName string expected map[string]types.Server }{ { @@ -1296,12 +1304,14 @@ func TestGetServers(t *testing.T) { for _, test := range testCases { test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() + if test.desc == "should return nil when all hosts are empty" { + t.Run(test.desc, func(t *testing.T) { + t.Parallel() - actual := p.getServersV1(test.application, test.serviceName) + actual := p.getServers(withAppData(test.application, test.segmentName)) - assert.Equal(t, test.expected, actual) - }) + assert.Equal(t, test.expected, actual) + }) + } } } diff --git a/provider/marathon/deprecated_config.go b/provider/marathon/deprecated_config.go index 2e5b0a3a0..5f4b50bca 100644 --- a/provider/marathon/deprecated_config.go +++ b/provider/marathon/deprecated_config.go @@ -138,10 +138,11 @@ func (p *Provider) getFrontendRuleV1(application marathon.Application, serviceNa } } + domain := label.GetStringValue(labels, label.SuffixDomain, p.Domain) if len(serviceName) > 0 { - return "Host:" + strings.ToLower(provider.Normalize(serviceName)) + "." + p.getSubDomain(application.ID) + "." + p.Domain + return "Host:" + strings.ToLower(provider.Normalize(serviceName)) + "." + p.getSubDomain(application.ID) + "." + domain } - return "Host:" + p.getSubDomain(application.ID) + "." + p.Domain + return "Host:" + p.getSubDomain(application.ID) + "." + domain } // Deprecated diff --git a/provider/marathon/deprecated_config_test.go b/provider/marathon/deprecated_config_test.go index d6328e3b9..3c5df44f6 100644 --- a/provider/marathon/deprecated_config_test.go +++ b/provider/marathon/deprecated_config_test.go @@ -760,3 +760,67 @@ func TestGetStickyV1(t *testing.T) { }) } } + +func TestGetServersV1(t *testing.T) { + testCases := []struct { + desc string + application marathon.Application + segmentName string + expected map[string]types.Server + }{ + { + desc: "should return nil when no task", + application: application(ipAddrPerTask(80)), + expected: nil, + }, + { + desc: "should return nil when all hosts are empty", + application: application( + withTasks( + task(ipAddresses("1.1.1.1"), withTaskID("A"), taskPorts(80)), + task(ipAddresses("1.1.1.2"), withTaskID("B"), taskPorts(80)), + task(ipAddresses("1.1.1.3"), withTaskID("C"), taskPorts(80))), + ), + expected: nil, + }, + { + desc: "with 3 tasks", + application: application( + ipAddrPerTask(80), + withTasks( + task(ipAddresses("1.1.1.1"), withTaskID("A"), taskPorts(80)), + task(ipAddresses("1.1.1.2"), withTaskID("B"), taskPorts(80)), + task(ipAddresses("1.1.1.3"), withTaskID("C"), taskPorts(80))), + ), + expected: map[string]types.Server{ + "server-A": { + URL: "http://1.1.1.1:80", + Weight: label.DefaultWeight, + }, + "server-B": { + URL: "http://1.1.1.2:80", + Weight: label.DefaultWeight, + }, + "server-C": { + URL: "http://1.1.1.3:80", + Weight: label.DefaultWeight, + }, + }, + }, + } + + p := &Provider{} + + for _, test := range testCases { + test := test + if test.desc == "should return nil when all hosts are empty" { + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + actual := p.getServersV1(test.application, test.segmentName) + + assert.Equal(t, test.expected, actual) + }) + } + } +} diff --git a/provider/mesos/config.go b/provider/mesos/config.go index 7f825e505..a5d874c5f 100644 --- a/provider/mesos/config.go +++ b/provider/mesos/config.go @@ -166,7 +166,9 @@ func (p *Provider) getFrontendRule(task taskData) string { if v := label.GetStringValue(task.TraefikLabels, label.TraefikFrontendRule, ""); len(v) > 0 { return v } - return "Host:" + strings.ToLower(strings.Replace(p.getSubDomain(task.DiscoveryInfo.Name), "_", "-", -1)) + "." + p.Domain + + domain := label.GetStringValue(task.TraefikLabels, label.TraefikDomain, p.Domain) + return "Host:" + strings.ToLower(strings.Replace(p.getSubDomain(task.DiscoveryInfo.Name), "_", "-", -1)) + "." + domain } func (p *Provider) getServers(tasks []taskData) map[string]types.Server { diff --git a/provider/mesos/config_test.go b/provider/mesos/config_test.go index 2fd96a0e4..c0492a89d 100644 --- a/provider/mesos/config_test.go +++ b/provider/mesos/config_test.go @@ -652,3 +652,50 @@ func TestGetServers(t *testing.T) { }) } } + +func TestGetFrontendRule(t *testing.T) { + p := Provider{ + Domain: "mesos.localhost", + } + + testCases := []struct { + desc string + mesosTask taskData + expected string + }{ + { + desc: "label missing", + mesosTask: aTaskData("test", + withInfo("foo"), + ), + expected: "Host:foo.mesos.localhost", + }, + { + desc: "label domain", + mesosTask: aTaskData("test", + withInfo("foo"), + withLabel(label.TraefikDomain, "traefik.localhost"), + ), + expected: "Host:foo.traefik.localhost", + }, + { + desc: "frontend rule available", + mesosTask: aTaskData("test", + withInfo("foo"), + withLabel(label.TraefikFrontendRule, "Host:foo.bar"), + ), + expected: "Host:foo.bar", + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + rule := p.getFrontendRule(test.mesosTask) + + assert.Equal(t, test.expected, rule) + }) + } +} diff --git a/provider/mesos/deprecated_config.go b/provider/mesos/deprecated_config.go index cbd18ee41..71c1fb2b6 100644 --- a/provider/mesos/deprecated_config.go +++ b/provider/mesos/deprecated_config.go @@ -196,7 +196,9 @@ func (p *Provider) getFrontendRuleV1(task state.Task) string { if v := getStringValueV1(task, label.TraefikFrontendRule, ""); len(v) > 0 { return v } - return "Host:" + strings.ToLower(strings.Replace(p.getSubDomain(task.DiscoveryInfo.Name), "_", "-", -1)) + "." + p.Domain + + domain := getStringValueV1(task, label.TraefikDomain, p.Domain) + return "Host:" + strings.ToLower(strings.Replace(p.getSubDomain(task.DiscoveryInfo.Name), "_", "-", -1)) + "." + domain } // Deprecated diff --git a/provider/rancher/config.go b/provider/rancher/config.go index 494637d10..a24c4c191 100644 --- a/provider/rancher/config.go +++ b/provider/rancher/config.go @@ -124,7 +124,9 @@ func (p *Provider) serviceFilter(service rancherData) bool { } func (p *Provider) getFrontendRule(serviceName string, labels map[string]string) string { - defaultRule := "Host:" + strings.ToLower(strings.Replace(serviceName, "/", ".", -1)) + "." + p.Domain + domain := label.GetStringValue(labels, label.TraefikDomain, p.Domain) + defaultRule := "Host:" + strings.ToLower(strings.Replace(serviceName, "/", ".", -1)) + "." + domain + return label.GetStringValue(labels, label.TraefikFrontendRule, defaultRule) } diff --git a/provider/rancher/config_test.go b/provider/rancher/config_test.go index 9be47c337..599ae8de0 100644 --- a/provider/rancher/config_test.go +++ b/provider/rancher/config_test.go @@ -722,6 +722,16 @@ func TestProviderGetFrontendRule(t *testing.T) { }, expected: "Host:foo.rancher.localhost", }, + { + desc: "with domain label", + service: rancherData{ + Name: "test-service", + Labels: map[string]string{ + label.TraefikDomain: "traefik.localhost", + }, + }, + expected: "Host:test-service.traefik.localhost", + }, { desc: "host with /", service: rancherData{ @@ -739,26 +749,6 @@ func TestProviderGetFrontendRule(t *testing.T) { }, expected: "Host:foo.bar.com", }, - { - desc: "with Path label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - label.TraefikFrontendRule: "Path:/test", - }, - }, - expected: "Path:/test", - }, - { - desc: "with PathPrefix label", - service: rancherData{ - Name: "test-service", - Labels: map[string]string{ - label.TraefikFrontendRule: "PathPrefix:/test2", - }, - }, - expected: "PathPrefix:/test2", - }, } for _, test := range testCases {