From 9a9c8e57095f443cdc805849c63b1846f1190cad Mon Sep 17 00:00:00 2001 From: emile Date: Tue, 9 Feb 2016 23:10:24 +0100 Subject: [PATCH] Add Marathon TLS client config Signed-off-by: emile --- docs/index.md | 19 +- glide.yaml | 4 +- mocks/Marathon.go | 829 ++++++++++++++++++++++++++++++++++++++ provider/marathon.go | 14 +- provider/marathon_test.go | 46 +-- traefik.sample.toml | 7 + 6 files changed, 887 insertions(+), 32 deletions(-) create mode 100644 mocks/Marathon.go diff --git a/docs/index.md b/docs/index.md index e02d2e73f..3d4034be5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -625,11 +625,11 @@ Træfɪk can be configured to use Marathon as a backend configuration: # endpoint = "http://127.0.0.1:8080" -# Network interface used to call Marathon web services +# Network interface used to call Marathon web services. Needed in case of multiple network interfaces. # Optional # Default: "eth0" # -# networkInterface = "eth0" +networkInterface = "eth0" # Enable watch Marathon changes # @@ -649,6 +649,21 @@ domain = "marathon.localhost" # Optional # # filename = "marathon.tmpl" + +# Enable Marathon basic authentication +# +# Optional +# +# [marathon.basic] +# httpBasicAuthUser = "foo" +# httpBasicPassword = "bar" + +# TLS client configuration. https://golang.org/pkg/crypto/tls/#Config +# +# Optional +# +# [marathon.TLS] +# InsecureSkipVerify = true ``` Labels can be used on containers to override default behaviour: diff --git a/glide.yaml b/glide.yaml index 9a91f4b96..e0aacec11 100644 --- a/glide.yaml +++ b/glide.yaml @@ -43,7 +43,7 @@ import: - package: github.com/alecthomas/units ref: 6b4e7dc5e3143b85ea77909c72caf89416fc2915 - package: github.com/gambol99/go-marathon - ref: 8ce3f764250b2de3f2c627d12ca7dd21bd5e7f93 + ref: ade11d1dc2884ee1f387078fc28509559b6235d1 - package: github.com/mailgun/predicate ref: cb0bff91a7ab7cf7571e661ff883fc997bc554a3 - package: github.com/thoas/stats @@ -161,5 +161,7 @@ import: - package: github.com/spf13/cobra subpackages: - /cobra + - package: github.com/google/go-querystring/query - package: github.com/vulcand/vulcand/plugin/rewrite + - package: github.com/stretchr/testify/mock diff --git a/mocks/Marathon.go b/mocks/Marathon.go new file mode 100644 index 000000000..2fbe5ab5d --- /dev/null +++ b/mocks/Marathon.go @@ -0,0 +1,829 @@ +package mocks + +import "github.com/gambol99/go-marathon" +import "github.com/stretchr/testify/mock" + +import "net/url" + +import "time" + +// Marathon is a mock of marathon.Marathon +type Marathon struct { + mock.Mock +} + +// ListApplications provides a mock function with given fields: _a0 +func (_m *Marathon) ListApplications(_a0 url.Values) ([]string, error) { + ret := _m.Called(_a0) + + var r0 []string + if rf, ok := ret.Get(0).(func(url.Values) []string); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(url.Values) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ApplicationVersions provides a mock function with given fields: name +func (_m *Marathon) ApplicationVersions(name string) (*marathon.ApplicationVersions, error) { + ret := _m.Called(name) + + var r0 *marathon.ApplicationVersions + if rf, ok := ret.Get(0).(func(string) *marathon.ApplicationVersions); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.ApplicationVersions) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// HasApplicationVersion provides a mock function with given fields: name, version +func (_m *Marathon) HasApplicationVersion(name string, version string) (bool, error) { + ret := _m.Called(name, version) + + var r0 bool + if rf, ok := ret.Get(0).(func(string, string) bool); ok { + r0 = rf(name, version) + } else { + r0 = ret.Get(0).(bool) + } + + 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 +} + +// SetApplicationVersion provides a mock function with given fields: name, version +func (_m *Marathon) SetApplicationVersion(name string, version *marathon.ApplicationVersion) (*marathon.DeploymentID, error) { + ret := _m.Called(name, version) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string, *marathon.ApplicationVersion) *marathon.DeploymentID); ok { + r0 = rf(name, version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, *marathon.ApplicationVersion) error); ok { + r1 = rf(name, version) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ApplicationOK provides a mock function with given fields: name +func (_m *Marathon) ApplicationOK(name string) (bool, error) { + ret := _m.Called(name) + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(name) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateApplication provides a mock function with given fields: application +func (_m *Marathon) CreateApplication(application *marathon.Application) (*marathon.Application, error) { + ret := _m.Called(application) + + var r0 *marathon.Application + if rf, ok := ret.Get(0).(func(*marathon.Application) *marathon.Application); ok { + r0 = rf(application) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Application) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*marathon.Application) error); ok { + r1 = rf(application) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeleteApplication provides a mock function with given fields: name +func (_m *Marathon) DeleteApplication(name string) (*marathon.DeploymentID, error) { + ret := _m.Called(name) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string) *marathon.DeploymentID); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + 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) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(*marathon.Application) *marathon.DeploymentID); ok { + r0 = rf(application) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*marathon.Application) error); ok { + r1 = rf(application) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ApplicationDeployments provides a mock function with given fields: name +func (_m *Marathon) ApplicationDeployments(name string) ([]*marathon.DeploymentID, error) { + ret := _m.Called(name) + + var r0 []*marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string) []*marathon.DeploymentID); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ScaleApplicationInstances provides a mock function with given fields: name, instances, force +func (_m *Marathon) ScaleApplicationInstances(name string, instances int, force bool) (*marathon.DeploymentID, error) { + ret := _m.Called(name, instances, force) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string, int, bool) *marathon.DeploymentID); ok { + r0 = rf(name, instances, force) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, int, bool) error); ok { + r1 = rf(name, instances, force) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RestartApplication provides a mock function with given fields: name, force +func (_m *Marathon) RestartApplication(name string, force bool) (*marathon.DeploymentID, error) { + ret := _m.Called(name, force) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string, bool) *marathon.DeploymentID); ok { + r0 = rf(name, force) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, bool) error); ok { + r1 = rf(name, force) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Applications provides a mock function with given fields: _a0 +func (_m *Marathon) Applications(_a0 url.Values) (*marathon.Applications, error) { + ret := _m.Called(_a0) + + var r0 *marathon.Applications + if rf, ok := ret.Get(0).(func(url.Values) *marathon.Applications); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Applications) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(url.Values) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Application provides a mock function with given fields: name +func (_m *Marathon) Application(name string) (*marathon.Application, error) { + ret := _m.Called(name) + + var r0 *marathon.Application + if rf, ok := ret.Get(0).(func(string) *marathon.Application); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Application) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } 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) + + var r0 error + if rf, ok := ret.Get(0).(func(string, time.Duration) error); ok { + r0 = rf(name, timeout) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Tasks provides a mock function with given fields: application +func (_m *Marathon) Tasks(application string) (*marathon.Tasks, error) { + ret := _m.Called(application) + + var r0 *marathon.Tasks + if rf, ok := ret.Get(0).(func(string) *marathon.Tasks); ok { + r0 = rf(application) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Tasks) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(application) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AllTasks provides a mock function with given fields: opts +func (_m *Marathon) AllTasks(opts *marathon.AllTasksOpts) (*marathon.Tasks, error) { + ret := _m.Called(opts) + + var r0 *marathon.Tasks + if rf, ok := ret.Get(0).(func(*marathon.AllTasksOpts) *marathon.Tasks); ok { + r0 = rf(opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Tasks) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*marathon.AllTasksOpts) error); ok { + r1 = rf(opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TaskEndpoints provides a mock function with given fields: name, port, healthCheck +func (_m *Marathon) TaskEndpoints(name string, port int, healthCheck bool) ([]string, error) { + ret := _m.Called(name, port, healthCheck) + + var r0 []string + if rf, ok := ret.Get(0).(func(string, int, bool) []string); ok { + r0 = rf(name, port, healthCheck) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, int, bool) error); ok { + r1 = rf(name, port, healthCheck) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// KillApplicationTasks provides a mock function with given fields: applicationID, opts +func (_m *Marathon) KillApplicationTasks(applicationID string, opts *marathon.KillApplicationTasksOpts) (*marathon.Tasks, error) { + ret := _m.Called(applicationID, opts) + + var r0 *marathon.Tasks + if rf, ok := ret.Get(0).(func(string, *marathon.KillApplicationTasksOpts) *marathon.Tasks); ok { + r0 = rf(applicationID, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Tasks) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, *marathon.KillApplicationTasksOpts) error); ok { + r1 = rf(applicationID, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// KillTask provides a mock function with given fields: taskID, opts +func (_m *Marathon) KillTask(taskID string, opts *marathon.KillTaskOpts) (*marathon.Task, error) { + ret := _m.Called(taskID, opts) + + var r0 *marathon.Task + if rf, ok := ret.Get(0).(func(string, *marathon.KillTaskOpts) *marathon.Task); ok { + r0 = rf(taskID, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Task) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, *marathon.KillTaskOpts) error); ok { + r1 = rf(taskID, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// KillTasks provides a mock function with given fields: taskIDs, opts +func (_m *Marathon) KillTasks(taskIDs []string, opts *marathon.KillTaskOpts) error { + ret := _m.Called(taskIDs, opts) + + var r0 error + if rf, ok := ret.Get(0).(func([]string, *marathon.KillTaskOpts) error); ok { + r0 = rf(taskIDs, opts) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Groups provides a mock function with given fields: +func (_m *Marathon) Groups() (*marathon.Groups, error) { + ret := _m.Called() + + var r0 *marathon.Groups + if rf, ok := ret.Get(0).(func() *marathon.Groups); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Groups) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Group provides a mock function with given fields: name +func (_m *Marathon) Group(name string) (*marathon.Group, error) { + ret := _m.Called(name) + + var r0 *marathon.Group + if rf, ok := ret.Get(0).(func(string) *marathon.Group); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Group) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateGroup provides a mock function with given fields: group +func (_m *Marathon) CreateGroup(group *marathon.Group) error { + ret := _m.Called(group) + + var r0 error + if rf, ok := ret.Get(0).(func(*marathon.Group) error); ok { + r0 = rf(group) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteGroup provides a mock function with given fields: name +func (_m *Marathon) DeleteGroup(name string) (*marathon.DeploymentID, error) { + ret := _m.Called(name) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string) *marathon.DeploymentID); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdateGroup provides a mock function with given fields: id, group +func (_m *Marathon) UpdateGroup(id string, group *marathon.Group) (*marathon.DeploymentID, error) { + ret := _m.Called(id, group) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string, *marathon.Group) *marathon.DeploymentID); ok { + r0 = rf(id, group) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, *marathon.Group) error); ok { + r1 = rf(id, group) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// HasGroup provides a mock function with given fields: name +func (_m *Marathon) HasGroup(name string) (bool, error) { + ret := _m.Called(name) + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(name) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// WaitOnGroup provides a mock function with given fields: name, timeout +func (_m *Marathon) WaitOnGroup(name string, timeout time.Duration) error { + ret := _m.Called(name, timeout) + + var r0 error + if rf, ok := ret.Get(0).(func(string, time.Duration) error); ok { + r0 = rf(name, timeout) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Deployments provides a mock function with given fields: +func (_m *Marathon) Deployments() ([]*marathon.Deployment, error) { + ret := _m.Called() + + var r0 []*marathon.Deployment + if rf, ok := ret.Get(0).(func() []*marathon.Deployment); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*marathon.Deployment) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeleteDeployment provides a mock function with given fields: id, force +func (_m *Marathon) DeleteDeployment(id string, force bool) (*marathon.DeploymentID, error) { + ret := _m.Called(id, force) + + var r0 *marathon.DeploymentID + if rf, ok := ret.Get(0).(func(string, bool) *marathon.DeploymentID); ok { + r0 = rf(id, force) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.DeploymentID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, bool) error); ok { + r1 = rf(id, force) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// HasDeployment provides a mock function with given fields: id +func (_m *Marathon) HasDeployment(id string) (bool, error) { + ret := _m.Called(id) + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(id) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// WaitOnDeployment provides a mock function with given fields: id, timeout +func (_m *Marathon) WaitOnDeployment(id string, timeout time.Duration) error { + ret := _m.Called(id, timeout) + + var r0 error + if rf, ok := ret.Get(0).(func(string, time.Duration) error); ok { + r0 = rf(id, timeout) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Subscriptions provides a mock function with given fields: +func (_m *Marathon) Subscriptions() (*marathon.Subscriptions, error) { + ret := _m.Called() + + var r0 *marathon.Subscriptions + if rf, ok := ret.Get(0).(func() *marathon.Subscriptions); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Subscriptions) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AddEventsListener provides a mock function with given fields: channel, filter +func (_m *Marathon) AddEventsListener(channel marathon.EventsChannel, filter int) error { + ret := _m.Called(channel, filter) + + var r0 error + if rf, ok := ret.Get(0).(func(marathon.EventsChannel, int) error); ok { + r0 = rf(channel, filter) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveEventsListener provides a mock function with given fields: channel +func (_m *Marathon) RemoveEventsListener(channel marathon.EventsChannel) { + _m.Called(channel) +} + +// Unsubscribe provides a mock function with given fields: _a0 +func (_m *Marathon) Unsubscribe(_a0 string) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetMarathonURL provides a mock function with given fields: +func (_m *Marathon) GetMarathonURL() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Ping provides a mock function with given fields: +func (_m *Marathon) Ping() (bool, error) { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Info provides a mock function with given fields: +func (_m *Marathon) Info() (*marathon.Info, error) { + ret := _m.Called() + + var r0 *marathon.Info + if rf, ok := ret.Get(0).(func() *marathon.Info); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*marathon.Info) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Leader provides a mock function with given fields: +func (_m *Marathon) Leader() (string, error) { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbdicateLeader provides a mock function with given fields: +func (_m *Marathon) AbdicateLeader() (string, error) { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/provider/marathon.go b/provider/marathon.go index 33c53a0b4..ad54f56c8 100644 --- a/provider/marathon.go +++ b/provider/marathon.go @@ -7,10 +7,12 @@ import ( "strings" "text/template" + "crypto/tls" "github.com/BurntSushi/ty/fun" log "github.com/Sirupsen/logrus" "github.com/emilevauge/traefik/types" "github.com/gambol99/go-marathon" + "net/http" ) // Marathon holds configuration of the Marathon provider. @@ -20,7 +22,8 @@ type Marathon struct { Domain string NetworkInterface string Basic *MarathonBasic - marathonClient lightMarathonClient + TLS *tls.Config + marathonClient marathon.Marathon } // MarathonBasic holds basic authentication specific configurations @@ -44,6 +47,11 @@ func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage) config.HTTPBasicAuthUser = provider.Basic.HTTPBasicAuthUser config.HTTPBasicPassword = provider.Basic.HTTPBasicPassword } + config.HTTPClient = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: provider.TLS, + }, + } client, err := marathon.NewClient(config) if err != nil { log.Errorf("Failed to create a client for marathon, error: %s", err) @@ -100,7 +108,7 @@ func (provider *Marathon) loadMarathonConfig() *types.Configuration { return nil } - tasks, err := provider.marathonClient.AllTasks((url.Values{"status": []string{"running"}})) + tasks, err := provider.marathonClient.AllTasks(&marathon.AllTasksOpts{Status: "running"}) if err != nil { log.Errorf("Failed to create a client for marathon, error: %s", err) return nil @@ -190,7 +198,7 @@ func taskFilter(task marathon.Task, applications *marathon.Applications) bool { //filter healthchecks if application.HasHealthChecks() { if task.HasHealthCheckResults() { - for _, healthcheck := range task.HealthCheckResult { + for _, healthcheck := range task.HealthCheckResults { // found one bad healthcheck, return false if !healthcheck.Alive { log.Debugf("Filtering marathon task %s with bad healthcheck", task.AppID) diff --git a/provider/marathon_test.go b/provider/marathon_test.go index 6227a2641..31631870a 100644 --- a/provider/marathon_test.go +++ b/provider/marathon_test.go @@ -1,34 +1,32 @@ package provider import ( - "errors" - "net/url" "reflect" "testing" + "errors" + "github.com/emilevauge/traefik/mocks" "github.com/emilevauge/traefik/types" "github.com/gambol99/go-marathon" + "github.com/stretchr/testify/mock" ) type fakeClient struct { - applicationsError bool - applications *marathon.Applications - tasksError bool - tasks *marathon.Tasks + mocks.Marathon } -func (c *fakeClient) Applications(url.Values) (*marathon.Applications, error) { - if c.applicationsError { - return nil, errors.New("error") +func newFakeClient(applicationsError bool, applications *marathon.Applications, tasksError bool, tasks *marathon.Tasks) *fakeClient { + // create an instance of our test object + fakeClient := new(fakeClient) + if applicationsError { + fakeClient.On("Applications", mock.AnythingOfType("url.Values")).Return(nil, errors.New("error")) } - return c.applications, nil -} - -func (c *fakeClient) AllTasks(v url.Values) (*marathon.Tasks, error) { - if c.tasksError { - return nil, errors.New("error") + fakeClient.On("Applications", mock.AnythingOfType("url.Values")).Return(applications, nil) + if tasksError { + fakeClient.On("AllTasks", mock.AnythingOfType("*marathon.AllTasksOpts")).Return(nil, errors.New("error")) } - return c.tasks, nil + fakeClient.On("AllTasks", mock.AnythingOfType("*marathon.AllTasksOpts")).Return(tasks, nil) + return fakeClient } func TestMarathonLoadConfig(t *testing.T) { @@ -110,14 +108,10 @@ func TestMarathonLoadConfig(t *testing.T) { } for _, c := range cases { + fakeClient := newFakeClient(c.applicationsError, c.applications, c.tasksError, c.tasks) provider := &Marathon{ - Domain: "docker.localhost", - marathonClient: &fakeClient{ - applicationsError: c.applicationsError, - applications: c.applications, - tasksError: c.tasksError, - tasks: c.tasks, - }, + Domain: "docker.localhost", + marathonClient: fakeClient, } actualConfig := provider.loadMarathonConfig() if c.expectedNil { @@ -315,7 +309,7 @@ func TestMarathonTaskFilter(t *testing.T) { task: marathon.Task{ AppID: "foo", Ports: []int{80}, - HealthCheckResult: []*marathon.HealthCheckResult{ + HealthCheckResults: []*marathon.HealthCheckResult{ { Alive: false, }, @@ -338,7 +332,7 @@ func TestMarathonTaskFilter(t *testing.T) { task: marathon.Task{ AppID: "foo", Ports: []int{80}, - HealthCheckResult: []*marathon.HealthCheckResult{ + HealthCheckResults: []*marathon.HealthCheckResult{ { Alive: true, }, @@ -379,7 +373,7 @@ func TestMarathonTaskFilter(t *testing.T) { task: marathon.Task{ AppID: "foo", Ports: []int{80}, - HealthCheckResult: []*marathon.HealthCheckResult{ + HealthCheckResults: []*marathon.HealthCheckResult{ { Alive: true, }, diff --git a/traefik.sample.toml b/traefik.sample.toml index 3f77ea863..a773f2a17 100644 --- a/traefik.sample.toml +++ b/traefik.sample.toml @@ -239,6 +239,13 @@ # httpBasicAuthUser = "foo" # httpBasicPassword = "bar" +# TLS client configuration. https://golang.org/pkg/crypto/tls/#Config +# +# Optional +# +# [marathon.TLS] +# InsecureSkipVerify = true + ################################################################ # Consul KV configuration backend