diff --git a/docs/configuration/backends/ecs.md b/docs/configuration/backends/ecs.md index 15484a196..04a707a4b 100644 --- a/docs/configuration/backends/ecs.md +++ b/docs/configuration/backends/ecs.md @@ -78,17 +78,18 @@ SecretAccessKey = "123" Labels can be used on task containers to override default behaviour: -| Label | Description | -|----------------------------------------------|------------------------------------------------------------------------------------------| -| `traefik.protocol=https` | override the default `http` protocol | -| `traefik.weight=10` | assign this weight to the container | -| `traefik.enable=false` | disable this container in Træfik | -| `traefik.backend.loadbalancer.method=drr` | override the default `wrr` load balancer algorithm | -| `traefik.backend.loadbalancer.sticky=true` | enable backend sticky sessions | -| `traefik.frontend.rule=Host:test.traefik.io` | override the default frontend rule (Default: `Host:{containerName}.{domain}`). | -| `traefik.frontend.passHostHeader=true` | forward client `Host` header to the backend. | -| `traefik.frontend.priority=10` | override default frontend priority | -| `traefik.frontend.entryPoints=http,https` | assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. | +| Label | Description | +|---------------------------------------------------|------------------------------------------------------------------------------------------| +| `traefik.protocol=https` | override the default `http` protocol | +| `traefik.weight=10` | assign this weight to the container | +| `traefik.enable=false` | disable this container in Træfik | +| `traefik.backend.loadbalancer.method=drr` | override the default `wrr` load balancer algorithm | +| `traefik.backend.loadbalancer.sticky=true` | enable backend sticky sessions | +| `traefik.frontend.rule=Host:test.traefik.io` | override the default frontend rule (Default: `Host:{containerName}.{domain}`). | +| `traefik.frontend.passHostHeader=true` | forward client `Host` header to the backend. | +| `traefik.frontend.priority=10` | override default frontend priority | +| `traefik.frontend.entryPoints=http,https` | assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. | +| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` | If `AccessKeyID`/`SecretAccessKey` is not given credentials will be resolved in the following order: diff --git a/provider/ecs/ecs.go b/provider/ecs/ecs.go index b092ec8f9..e48ebe5bc 100644 --- a/provider/ecs/ecs.go +++ b/provider/ecs/ecs.go @@ -182,6 +182,7 @@ func (p *Provider) loadECSConfig(ctx context.Context, client *awsClient) (*types var ecsFuncMap = template.FuncMap{ "filterFrontends": p.filterFrontends, "getFrontendRule": p.getFrontendRule, + "getBasicAuth": p.getBasicAuth, "getLoadBalancerSticky": p.getLoadBalancerSticky, "getLoadBalancerMethod": p.getLoadBalancerMethod, } @@ -469,6 +470,14 @@ func (p *Provider) getFrontendRule(i ecsInstance) string { return "Host:" + strings.ToLower(strings.Replace(i.Name, "_", "-", -1)) + "." + p.Domain } +func (p *Provider) getBasicAuth(i ecsInstance) []string { + label := i.label(types.LabelFrontendAuthBasic) + if label != "" { + return strings.Split(label, ",") + } + return []string{} +} + func (p *Provider) getLoadBalancerSticky(instances []ecsInstance) string { if len(instances) > 0 { label := instances[0].label(types.LabelBackendLoadbalancerSticky) diff --git a/provider/ecs/ecs_test.go b/provider/ecs/ecs_test.go index 1264d3713..c3cd7bc82 100644 --- a/provider/ecs/ecs_test.go +++ b/provider/ecs/ecs_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ecs" "github.com/containous/traefik/types" + "github.com/stretchr/testify/assert" ) func makeEcsInstance(containerDef *ecs.ContainerDefinition) ecsInstance { @@ -74,10 +75,10 @@ func TestEcsProtocol(t *testing.T) { }, } - for i, c := range cases { - value := c.instanceInfo.Protocol() - if value != c.expected { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + for i, test := range cases { + value := test.instanceInfo.Protocol() + if value != test.expected { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -93,10 +94,10 @@ func TestEcsHost(t *testing.T) { }, } - for i, c := range cases { - value := c.instanceInfo.Host() - if value != c.expected { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + for i, test := range cases { + value := test.instanceInfo.Host() + if value != test.expected { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -112,10 +113,10 @@ func TestEcsPort(t *testing.T) { }, } - for i, c := range cases { - value := c.instanceInfo.Port() - if value != c.expected { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + for i, test := range cases { + value := test.instanceInfo.Port() + if value != test.expected { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -137,10 +138,10 @@ func TestEcsWeight(t *testing.T) { }, } - for i, c := range cases { - value := c.instanceInfo.Weight() - if value != c.expected { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + for i, test := range cases { + value := test.instanceInfo.Weight() + if value != test.expected { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -162,10 +163,10 @@ func TestEcsPassHostHeader(t *testing.T) { }, } - for i, c := range cases { - value := c.instanceInfo.PassHostHeader() - if value != c.expected { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + for i, test := range cases { + value := test.instanceInfo.PassHostHeader() + if value != test.expected { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -187,10 +188,10 @@ func TestEcsPriority(t *testing.T) { }, } - for i, c := range cases { - value := c.instanceInfo.Priority() - if value != c.expected { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + for i, test := range cases { + value := test.instanceInfo.Priority() + if value != test.expected { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -218,10 +219,10 @@ func TestEcsEntryPoints(t *testing.T) { }, } - for i, c := range cases { - value := c.instanceInfo.EntryPoints() - if !reflect.DeepEqual(value, c.expected) { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + for i, test := range cases { + value := test.instanceInfo.EntryPoints() + if !reflect.DeepEqual(value, test.expected) { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -299,13 +300,13 @@ func TestFilterInstance(t *testing.T) { }, } - for i, c := range cases { + for i, test := range cases { provider := &Provider{ - ExposedByDefault: c.exposedByDefault, + ExposedByDefault: test.exposedByDefault, } - value := provider.filterInstance(c.instanceInfo) - if value != c.expected { - t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i) + value := provider.filterInstance(test.instanceInfo) + if value != test.expected { + t.Fatalf("Should have been %v, got %v (case %d)", test.expected, value, i) } } } @@ -330,9 +331,9 @@ func TestTaskChunking(t *testing.T) { {1001, []int{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1}}, } - for _, c := range cases { + for _, test := range cases { var tasks []*string - for v := 0; v < c.count; v++ { + for v := 0; v < test.count; v++ { tasks = append(tasks, &testval) } @@ -343,8 +344,39 @@ func TestTaskChunking(t *testing.T) { outCount = append(outCount, len(el)) } - if !reflect.DeepEqual(outCount, c.expectedLengths) { - t.Errorf("Chunking %d elements, expected %#v, got %#v", c.count, c.expectedLengths, outCount) + if !reflect.DeepEqual(outCount, test.expectedLengths) { + t.Errorf("Chunking %d elements, expected %#v, got %#v", test.count, test.expectedLengths, outCount) } } } + +func TestEcsGetBasicAuth(t *testing.T) { + cases := []struct { + desc string + instance ecsInstance + expected []string + }{ + { + desc: "label missing", + instance: simpleEcsInstance(map[string]*string{}), + expected: []string{}, + }, + { + desc: "label existing", + instance: simpleEcsInstance(map[string]*string{ + types.LabelFrontendAuthBasic: aws.String("user:password"), + }), + expected: []string{"user:password"}, + }, + } + + for _, test := range cases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + provider := &Provider{} + actual := provider.getBasicAuth(test.instance) + assert.Equal(t, test.expected, actual) + }) + } +} diff --git a/templates/ecs.tmpl b/templates/ecs.tmpl index 99c758d24..36e9e29b4 100644 --- a/templates/ecs.tmpl +++ b/templates/ecs.tmpl @@ -18,6 +18,9 @@ priority = {{ .Priority }} entryPoints = [{{range .EntryPoints }} "{{.}}", + {{end}}] + basicAuth = [{{range getBasicAuth .}} + "{{.}}", {{end}}] [frontends.frontend-{{ $serviceName }}.routes.route-frontend-{{ $serviceName }}] rule = "{{getFrontendRule .}}"