Make Traefik health checks label-configurable with Marathon.
For the two existing health check parameters (path and interval), we add support for Marathon labels. Changes in detail: - Extend the Marathon provider and template. - Refactor Server.loadConfig to reduce duplication. - Refactor the healthcheck package slightly to accommodate the changes and allow extending by future parameters. - Update documentation.
This commit is contained in:
parent
441d5442a1
commit
d57f83c31c
8 changed files with 371 additions and 45 deletions
|
@ -24,8 +24,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
labelPort = "traefik.port"
|
||||
labelPortIndex = "traefik.portIndex"
|
||||
labelPort = "traefik.port"
|
||||
labelPortIndex = "traefik.portIndex"
|
||||
labelBackendHealthCheckPath = "traefik.backend.healthcheck.path"
|
||||
labelBackendHealthCheckInterval = "traefik.backend.healthcheck.interval"
|
||||
)
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
@ -157,6 +159,9 @@ func (p *Provider) loadMarathonConfig() *types.Configuration {
|
|||
"getLoadBalancerMethod": p.getLoadBalancerMethod,
|
||||
"getCircuitBreakerExpression": p.getCircuitBreakerExpression,
|
||||
"getSticky": p.getSticky,
|
||||
"hasHealthCheckLabels": p.hasHealthCheckLabels,
|
||||
"getHealthCheckPath": p.getHealthCheckPath,
|
||||
"getHealthCheckInterval": p.getHealthCheckInterval,
|
||||
}
|
||||
|
||||
applications, err := p.marathonClient.Applications(nil)
|
||||
|
@ -461,6 +466,24 @@ func (p *Provider) getCircuitBreakerExpression(application marathon.Application)
|
|||
return "NetworkErrorRatio() > 1"
|
||||
}
|
||||
|
||||
func (p *Provider) hasHealthCheckLabels(application marathon.Application) bool {
|
||||
return p.getHealthCheckPath(application) != ""
|
||||
}
|
||||
|
||||
func (p *Provider) getHealthCheckPath(application marathon.Application) string {
|
||||
if label, ok := p.getLabel(application, labelBackendHealthCheckPath); ok {
|
||||
return label
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Provider) getHealthCheckInterval(application marathon.Application) string {
|
||||
if label, ok := p.getLabel(application, labelBackendHealthCheckInterval); ok {
|
||||
return label
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func processPorts(application marathon.Application, task marathon.Task) (int, error) {
|
||||
if portLabel, ok := (*application.Labels)[labelPort]; ok {
|
||||
port, err := strconv.Atoi(portLabel)
|
||||
|
|
|
@ -361,10 +361,10 @@ func TestMarathonLoadConfig(t *testing.T) {
|
|||
} else {
|
||||
// Compare backends
|
||||
if !reflect.DeepEqual(actualConfig.Backends, c.expectedBackends) {
|
||||
t.Errorf("got backend %v, want %v", spew.Sdump(actualConfig.Backends), spew.Sdump(c.expectedBackends))
|
||||
t.Errorf("got backend\n%v\nwant\n\n%v", spew.Sdump(actualConfig.Backends), spew.Sdump(c.expectedBackends))
|
||||
}
|
||||
if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) {
|
||||
t.Errorf("got frontend %v, want %v", spew.Sdump(actualConfig.Frontends), spew.Sdump(c.expectedFrontends))
|
||||
t.Errorf("got frontend\n%v\nwant\n\n%v", spew.Sdump(actualConfig.Frontends), spew.Sdump(c.expectedFrontends))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1430,6 +1430,125 @@ func TestMarathonGetSubDomain(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMarathonHasHealthCheckLabels(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
value *string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
desc: "label missing",
|
||||
value: nil,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "empty path",
|
||||
value: stringp(""),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "non-empty path",
|
||||
value: stringp("/path"),
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := marathon.Application{
|
||||
Labels: &map[string]string{},
|
||||
}
|
||||
if test.value != nil {
|
||||
app.AddLabel(labelBackendHealthCheckPath, *test.value)
|
||||
}
|
||||
prov := &Provider{}
|
||||
got := prov.hasHealthCheckLabels(app)
|
||||
if got != test.want {
|
||||
t.Errorf("got %t, want %t", got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarathonGetHealthCheckPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
value *string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
desc: "label missing",
|
||||
value: nil,
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
desc: "path existing",
|
||||
value: stringp("/path"),
|
||||
want: "/path",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := marathon.Application{}
|
||||
app.EmptyLabels()
|
||||
if test.value != nil {
|
||||
app.AddLabel(labelBackendHealthCheckPath, *test.value)
|
||||
}
|
||||
prov := &Provider{}
|
||||
got := prov.getHealthCheckPath(app)
|
||||
if got != test.want {
|
||||
t.Errorf("got %s, want %s", got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarathonGetHealthCheckInterval(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
value *string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
desc: "label missing",
|
||||
value: nil,
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
desc: "interval existing",
|
||||
value: stringp("5m"),
|
||||
want: "5m",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := marathon.Application{
|
||||
Labels: &map[string]string{},
|
||||
}
|
||||
if test.value != nil {
|
||||
app.AddLabel(labelBackendHealthCheckInterval, *test.value)
|
||||
}
|
||||
prov := &Provider{}
|
||||
got := prov.getHealthCheckInterval(app)
|
||||
if got != test.want {
|
||||
t.Errorf("got %s, want %s", got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func stringp(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func TestGetBackendServer(t *testing.T) {
|
||||
appID := "appId"
|
||||
host := "host"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue