From 40a24499c2ff53c240f39a532bdbe338544a5771 Mon Sep 17 00:00:00 2001 From: wndhydrnt Date: Wed, 12 Aug 2015 21:09:39 +0200 Subject: [PATCH] Fix panic when no master could be parsed Fixes #19 --- CHANGELOG.md | 3 ++- marathon/generator.go | 20 ++------------------ mesos_master/mesos_master.go | 22 ++++++++++++++-------- mesos_master/notifier.go | 18 ++++++++++++++++-- mesos_master/notifier_test.go | 9 ++++----- utils/utils.go | 21 +++++++++++++++++++++ 6 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 utils/utils.go diff --git a/CHANGELOG.md b/CHANGELOG.md index dd63fb2..0565f7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ Improvements: Bug Fixes: * [Docs] Syntax error in example configuration file of HAProxy -* [Marathon] Fix ServiceGenerator only picks the first server in the list [#16](https://github.com/wndhydrnt/proxym/issues/16). +* [Marathon] Fix ServiceGenerator only picks the first server in the list [#16](https://github.com/wndhydrnt/proxym/issues/16) +* [Mesos Master] Fix panic when no master could be parsed [#19](https://github.com/wndhydrnt/proxym/issues/19) ## 1.4.0 diff --git a/marathon/generator.go b/marathon/generator.go index 0e40360..e0c0e01 100644 --- a/marathon/generator.go +++ b/marathon/generator.go @@ -6,12 +6,11 @@ import ( "fmt" "github.com/wndhydrnt/proxym/log" "github.com/wndhydrnt/proxym/types" + "github.com/wndhydrnt/proxym/utils" "io/ioutil" - "math/rand" "net/http" "strconv" "strings" - "time" ) // Generator talks to Marathon and creates a list of services as a result. @@ -26,7 +25,7 @@ func (g *Generator) Generate() ([]*types.Service, error) { var apps Apps var tasks Tasks - server := pickRandomServer(g.marathonServers) + server := utils.PickRandomFromList(g.marathonServers) log.AppLog.Debug("Querying Marathon server at '%s'", server) @@ -155,18 +154,3 @@ func normalizeId(id string, port int) string { return "marathon_" + strings.Join(parts, "_") + "_" + strconv.Itoa(port) } - -func pickRandomServer(servers []string) string { - if len(servers) == 1 { - return servers[0] - } - - src := rand.NewSource(time.Now().UnixNano()) - r := rand.New(src) - - max := (len(servers) * 100) - 1 - - pick := float64(r.Intn(max)) / 100 - - return servers[int(pick)] -} diff --git a/mesos_master/mesos_master.go b/mesos_master/mesos_master.go index 8eb44bf..6d4d78b 100644 --- a/mesos_master/mesos_master.go +++ b/mesos_master/mesos_master.go @@ -3,10 +3,12 @@ package mesos_master import ( "encoding/json" "errors" + "fmt" "github.com/kelseyhightower/envconfig" "github.com/wndhydrnt/proxym/log" "github.com/wndhydrnt/proxym/manager" "github.com/wndhydrnt/proxym/types" + "github.com/wndhydrnt/proxym/utils" "io/ioutil" "math/rand" "net/http" @@ -46,7 +48,13 @@ type state struct { } func parseLeader(leader string) (types.Host, error) { - address := strings.Split(leader, "@")[1] + pidParts := strings.Split(leader, "@") + + if len(pidParts) != 2 { + return types.Host{}, errors.New(fmt.Sprintf("Unable to parse Mesos Master PID %s", leader)) + } + + address := pidParts[1] parts := strings.Split(address, ":") @@ -90,10 +98,10 @@ func query(hc *http.Client, master string) (string, error) { return state.Leader, nil } -func leader(hc *http.Client, masters string) (types.Host, error) { +func leader(hc *http.Client, masters []string) (types.Host, error) { var host types.Host - master := pickMaster(masters) + master := utils.PickRandomFromList(masters) leaderId, err := query(hc, master) if err != nil { @@ -131,15 +139,13 @@ func init() { return } - hc := &http.Client{} lr := &leaderRegistry{ mutex: &sync.Mutex{}, } - n := &MesosMasterNotifier{ - config: &c, - hc: hc, - leaderRegistry: lr, + n, err := NewMesosNotifier(&c, lr) + if err != nil { + log.ErrorLog.Fatal(err) } manager.AddNotifier(n) diff --git a/mesos_master/notifier.go b/mesos_master/notifier.go index 5eb67bc..2187b45 100644 --- a/mesos_master/notifier.go +++ b/mesos_master/notifier.go @@ -1,9 +1,11 @@ package mesos_master import ( + "errors" "github.com/wndhydrnt/proxym/log" "github.com/wndhydrnt/proxym/types" "net/http" + "strings" "sync" "time" ) @@ -13,6 +15,7 @@ type MesosMasterNotifier struct { currentLeader types.Host hc *http.Client leaderRegistry *leaderRegistry + masters []string } func (m *MesosMasterNotifier) Start(refresh chan string, quit chan int, wg *sync.WaitGroup) { @@ -29,9 +32,9 @@ func (m *MesosMasterNotifier) Start(refresh chan string, quit chan int, wg *sync } func (m *MesosMasterNotifier) pollLeader(refresh chan string) { - host, err := leader(m.hc, m.config.Masters) + host, err := leader(m.hc, m.masters) if err != nil { - log.ErrorLog.Error("Error getting current Mesos Master leader: '%s'", err) + log.ErrorLog.Error("Error getting current Mesos Master leader: %s", err) return } @@ -47,3 +50,14 @@ func (m *MesosMasterNotifier) pollLeader(refresh chan string) { m.currentLeader = host } + +func NewMesosNotifier(c *Config, lr *leaderRegistry) (*MesosMasterNotifier, error) { + hc := &http.Client{} + masters := strings.Split(c.Masters, ",") + + if len(masters) == 0 { + return nil, errors.New("PROXYM_MESOS_MASTER_MASTERS is not set") + } + + return &MesosMasterNotifier{config: c, hc: hc, leaderRegistry: lr, masters: masters}, nil +} diff --git a/mesos_master/notifier_test.go b/mesos_master/notifier_test.go index 60f4199..d2e456d 100644 --- a/mesos_master/notifier_test.go +++ b/mesos_master/notifier_test.go @@ -45,14 +45,13 @@ func TestShouldTriggerRefreshWhenMasterChanges(t *testing.T) { mutex: &sync.Mutex{}, } - n := MesosMasterNotifier{ - config: &Config{ + n, _ := NewMesosNotifier( + &Config{ Masters: ts.URL, PollInterval: 1, }, - hc: &http.Client{}, - leaderRegistry: lr, - } + lr, + ) go n.Start(refresh, make(chan int), wg) diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..a23e165 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,21 @@ +package utils + +import ( + "math/rand" + "time" +) + +func PickRandomFromList(list []string) string { + if len(list) == 1 { + return list[0] + } + + src := rand.NewSource(time.Now().UnixNano()) + r := rand.New(src) + + max := (len(list) * 100) - 1 + + pick := float64(r.Intn(max)) / 100 + + return list[int(pick)] +}