diff --git a/acme/challengeProvider.go b/acme/challengeProvider.go index 8bdda2673..d9bccf204 100644 --- a/acme/challengeProvider.go +++ b/acme/challengeProvider.go @@ -29,7 +29,7 @@ func (c *wrapperChallengeProvider) getCertificate(domain string) (cert *tls.Cert } func (c *wrapperChallengeProvider) Present(domain, token, keyAuth string) error { - cert, err := acme.TLSSNI01ChallengeCert(keyAuth) + cert, _, err := acme.TLSSNI01ChallengeCert(keyAuth) if err != nil { return err } diff --git a/docs/toml.md b/docs/toml.md index 317da8049..c658fd731 100644 --- a/docs/toml.md +++ b/docs/toml.md @@ -666,6 +666,12 @@ domain = "marathon.localhost" # # [marathon.TLS] # InsecureSkipVerify = true + +# DCOSToken for DCOS environment, This will override the Authorization header +# +# Optional +# +# dcosToken = "xxxxxx" ``` Labels can be used on containers to override default behaviour: diff --git a/glide.lock b/glide.lock index 749d2f43b..0bd2350b3 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 7330fcb934bc52f47319f969bbf918e325bac2436518e3fad74de596f13bbda2 -updated: 2016-06-18T12:59:25.604052029+02:00 +hash: cba5a5482db5b6b3857187d401d8e47f9b36f00e7acdf6aba0174707cc8c8b8a +updated: 2016-06-20T23:18:44.178752884+02:00 imports: - name: github.com/boltdb/bolt version: 3f7947a25d970e1e5f512276c14d5dcf731ccd5e @@ -84,7 +84,7 @@ imports: - name: github.com/elazarl/go-bindata-assetfs version: 57eb5e1fc594ad4b0b1dbea7b286d299e0cb43c2 - name: github.com/gambol99/go-marathon - version: ade11d1dc2884ee1f387078fc28509559b6235d1 + version: a558128c87724cd7430060ef5aedf39f83937f55 - name: github.com/go-check/check version: 4f90aeace3a26ad7021961c297b22c42160c7b25 - name: github.com/google/go-querystring @@ -183,7 +183,7 @@ imports: - conntracker - router - name: github.com/xenolf/lego - version: 30a7a8e8821de3532192d1240a45e53c6204f603 + version: b2fad6198110326662e9e356a97199078a4a775c subpackages: - acme - name: golang.org/x/crypto diff --git a/glide.yaml b/glide.yaml index 31d7187c3..e50266f48 100644 --- a/glide.yaml +++ b/glide.yaml @@ -42,7 +42,7 @@ import: - store/zookeeper - package: github.com/elazarl/go-bindata-assetfs - package: github.com/gambol99/go-marathon - version: ade11d1dc2884ee1f387078fc28509559b6235d1 + version: a558128c87724cd7430060ef5aedf39f83937f55 - package: github.com/containous/mux - package: github.com/hashicorp/consul subpackages: @@ -60,7 +60,7 @@ import: subpackages: - plugin/rewrite - package: github.com/xenolf/lego - version: 30a7a8e8821de3532192d1240a45e53c6204f603 + version: b2fad6198110326662e9e356a97199078a4a775c subpackages: - acme - package: golang.org/x/net diff --git a/mocks/Marathon.go b/mocks/Marathon.go index 2fbe5ab5d..9f21da682 100644 --- a/mocks/Marathon.go +++ b/mocks/Marathon.go @@ -169,13 +169,13 @@ func (_m *Marathon) DeleteApplication(name string) (*marathon.DeploymentID, erro return r0, r1 } -// UpdateApplication provides a mock function with given fields: application -func (_m *Marathon) UpdateApplication(application *marathon.Application) (*marathon.DeploymentID, error) { - ret := _m.Called(application) +// UpdateApplication provides a mock function with given fields: application, force +func (_m *Marathon) UpdateApplication(application *marathon.Application, force bool) (*marathon.DeploymentID, error) { + ret := _m.Called(application, force) var r0 *marathon.DeploymentID - if rf, ok := ret.Get(0).(func(*marathon.Application) *marathon.DeploymentID); ok { - r0 = rf(application) + if rf, ok := ret.Get(0).(func(*marathon.Application, bool) *marathon.DeploymentID); ok { + r0 = rf(application, force) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*marathon.DeploymentID) @@ -183,8 +183,8 @@ func (_m *Marathon) UpdateApplication(application *marathon.Application) (*marat } var r1 error - if rf, ok := ret.Get(1).(func(*marathon.Application) error); ok { - r1 = rf(application) + if rf, ok := ret.Get(1).(func(*marathon.Application, bool) error); ok { + r1 = rf(application, force) } else { r1 = ret.Error(1) } @@ -307,6 +307,29 @@ func (_m *Marathon) Application(name string) (*marathon.Application, error) { return r0, r1 } +// ApplicationByVersion provides a mock function with given fields: name, version +func (_m *Marathon) ApplicationByVersion(name string, version string) (*marathon.Application, error) { + ret := _m.Called(name, version) + + var r0 *marathon.Application + if rf, ok := ret.Get(0).(func(string, string) *marathon.Application); ok { + r0 = rf(name, version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Application) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(name, version) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // WaitOnApplication provides a mock function with given fields: name, timeout func (_m *Marathon) WaitOnApplication(name string, timeout time.Duration) error { ret := _m.Called(name, timeout) diff --git a/provider/marathon.go b/provider/marathon.go index 4efdc390a..d0068e23b 100644 --- a/provider/marathon.go +++ b/provider/marathon.go @@ -26,6 +26,7 @@ type Marathon struct { Domain string `description:"Default domain used"` ExposedByDefault bool `description:"Expose Marathon apps by default"` GroupsAsSubDomains bool `description:"Convert Marathon groups to subdomains"` + DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header"` Basic *MarathonBasic TLS *tls.Config marathonClient marathon.Marathon @@ -54,6 +55,9 @@ func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, config.HTTPBasicAuthUser = provider.Basic.HTTPBasicAuthUser config.HTTPBasicPassword = provider.Basic.HTTPBasicPassword } + if len(provider.DCOSToken) > 0 { + config.DCOSToken = provider.DCOSToken + } config.HTTPClient = &http.Client{ Transport: &http.Transport{ TLSClientConfig: provider.TLS, @@ -67,7 +71,7 @@ func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, provider.marathonClient = client update := make(marathon.EventsChannel, 5) if provider.Watch { - if err := client.AddEventsListener(update, marathon.EVENTS_APPLICATIONS); err != nil { + if err := client.AddEventsListener(update, marathon.EventIDApplications); err != nil { log.Errorf("Failed to register for events, %s", err) return err } @@ -179,8 +183,8 @@ func taskFilter(task marathon.Task, applications *marathon.Applications, exposed } //filter indeterminable task port - portIndexLabel := application.Labels["traefik.portIndex"] - portValueLabel := application.Labels["traefik.port"] + portIndexLabel := (*application.Labels)["traefik.portIndex"] + portValueLabel := (*application.Labels)["traefik.port"] if portIndexLabel != "" && portValueLabel != "" { log.Debugf("Filtering marathon task %s specifying both traefik.portIndex and traefik.port labels", task.AppID) return false @@ -190,14 +194,14 @@ func taskFilter(task marathon.Task, applications *marathon.Applications, exposed return false } if portIndexLabel != "" { - index, err := strconv.Atoi(application.Labels["traefik.portIndex"]) + index, err := strconv.Atoi((*application.Labels)["traefik.portIndex"]) if err != nil || index < 0 || index > len(application.Ports)-1 { log.Debugf("Filtering marathon task %s with unexpected value for traefik.portIndex label", task.AppID) return false } } if portValueLabel != "" { - port, err := strconv.Atoi(application.Labels["traefik.port"]) + port, err := strconv.Atoi((*application.Labels)["traefik.port"]) if err != nil { log.Debugf("Filtering marathon task %s with unexpected value for traefik.port label", task.AppID) return false @@ -251,11 +255,11 @@ func getApplication(task marathon.Task, apps []marathon.Application) (marathon.A } func isApplicationEnabled(application marathon.Application, exposedByDefault bool) bool { - return exposedByDefault && application.Labels["traefik.enable"] != "false" || application.Labels["traefik.enable"] == "true" + return exposedByDefault && (*application.Labels)["traefik.enable"] != "false" || (*application.Labels)["traefik.enable"] == "true" } func (provider *Marathon) getLabel(application marathon.Application, label string) (string, error) { - for key, value := range application.Labels { + for key, value := range *application.Labels { if key == label { return value, nil } diff --git a/provider/marathon_test.go b/provider/marathon_test.go index ff5f79f10..a9ac67afb 100644 --- a/provider/marathon_test.go +++ b/provider/marathon_test.go @@ -19,13 +19,17 @@ func newFakeClient(applicationsError bool, applications *marathon.Applications, // create an instance of our test object fakeClient := new(fakeClient) if applicationsError { - fakeClient.On("Applications", mock.AnythingOfType("url.Values")).Return(nil, errors.New("error")) + fakeClient.On("Applications", mock.Anything).Return(nil, errors.New("error")) + } else { + fakeClient.On("Applications", mock.Anything).Return(applications, nil) } - fakeClient.On("Applications", mock.AnythingOfType("url.Values")).Return(applications, nil) - if tasksError { - fakeClient.On("AllTasks", mock.AnythingOfType("*marathon.AllTasksOpts")).Return(nil, errors.New("error")) + if !applicationsError { + if tasksError { + fakeClient.On("AllTasks", mock.Anything).Return(nil, errors.New("error")) + } else { + fakeClient.On("AllTasks", mock.Anything).Return(tasks, nil) + } } - fakeClient.On("AllTasks", mock.AnythingOfType("*marathon.AllTasksOpts")).Return(tasks, nil) return fakeClient } @@ -65,8 +69,9 @@ func TestMarathonLoadConfig(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "/test", - Ports: []int{80}, + ID: "/test", + Ports: []int{80}, + Labels: &map[string]string{}, }, }, }, @@ -115,6 +120,7 @@ func TestMarathonLoadConfig(t *testing.T) { marathonClient: fakeClient, } actualConfig := provider.loadMarathonConfig() + fakeClient.AssertExpectations(t) if c.expectedNil { if actualConfig != nil { t.Fatalf("Should have been nil, got %v", actualConfig) @@ -161,7 +167,8 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "foo", + ID: "foo", + Labels: &map[string]string{}, }, }, }, @@ -176,8 +183,9 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "foo", - Ports: []int{80, 443}, + ID: "foo", + Ports: []int{80, 443}, + Labels: &map[string]string{}, }, }, }, @@ -194,7 +202,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "foo", Ports: []int{80}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.enable": "false", }, }, @@ -213,7 +221,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "specify-port-number", Ports: []int{80, 443}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.port": "80", }, }, @@ -232,7 +240,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "specify-unknown-port-number", Ports: []int{80, 443}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.port": "8080", }, }, @@ -251,7 +259,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "specify-port-index", Ports: []int{80, 443}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.portIndex": "0", }, }, @@ -270,7 +278,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "specify-out-of-range-port-index", Ports: []int{80, 443}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.portIndex": "2", }, }, @@ -289,7 +297,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "specify-both-port-index-and-number", Ports: []int{80, 443}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.port": "443", "traefik.portIndex": "1", }, @@ -307,10 +315,11 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "foo", - Ports: []int{80}, - HealthChecks: []*marathon.HealthCheck{ - marathon.NewDefaultHealthCheck(), + ID: "foo", + Ports: []int{80}, + Labels: &map[string]string{}, + HealthChecks: &[]marathon.HealthCheck{ + *marathon.NewDefaultHealthCheck(), }, }, }, @@ -331,10 +340,11 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "foo", - Ports: []int{80}, - HealthChecks: []*marathon.HealthCheck{ - marathon.NewDefaultHealthCheck(), + ID: "foo", + Ports: []int{80}, + Labels: &map[string]string{}, + HealthChecks: &[]marathon.HealthCheck{ + *marathon.NewDefaultHealthCheck(), }, }, }, @@ -358,10 +368,11 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "foo", - Ports: []int{80}, - HealthChecks: []*marathon.HealthCheck{ - marathon.NewDefaultHealthCheck(), + ID: "foo", + Ports: []int{80}, + Labels: &map[string]string{}, + HealthChecks: &[]marathon.HealthCheck{ + *marathon.NewDefaultHealthCheck(), }, }, }, @@ -377,8 +388,9 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "foo", - Ports: []int{80}, + ID: "foo", + Ports: []int{80}, + Labels: &map[string]string{}, }, }, }, @@ -398,10 +410,11 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "foo", - Ports: []int{80}, - HealthChecks: []*marathon.HealthCheck{ - marathon.NewDefaultHealthCheck(), + ID: "foo", + Ports: []int{80}, + Labels: &map[string]string{}, + HealthChecks: &[]marathon.HealthCheck{ + *marathon.NewDefaultHealthCheck(), }, }, }, @@ -417,8 +430,9 @@ func TestMarathonTaskFilter(t *testing.T) { applications: &marathon.Applications{ Apps: []marathon.Application{ { - ID: "disable-default-expose", - Ports: []int{80}, + ID: "disable-default-expose", + Ports: []int{80}, + Labels: &map[string]string{}, }, }, }, @@ -435,7 +449,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "disable-default-expose-disable-in-label", Ports: []int{80}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.enable": "false", }, }, @@ -454,7 +468,7 @@ func TestMarathonTaskFilter(t *testing.T) { { ID: "disable-default-expose-enable-in-label", Ports: []int{80}, - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.enable": "true", }, }, @@ -486,14 +500,16 @@ func TestMarathonApplicationFilter(t *testing.T) { }, { application: marathon.Application{ - ID: "test", + ID: "test", + Labels: &map[string]string{}, }, filteredTasks: []marathon.Task{}, expected: false, }, { application: marathon.Application{ - ID: "foo", + ID: "foo", + Labels: &map[string]string{}, }, filteredTasks: []marathon.Task{ { @@ -504,7 +520,8 @@ func TestMarathonApplicationFilter(t *testing.T) { }, { application: marathon.Application{ - ID: "foo", + ID: "foo", + Labels: &map[string]string{}, }, filteredTasks: []marathon.Task{ { @@ -539,7 +556,8 @@ func TestMarathonGetPort(t *testing.T) { { applications: []marathon.Application{ { - ID: "test1", + ID: "test1", + Labels: &map[string]string{}, }, }, task: marathon.Task{ @@ -550,7 +568,8 @@ func TestMarathonGetPort(t *testing.T) { { applications: []marathon.Application{ { - ID: "test1", + ID: "test1", + Labels: &map[string]string{}, }, }, task: marathon.Task{ @@ -562,7 +581,8 @@ func TestMarathonGetPort(t *testing.T) { { applications: []marathon.Application{ { - ID: "test1", + ID: "test1", + Labels: &map[string]string{}, }, }, task: marathon.Task{ @@ -575,7 +595,7 @@ func TestMarathonGetPort(t *testing.T) { applications: []marathon.Application{ { ID: "specify-port-number", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.port": "443", }, }, @@ -590,7 +610,7 @@ func TestMarathonGetPort(t *testing.T) { applications: []marathon.Application{ { ID: "specify-port-index", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.portIndex": "1", }, }, @@ -628,7 +648,7 @@ func TestMarathonGetWeigh(t *testing.T) { applications: []marathon.Application{ { ID: "test1", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.weight": "10", }, }, @@ -642,7 +662,7 @@ func TestMarathonGetWeigh(t *testing.T) { applications: []marathon.Application{ { ID: "test", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.test": "10", }, }, @@ -656,7 +676,7 @@ func TestMarathonGetWeigh(t *testing.T) { applications: []marathon.Application{ { ID: "test", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.weight": "10", }, }, @@ -686,12 +706,13 @@ func TestMarathonGetDomain(t *testing.T) { expected string }{ { - application: marathon.Application{}, - expected: "docker.localhost", + application: marathon.Application{ + Labels: &map[string]string{}}, + expected: "docker.localhost", }, { application: marathon.Application{ - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.domain": "foo.bar", }, }, @@ -724,7 +745,7 @@ func TestMarathonGetProtocol(t *testing.T) { applications: []marathon.Application{ { ID: "test1", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.protocol": "https", }, }, @@ -738,7 +759,7 @@ func TestMarathonGetProtocol(t *testing.T) { applications: []marathon.Application{ { ID: "test", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.foo": "bar", }, }, @@ -752,7 +773,7 @@ func TestMarathonGetProtocol(t *testing.T) { applications: []marathon.Application{ { ID: "test", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.protocol": "https", }, }, @@ -780,12 +801,13 @@ func TestMarathonGetPassHostHeader(t *testing.T) { expected string }{ { - application: marathon.Application{}, - expected: "true", + application: marathon.Application{ + Labels: &map[string]string{}}, + expected: "true", }, { application: marathon.Application{ - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.frontend.passHostHeader": "false", }, }, @@ -809,12 +831,13 @@ func TestMarathonGetEntryPoints(t *testing.T) { expected []string }{ { - application: marathon.Application{}, - expected: []string{}, + application: marathon.Application{ + Labels: &map[string]string{}}, + expected: []string{}, }, { application: marathon.Application{ - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.frontend.entryPoints": "http,https", }, }, @@ -841,18 +864,20 @@ func TestMarathonGetFrontendRule(t *testing.T) { expected string }{ { - application: marathon.Application{}, - expected: "Host:.docker.localhost", + application: marathon.Application{ + Labels: &map[string]string{}}, + expected: "Host:.docker.localhost", }, { application: marathon.Application{ - ID: "test", + ID: "test", + Labels: &map[string]string{}, }, expected: "Host:test.docker.localhost", }, { application: marathon.Application{ - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.frontend.rule": "Host:foo.bar", }, }, @@ -878,7 +903,7 @@ func TestMarathonGetBackend(t *testing.T) { { application: marathon.Application{ ID: "foo", - Labels: map[string]string{ + Labels: &map[string]string{ "traefik.backend": "bar", }, }, diff --git a/traefik.sample.toml b/traefik.sample.toml index 33e755136..88f610cad 100644 --- a/traefik.sample.toml +++ b/traefik.sample.toml @@ -318,12 +318,11 @@ # httpBasicAuthUser = "foo" # httpBasicPassword = "bar" -# TLS client configuration. https://golang.org/pkg/crypto/tls/#Config +# DCOSToken for DCOS environment, This will override the Authorization header # # Optional # -# [marathon.TLS] -# InsecureSkipVerify = true +# dcosToken = "xxxxxx" ################################################################ # Kubernetes Ingress configuration backend