From 928675a8473955d1878775d6e2ece6ab6089d249 Mon Sep 17 00:00:00 2001 From: tuier Date: Tue, 20 Sep 2016 09:44:32 +0100 Subject: [PATCH 1/3] feat(constraints): Support constraint for Marathon provider --- provider/marathon.go | 25 +++++++++++++++++++++---- provider/marathon_test.go | 10 +++++++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/provider/marathon.go b/provider/marathon.go index 27982b5ce..afb9c105e 100644 --- a/provider/marathon.go +++ b/provider/marathon.go @@ -153,12 +153,12 @@ func (provider *Marathon) loadMarathonConfig() *types.Configuration { //filter tasks filteredTasks := fun.Filter(func(task marathon.Task) bool { - return taskFilter(task, applications, provider.ExposedByDefault) + return provider.taskFilter(task, applications, provider.ExposedByDefault) }, tasks.Tasks).([]marathon.Task) //filter apps filteredApps := fun.Filter(func(app marathon.Application) bool { - return applicationFilter(app, filteredTasks) + return provider.applicationFilter(app, filteredTasks) }, applications.Apps).([]marathon.Application) templateObjects := struct { @@ -178,7 +178,7 @@ func (provider *Marathon) loadMarathonConfig() *types.Configuration { return configuration } -func taskFilter(task marathon.Task, applications *marathon.Applications, exposedByDefaultFlag bool) bool { +func (provider *Marathon) taskFilter(task marathon.Task, applications *marathon.Applications, exposedByDefaultFlag bool) bool { if len(task.Ports) == 0 { log.Debug("Filtering marathon task without port %s", task.AppID) return false @@ -188,6 +188,15 @@ func taskFilter(task marathon.Task, applications *marathon.Applications, exposed log.Errorf("Unable to get marathon application from task %s", task.AppID) return false } + if label, err := provider.getLabel(application, "traefik.tags"); err == nil { + constraintTags := strings.Split(label, ",") + if ok, failingConstraint := provider.MatchConstraints(constraintTags); !ok { + if failingConstraint != nil { + log.Debugf("Application %v pruned by '%v' constraint", application.ID, failingConstraint.String()) + } + return false + } + } if !isApplicationEnabled(application, exposedByDefaultFlag) { log.Debugf("Filtering disabled marathon task %s", task.AppID) @@ -248,7 +257,15 @@ func taskFilter(task marathon.Task, applications *marathon.Applications, exposed return true } -func applicationFilter(app marathon.Application, filteredTasks []marathon.Task) bool { +func (provider *Marathon) applicationFilter(app marathon.Application, filteredTasks []marathon.Task) bool { + constraintTags := strings.Split((*app.Labels)["traefik.tags"], ",") + if ok, failingConstraint := provider.MatchConstraints(constraintTags); !ok { + if failingConstraint != nil { + log.Debugf("Application %v pruned by '%v' constraint", app.ID, failingConstraint.String()) + } + return false + } + return fun.Exists(func(task marathon.Task) bool { return task.AppID == app.ID }, filteredTasks) diff --git a/provider/marathon_test.go b/provider/marathon_test.go index 94e91701e..c8cc6808f 100644 --- a/provider/marathon_test.go +++ b/provider/marathon_test.go @@ -674,8 +674,9 @@ func TestMarathonTaskFilter(t *testing.T) { }, } + provider := &Marathon{} for _, c := range cases { - actual := taskFilter(c.task, c.applications, c.exposedByDefault) + actual := provider.taskFilter(c.task, c.applications, c.exposedByDefault) if actual != c.expected { t.Fatalf("expected %v, got %v", c.expected, actual) } @@ -689,7 +690,9 @@ func TestMarathonApplicationFilter(t *testing.T) { expected bool }{ { - application: marathon.Application{}, + application: marathon.Application{ + Labels: &map[string]string{}, + }, filteredTasks: []marathon.Task{}, expected: false, }, @@ -727,8 +730,9 @@ func TestMarathonApplicationFilter(t *testing.T) { }, } + provider := &Marathon{} for _, c := range cases { - actual := applicationFilter(c.application, c.filteredTasks) + actual := provider.applicationFilter(c.application, c.filteredTasks) if actual != c.expected { t.Fatalf("expected %v, got %v", c.expected, actual) } From cc0fdf15ef684b9b532f49c82b53b328286ef23d Mon Sep 17 00:00:00 2001 From: tuier Date: Wed, 21 Sep 2016 00:15:09 +0100 Subject: [PATCH 2/3] test for task and application constraint --- provider/marathon_test.go | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/provider/marathon_test.go b/provider/marathon_test.go index c8cc6808f..df7153d23 100644 --- a/provider/marathon_test.go +++ b/provider/marathon_test.go @@ -683,6 +683,105 @@ func TestMarathonTaskFilter(t *testing.T) { } } +func TestMarathonAppConstraints(t *testing.T) { + cases := []struct { + application marathon.Application + filteredTasks []marathon.Task + expected bool + }{ + { + application: marathon.Application{ + ID: "foo1", + Labels: &map[string]string{}, + }, + filteredTasks: []marathon.Task{ + { + AppID: "foo1", + }, + }, + expected: false, + }, + { + application: marathon.Application{ + ID: "foo", + Labels: &map[string]string{ + "traefik.tags": "valid", + }, + }, + filteredTasks: []marathon.Task{ + { + AppID: "foo", + }, + }, + expected: true, + }, + } + + provider := &Marathon{} + constraint, _ := types.NewConstraint("tag==valid") + provider.Constraints = []types.Constraint{*constraint} + for _, c := range cases { + actual := provider.applicationFilter(c.application, c.filteredTasks) + if actual != c.expected { + t.Fatalf("expected %v, got %v: %v", c.expected, actual, c.application) + } + } + +} +func TestMarathonTaskConstraints(t *testing.T) { + cases := []struct { + applications []marathon.Application + filteredTask marathon.Task + expected bool + }{ + { + applications: []marathon.Application{ + marathon.Application{ + ID: "bar1", + Labels: &map[string]string{}, + }, marathon.Application{ + ID: "foo1", + Labels: &map[string]string{ + "traefik.tags": "other", + }, + }, + }, + filteredTask: marathon.Task{ + AppID: "foo1", + Ports: []int{80}, + }, + expected: false, + }, + { + applications: []marathon.Application{ + marathon.Application{ + ID: "foo2", + Labels: &map[string]string{ + "traefik.tags": "valid", + }, + }, + }, + filteredTask: marathon.Task{ + AppID: "foo2", + Ports: []int{80}, + }, + expected: true, + }, + } + + provider := &Marathon{} + constraint, _ := types.NewConstraint("tag==valid") + provider.Constraints = []types.Constraint{*constraint} + for _, c := range cases { + apps := new(marathon.Applications) + apps.Apps = c.applications + actual := provider.taskFilter(c.filteredTask, apps, true) + if actual != c.expected { + t.Fatalf("expected %v, got %v: %v", c.expected, actual, c.filteredTask) + } + } +} + func TestMarathonApplicationFilter(t *testing.T) { cases := []struct { application marathon.Application From 361dc94002dc8fbe48878620deb9f31f6405f168 Mon Sep 17 00:00:00 2001 From: tuier Date: Wed, 21 Sep 2016 00:41:34 +0100 Subject: [PATCH 3/3] fmt --- provider/marathon_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/provider/marathon_test.go b/provider/marathon_test.go index df7153d23..cb4edea27 100644 --- a/provider/marathon_test.go +++ b/provider/marathon_test.go @@ -736,10 +736,10 @@ func TestMarathonTaskConstraints(t *testing.T) { }{ { applications: []marathon.Application{ - marathon.Application{ + { ID: "bar1", Labels: &map[string]string{}, - }, marathon.Application{ + }, { ID: "foo1", Labels: &map[string]string{ "traefik.tags": "other", @@ -754,7 +754,7 @@ func TestMarathonTaskConstraints(t *testing.T) { }, { applications: []marathon.Application{ - marathon.Application{ + { ID: "foo2", Labels: &map[string]string{ "traefik.tags": "valid",