Merge pull request #686 from tuier/marathon_constraints

feat(constraints): Supports constraints for Marathon provider
This commit is contained in:
Emile Vauge 2016-09-23 09:58:17 +02:00 committed by GitHub
commit 5d0f82ffbd
2 changed files with 127 additions and 7 deletions

View file

@ -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)

View file

@ -674,14 +674,114 @@ 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)
}
}
}
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{
{
ID: "bar1",
Labels: &map[string]string{},
}, {
ID: "foo1",
Labels: &map[string]string{
"traefik.tags": "other",
},
},
},
filteredTask: marathon.Task{
AppID: "foo1",
Ports: []int{80},
},
expected: false,
},
{
applications: []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
@ -689,7 +789,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 +829,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)
}