New constraints management.
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
This commit is contained in:
parent
e9792b446f
commit
fe68e9e243
40 changed files with 658 additions and 630 deletions
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/containous/traefik/pkg/config/label"
|
||||
"github.com/containous/traefik/pkg/log"
|
||||
"github.com/containous/traefik/pkg/provider"
|
||||
"github.com/containous/traefik/pkg/provider/constraints"
|
||||
"github.com/gambol99/go-marathon"
|
||||
)
|
||||
|
||||
|
@ -29,11 +30,20 @@ func (p *Provider) buildConfiguration(ctx context.Context, applications *maratho
|
|||
continue
|
||||
}
|
||||
|
||||
if !p.keepApplication(ctxApp, extraConf) {
|
||||
labels := stringValueMap(app.Labels)
|
||||
|
||||
if app.Constraints != nil {
|
||||
for i, constraintParts := range *app.Constraints {
|
||||
key := constraints.MarathonConstraintPrefix + "-" + strconv.Itoa(i)
|
||||
labels[key] = strings.Join(constraintParts, ":")
|
||||
}
|
||||
}
|
||||
|
||||
if !p.keepApplication(ctxApp, extraConf, labels) {
|
||||
continue
|
||||
}
|
||||
|
||||
confFromLabel, err := label.DecodeConfiguration(stringValueMap(app.Labels))
|
||||
confFromLabel, err := label.DecodeConfiguration(labels)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
|
@ -65,7 +75,7 @@ func (p *Provider) buildConfiguration(ctx context.Context, applications *maratho
|
|||
Labels map[string]string
|
||||
}{
|
||||
Name: app.ID,
|
||||
Labels: stringValueMap(app.Labels),
|
||||
Labels: labels,
|
||||
}
|
||||
|
||||
serviceName := getServiceName(app)
|
||||
|
@ -164,7 +174,7 @@ func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, app maratho
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) keepApplication(ctx context.Context, extraConf configuration) bool {
|
||||
func (p *Provider) keepApplication(ctx context.Context, extraConf configuration, labels map[string]string) bool {
|
||||
logger := log.FromContext(ctx)
|
||||
|
||||
// Filter disabled application.
|
||||
|
@ -174,10 +184,13 @@ func (p *Provider) keepApplication(ctx context.Context, extraConf configuration)
|
|||
}
|
||||
|
||||
// Filter by constraints.
|
||||
if ok, failingConstraint := p.MatchConstraints(extraConf.Tags); !ok {
|
||||
if failingConstraint != nil {
|
||||
logger.Debugf("Filtering Marathon application, pruned by %q constraint", failingConstraint.String())
|
||||
}
|
||||
matches, err := constraints.Match(labels, p.Constraints)
|
||||
if err != nil {
|
||||
logger.Error("Error matching constraints expression: %v", err)
|
||||
return false
|
||||
}
|
||||
if !matches {
|
||||
logger.Debugf("Marathon application filtered by constraint expression: %q", p.Constraints)
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/containous/traefik/pkg/config"
|
||||
"github.com/containous/traefik/pkg/types"
|
||||
"github.com/gambol99/go-marathon"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -29,12 +28,11 @@ func TestGetConfigurationAPIErrors(t *testing.T) {
|
|||
|
||||
func TestBuildConfiguration(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
applications *marathon.Applications
|
||||
constraints []*types.Constraint
|
||||
filterMarathonConstraints bool
|
||||
defaultRule string
|
||||
expected *config.Configuration
|
||||
desc string
|
||||
applications *marathon.Applications
|
||||
constraints string
|
||||
defaultRule string
|
||||
expected *config.Configuration
|
||||
}{
|
||||
{
|
||||
desc: "simple application",
|
||||
|
@ -1065,13 +1063,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withTasks(localhostTask(taskPorts(80, 81))),
|
||||
withLabel("traefik.tags", "foo"),
|
||||
)),
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Value: "bar",
|
||||
},
|
||||
},
|
||||
constraints: `Label("traefik.tags", "bar")`,
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
|
@ -1093,14 +1085,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withTasks(localhostTask(taskPorts(80, 81))),
|
||||
constraint("rack_id:CLUSTER:rack-1"),
|
||||
)),
|
||||
filterMarathonConstraints: true,
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Value: "rack_id:CLUSTER:rack-2",
|
||||
},
|
||||
},
|
||||
constraints: `MarathonConstraint("rack_id:CLUSTER:rack-2")`,
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
|
@ -1122,14 +1107,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withTasks(localhostTask(taskPorts(80, 81))),
|
||||
constraint("rack_id:CLUSTER:rack-1"),
|
||||
)),
|
||||
filterMarathonConstraints: true,
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Value: "rack_id:CLUSTER:rack-1",
|
||||
},
|
||||
},
|
||||
constraints: `MarathonConstraint("rack_id:CLUSTER:rack-1")`,
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
|
@ -1167,14 +1145,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withTasks(localhostTask(taskPorts(80, 81))),
|
||||
withLabel("traefik.tags", "bar"),
|
||||
)),
|
||||
|
||||
constraints: []*types.Constraint{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
Value: "bar",
|
||||
},
|
||||
},
|
||||
constraints: `Label("traefik.tags", "bar")`,
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
|
@ -1417,9 +1388,8 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
}
|
||||
|
||||
p := &Provider{
|
||||
DefaultRule: defaultRule,
|
||||
ExposedByDefault: true,
|
||||
FilterMarathonConstraints: test.filterMarathonConstraints,
|
||||
DefaultRule: defaultRule,
|
||||
ExposedByDefault: true,
|
||||
}
|
||||
p.Constraints = test.constraints
|
||||
|
||||
|
@ -1473,7 +1443,7 @@ func TestApplicationFilterEnabled(t *testing.T) {
|
|||
extraConf, err := provider.getConfiguration(app)
|
||||
require.NoError(t, err)
|
||||
|
||||
if provider.keepApplication(context.Background(), extraConf) != test.expected {
|
||||
if provider.keepApplication(context.Background(), extraConf, stringValueMap(app.Labels)) != test.expected {
|
||||
t.Errorf("got unexpected filtering = %t", !test.expected)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,7 +2,6 @@ package marathon
|
|||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/pkg/config/label"
|
||||
"github.com/gambol99/go-marathon"
|
||||
|
@ -10,7 +9,6 @@ import (
|
|||
|
||||
type configuration struct {
|
||||
Enable bool
|
||||
Tags []string
|
||||
Marathon specificConfiguration
|
||||
}
|
||||
|
||||
|
@ -23,23 +21,16 @@ func (p *Provider) getConfiguration(app marathon.Application) (configuration, er
|
|||
|
||||
conf := configuration{
|
||||
Enable: p.ExposedByDefault,
|
||||
Tags: nil,
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: math.MinInt32,
|
||||
},
|
||||
}
|
||||
|
||||
err := label.Decode(labels, &conf, "traefik.marathon.", "traefik.enable", "traefik.tags")
|
||||
err := label.Decode(labels, &conf, "traefik.marathon.", "traefik.enable")
|
||||
if err != nil {
|
||||
return configuration{}, err
|
||||
}
|
||||
|
||||
if p.FilterMarathonConstraints && app.Constraints != nil {
|
||||
for _, constraintParts := range *app.Constraints {
|
||||
conf.Tags = append(conf.Tags, strings.Join(constraintParts, ":"))
|
||||
}
|
||||
}
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,10 @@ func TestGetConfiguration(t *testing.T) {
|
|||
Labels: &map[string]string{},
|
||||
},
|
||||
p: Provider{
|
||||
ExposedByDefault: false,
|
||||
FilterMarathonConstraints: false,
|
||||
ExposedByDefault: false,
|
||||
},
|
||||
expected: configuration{
|
||||
Enable: false,
|
||||
Tags: nil,
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: math.MinInt32,
|
||||
},
|
||||
|
@ -43,12 +41,10 @@ func TestGetConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
p: Provider{
|
||||
ExposedByDefault: false,
|
||||
FilterMarathonConstraints: false,
|
||||
ExposedByDefault: false,
|
||||
},
|
||||
expected: configuration{
|
||||
Enable: true,
|
||||
Tags: nil,
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: math.MinInt32,
|
||||
},
|
||||
|
@ -63,12 +59,10 @@ func TestGetConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
p: Provider{
|
||||
ExposedByDefault: false,
|
||||
FilterMarathonConstraints: false,
|
||||
ExposedByDefault: false,
|
||||
},
|
||||
expected: configuration{
|
||||
Enable: false,
|
||||
Tags: nil,
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: 4,
|
||||
},
|
||||
|
@ -83,14 +77,10 @@ func TestGetConfiguration(t *testing.T) {
|
|||
Labels: &map[string]string{},
|
||||
},
|
||||
p: Provider{
|
||||
ExposedByDefault: false,
|
||||
FilterMarathonConstraints: true,
|
||||
ExposedByDefault: false,
|
||||
},
|
||||
expected: configuration{
|
||||
Enable: false,
|
||||
Tags: []string{
|
||||
"key:value",
|
||||
},
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: math.MinInt32,
|
||||
},
|
||||
|
@ -103,12 +93,10 @@ func TestGetConfiguration(t *testing.T) {
|
|||
Labels: &map[string]string{},
|
||||
},
|
||||
p: Provider{
|
||||
ExposedByDefault: true,
|
||||
FilterMarathonConstraints: false,
|
||||
ExposedByDefault: true,
|
||||
},
|
||||
expected: configuration{
|
||||
Enable: true,
|
||||
Tags: nil,
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: math.MinInt32,
|
||||
},
|
||||
|
@ -123,32 +111,10 @@ func TestGetConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
p: Provider{
|
||||
ExposedByDefault: true,
|
||||
FilterMarathonConstraints: false,
|
||||
ExposedByDefault: true,
|
||||
},
|
||||
expected: configuration{
|
||||
Enable: false,
|
||||
Tags: nil,
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: math.MinInt32,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Tags in label",
|
||||
app: marathon.Application{
|
||||
Constraints: &[][]string{},
|
||||
Labels: &map[string]string{
|
||||
"traefik.tags": "mytags",
|
||||
},
|
||||
},
|
||||
p: Provider{
|
||||
ExposedByDefault: true,
|
||||
FilterMarathonConstraints: false,
|
||||
},
|
||||
expected: configuration{
|
||||
Enable: true,
|
||||
Tags: []string{"mytags"},
|
||||
Marathon: specificConfiguration{
|
||||
IPAddressIdx: math.MinInt32,
|
||||
},
|
||||
|
|
|
@ -45,26 +45,24 @@ var _ provider.Provider = (*Provider)(nil)
|
|||
|
||||
// Provider holds configuration of the provider.
|
||||
type Provider struct {
|
||||
provider.Constrainer `description:"List of constraints used to filter out some containers." export:"true"`
|
||||
|
||||
Trace bool `description:"Display additional provider logs." export:"true"`
|
||||
Watch bool `description:"Watch provider." export:"true"`
|
||||
Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon." export:"true"`
|
||||
DefaultRule string `description:"Default rule."`
|
||||
ExposedByDefault bool `description:"Expose Marathon apps by default." export:"true"`
|
||||
DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header." export:"true"`
|
||||
FilterMarathonConstraints bool `description:"Enable use of Marathon constraints in constraint filtering." export:"true"`
|
||||
TLS *types.ClientTLS `description:"Enable TLS support." export:"true"`
|
||||
DialerTimeout types.Duration `description:"Set a dialer timeout for Marathon." export:"true"`
|
||||
ResponseHeaderTimeout types.Duration `description:"Set a response header timeout for Marathon." export:"true"`
|
||||
TLSHandshakeTimeout types.Duration `description:"Set a TLS handshake timeout for Marathon." export:"true"`
|
||||
KeepAlive types.Duration `description:"Set a TCP Keep Alive time." export:"true"`
|
||||
ForceTaskHostname bool `description:"Force to use the task's hostname." export:"true"`
|
||||
Basic *Basic `description:"Enable basic authentication." export:"true"`
|
||||
RespectReadinessChecks bool `description:"Filter out tasks with non-successful readiness checks during deployments." export:"true"`
|
||||
readyChecker *readinessChecker
|
||||
marathonClient marathon.Marathon
|
||||
defaultRuleTpl *template.Template
|
||||
Constraints string `description:"Constraints is an expression that Traefik matches against the application's labels to determine whether to create any route for that application." export:"true"`
|
||||
Trace bool `description:"Display additional provider logs." export:"true"`
|
||||
Watch bool `description:"Watch provider." export:"true"`
|
||||
Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon." export:"true"`
|
||||
DefaultRule string `description:"Default rule."`
|
||||
ExposedByDefault bool `description:"Expose Marathon apps by default." export:"true"`
|
||||
DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header." export:"true"`
|
||||
TLS *types.ClientTLS `description:"Enable TLS support." export:"true"`
|
||||
DialerTimeout types.Duration `description:"Set a dialer timeout for Marathon." export:"true"`
|
||||
ResponseHeaderTimeout types.Duration `description:"Set a response header timeout for Marathon." export:"true"`
|
||||
TLSHandshakeTimeout types.Duration `description:"Set a TLS handshake timeout for Marathon." export:"true"`
|
||||
KeepAlive types.Duration `description:"Set a TCP Keep Alive time." export:"true"`
|
||||
ForceTaskHostname bool `description:"Force to use the task's hostname." export:"true"`
|
||||
Basic *Basic `description:"Enable basic authentication." export:"true"`
|
||||
RespectReadinessChecks bool `description:"Filter out tasks with non-successful readiness checks during deployments." export:"true"`
|
||||
readyChecker *readinessChecker
|
||||
marathonClient marathon.Marathon
|
||||
defaultRuleTpl *template.Template
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue