Browse files

Fix group/all restarts with process dependencies

- widen the scope of visitor table so processes dependencies are not
  restarted more than once during a group control action

- visitor table is now passed as a param (via type ControlAction)
  rather than shared (was a member of type Control)

- add integration tests

Change-Id: I58c0e167f70208ce07b5600e228227f20366adc7
  • Loading branch information...
1 parent 6d63c29 commit 045dc3a1dfb558a8b924e2b205f7db6a243b85d9 @dougm dougm committed Nov 27, 2012
Showing with 415 additions and 69 deletions.
  1. +11 −8 api.go
  2. +66 −40 control.go
  3. +11 −11 control_test.go
  4. +4 −4 eventmonitor.go
  5. +2 −2 eventmonitor_test.go
  6. +2 −3 test/integration/api_test.go
  7. +318 −0 test/integration/depends_test.go
  8. +1 −1 watcher.go
View
19 api.go
@@ -95,7 +95,7 @@ func NewAPI(config *ConfigManager) *API {
// *Process methods apply to a single service
-func (c *Control) callAction(name string, r *ActionResult, action int) error {
+func (c *Control) callAction(name string, r *ActionResult, action *ControlAction) error {
err := c.DoAction(name, action)
r.Total++
@@ -108,23 +108,23 @@ func (c *Control) callAction(name string, r *ActionResult, action int) error {
}
func (a *API) StartProcess(name string, r *ActionResult) error {
- return a.Control.callAction(name, r, ACTION_START)
+ return a.Control.callAction(name, r, NewControlAction(ACTION_START))
}
func (a *API) StopProcess(name string, r *ActionResult) error {
- return a.Control.callAction(name, r, ACTION_STOP)
+ return a.Control.callAction(name, r, NewControlAction(ACTION_STOP))
}
func (a *API) RestartProcess(name string, r *ActionResult) error {
- return a.Control.callAction(name, r, ACTION_RESTART)
+ return a.Control.callAction(name, r, NewControlAction(ACTION_RESTART))
}
func (a *API) MonitorProcess(name string, r *ActionResult) error {
- return a.Control.callAction(name, r, ACTION_MONITOR)
+ return a.Control.callAction(name, r, NewControlAction(ACTION_MONITOR))
}
func (a *API) UnmonitorProcess(name string, r *ActionResult) error {
- return a.Control.callAction(name, r, ACTION_UNMONITOR)
+ return a.Control.callAction(name, r, NewControlAction(ACTION_UNMONITOR))
}
func (c *Control) processSummary(process *Process, summary *ProcessSummary) {
@@ -165,13 +165,15 @@ func (a *API) StatusProcess(name string, r *ProcessStatus) error {
// *Group methods apply to a service group
-func (c *Control) groupAction(name string, r *ActionResult, action int) error {
+func (c *Control) groupAction(name string, r *ActionResult, method int) error {
group, err := c.Config().FindGroup(name)
if err != nil {
return &ActionError{err}
}
+ action := NewGroupControlAction(method)
+
for name := range group.Processes {
c.callAction(name, r, action)
}
@@ -227,7 +229,8 @@ func (a *API) StatusGroup(name string, r *ProcessGroupStatus) error {
// *All methods apply to all services
-func (c *Control) allAction(r *ActionResult, action int) error {
+func (c *Control) allAction(r *ActionResult, method int) error {
+ action := NewGroupControlAction(method)
for _, processGroup := range c.Config().ProcessGroups {
for name, _ := range processGroup.Processes {
c.callAction(name, r, action)
View
106 control.go
@@ -27,6 +27,11 @@ const (
)
const (
+ scopeDefault = iota
+ scopeRestartGroup
+)
+
+const (
processStopped = iota
processStarted
)
@@ -45,11 +50,16 @@ type EventMonitorInterface interface {
type Control struct {
ConfigManager *ConfigManager
EventMonitor EventMonitorInterface
- visits map[string]*visitor
States map[string]*ProcessState
persistLock sync.Mutex
}
+type ControlAction struct {
+ scope int
+ method int
+ visits map[string]*visitor
+}
+
// flags to avoid invoking actions more than once
// as we traverse the dependency graph
type visitor struct {
@@ -138,7 +148,7 @@ func (c *ConfigManager) VisitProcesses(visit func(p *Process) bool) {
}
}
-func (c *Control) visitorOf(process *Process) *visitor {
+func (c *ControlAction) visitorOf(process *Process) *visitor {
if _, exists := c.visits[process.Name]; !exists {
c.visits[process.Name] = &visitor{}
}
@@ -168,9 +178,24 @@ func (c *Control) RegisterEventMonitor(eventMonitor *EventMonitor) {
c.EventMonitor = eventMonitor
}
+func NewControlAction(method int) *ControlAction {
+ return &ControlAction{
+ method: method,
+ visits: make(map[string]*visitor),
+ }
+}
+
+func NewGroupControlAction(method int) *ControlAction {
+ action := NewControlAction(method)
+ if method == ACTION_RESTART {
+ action.scope = scopeRestartGroup
+ }
+ return action
+}
+
// Invoke given action for the given process and its
// dependents and/or dependencies
-func (c *Control) DoAction(name string, action int) error {
+func (c *Control) DoAction(name string, action *ControlAction) error {
process, err := c.Config().FindProcess(name)
if err != nil {
Log.Error(err.Error())
@@ -182,39 +207,38 @@ func (c *Control) DoAction(name string, action int) error {
})
}
-func (c *Control) dispatchAction(process *Process, action int) error {
- c.visits = make(map[string]*visitor)
+func (c *Control) dispatchAction(process *Process, action *ControlAction) error {
- switch action {
+ switch action.method {
case ACTION_START:
if process.IsRunning() {
Log.Debugf("Process %q already running", process.Name)
c.monitorSet(process)
return nil
}
- c.doDepend(process, ACTION_STOP)
- c.doStart(process)
- c.doDepend(process, ACTION_START)
+ c.doDepend(process, ACTION_STOP, action)
+ c.doStart(process, action)
+ c.doDepend(process, ACTION_START, action)
case ACTION_STOP:
- c.doDepend(process, ACTION_STOP)
- c.doStop(process)
+ c.doDepend(process, ACTION_STOP, action)
+ c.doStop(process, action)
case ACTION_RESTART:
- c.doDepend(process, ACTION_STOP)
- if c.doStop(process) {
- c.doStart(process)
- c.doDepend(process, ACTION_START)
+ c.doDepend(process, ACTION_STOP, action)
+ if c.doStop(process, action) {
+ c.doStart(process, action)
+ c.doDepend(process, ACTION_START, action)
} else {
c.monitorSet(process)
}
case ACTION_MONITOR:
- c.doMonitor(process)
+ c.doMonitor(process, action)
case ACTION_UNMONITOR:
- c.doDepend(process, ACTION_UNMONITOR)
- c.doUnmonitor(process)
+ c.doDepend(process, ACTION_UNMONITOR, action)
+ c.doUnmonitor(process, action)
default:
err := fmt.Errorf("process %q -- invalid action: %d",
@@ -239,19 +263,21 @@ func (c *Control) invoke(process *Process, action func() error) error {
}
// Start the given Process dependencies before starting Process
-func (c *Control) doStart(process *Process) {
- visitor := c.visitorOf(process)
+func (c *Control) doStart(process *Process, action *ControlAction) {
+ visitor := action.visitorOf(process)
if visitor.started {
return
}
visitor.started = true
- for _, d := range process.DependsOn {
- parent, err := c.Config().FindProcess(d)
- if err != nil {
- panic(err)
+ if action.scope != scopeRestartGroup {
+ for _, d := range process.DependsOn {
+ parent, err := c.Config().FindProcess(d)
+ if err != nil {
+ panic(err)
+ }
+ c.doStart(parent, action)
}
- c.doStart(parent)
}
if !process.IsRunning() {
@@ -265,8 +291,8 @@ func (c *Control) doStart(process *Process) {
// Stop the given Process.
// Waits for process to stop or until Process.Timeout is reached.
-func (c *Control) doStop(process *Process) bool {
- visitor := c.visitorOf(process)
+func (c *Control) doStop(process *Process, action *ControlAction) bool {
+ visitor := action.visitorOf(process)
var rv = true
if visitor.stopped {
return rv
@@ -286,8 +312,8 @@ func (c *Control) doStop(process *Process) bool {
}
// Enable monitoring for Process dependencies and given Process.
-func (c *Control) doMonitor(process *Process) {
- if c.visitorOf(process).started {
+func (c *Control) doMonitor(process *Process, action *ControlAction) {
+ if action.visitorOf(process).started {
return
}
@@ -296,15 +322,15 @@ func (c *Control) doMonitor(process *Process) {
if err != nil {
panic(err)
}
- c.doMonitor(parent)
+ c.doMonitor(parent, action)
}
c.monitorSet(process)
}
// Disable monitoring for the given Process
-func (c *Control) doUnmonitor(process *Process) {
- visitor := c.visitorOf(process)
+func (c *Control) doUnmonitor(process *Process, action *ControlAction) {
+ visitor := action.visitorOf(process)
if visitor.stopped {
return
}
@@ -314,24 +340,24 @@ func (c *Control) doUnmonitor(process *Process) {
}
// Apply actions to processes that depend on the given Process
-func (c *Control) doDepend(process *Process, action int) {
+func (c *Control) doDepend(process *Process, method int, action *ControlAction) {
c.ConfigManager.VisitProcesses(func(child *Process) bool {
for _, dep := range child.DependsOn {
if dep == process.Name {
- switch action {
+ switch method {
case ACTION_START:
- c.doStart(child)
+ c.doStart(child, action)
case ACTION_MONITOR:
- c.doMonitor(child)
+ c.doMonitor(child, action)
}
- c.doDepend(child, action)
+ c.doDepend(child, method, action)
- switch action {
+ switch method {
case ACTION_STOP:
- c.doStop(child)
+ c.doStop(child, action)
case ACTION_UNMONITOR:
- c.doUnmonitor(child)
+ c.doUnmonitor(child, action)
}
break
}
View
22 control_test.go
@@ -53,7 +53,7 @@ func (s *ControlSuite) TestActions(c *C) {
c.Check(MONITOR_NOT, Equals, ctl.State(process).Monitor)
c.Check(0, Equals, ctl.State(process).Starts)
- rv := ctl.DoAction(name, ACTION_START)
+ rv := ctl.DoAction(name, NewControlAction(ACTION_START))
c.Check(1, Equals, fem.numStartMonitoringCalled)
c.Check(rv, IsNil)
@@ -62,18 +62,18 @@ func (s *ControlSuite) TestActions(c *C) {
c.Check(true, Equals, process.IsRunning())
- rv = ctl.DoAction(name, ACTION_RESTART)
+ rv = ctl.DoAction(name, NewControlAction(ACTION_RESTART))
c.Check(2, Equals, fem.numStartMonitoringCalled)
c.Check(rv, IsNil)
c.Check(2, Equals, ctl.State(process).Starts)
- rv = ctl.DoAction(name, ACTION_STOP)
+ rv = ctl.DoAction(name, NewControlAction(ACTION_STOP))
c.Check(rv, IsNil)
c.Check(MONITOR_NOT, Equals, ctl.State(process).Monitor)
- rv = ctl.DoAction(name, ACTION_MONITOR)
+ rv = ctl.DoAction(name, NewControlAction(ACTION_MONITOR))
c.Check(3, Equals, fem.numStartMonitoringCalled)
c.Check(rv, IsNil)
@@ -111,13 +111,13 @@ func (s *ControlSuite) TestDepends(c *C) {
c.Check(err, IsNil)
// start main process
- rv := ctl.DoAction(name, ACTION_START)
+ rv := ctl.DoAction(name, NewControlAction(ACTION_START))
c.Check(rv, IsNil)
c.Check(true, Equals, process.IsRunning())
// stop main process
- rv = ctl.DoAction(name, ACTION_STOP)
+ rv = ctl.DoAction(name, NewControlAction(ACTION_STOP))
c.Check(rv, IsNil)
c.Check(false, Equals, process.IsRunning())
@@ -152,7 +152,7 @@ func (s *ControlSuite) TestDepends(c *C) {
// test start/stop of dependant
// start main sevice
- rv = ctl.DoAction(name, ACTION_START)
+ rv = ctl.DoAction(name, NewControlAction(ACTION_START))
c.Check(rv, IsNil)
c.Check(true, Equals, process.IsRunning())
c.Check(2, Equals, ctl.State(process).Starts)
@@ -167,28 +167,28 @@ func (s *ControlSuite) TestDepends(c *C) {
}
// stop a dependency
- rv = ctl.DoAction(process.DependsOn[0], ACTION_STOP)
+ rv = ctl.DoAction(process.DependsOn[0], NewControlAction(ACTION_STOP))
c.Check(rv, IsNil)
// dependent will also stop
c.Check(false, Equals, process.IsRunning())
// start a dependency
- rv = ctl.DoAction(process.DependsOn[0], ACTION_START)
+ rv = ctl.DoAction(process.DependsOn[0], NewControlAction(ACTION_START))
c.Check(rv, IsNil)
// main process will come back up
c.Check(true, Equals, process.IsRunning())
- ctl.DoAction(process.Name, ACTION_STOP)
+ ctl.DoAction(process.Name, NewControlAction(ACTION_STOP))
c.Check(3, Equals, ctl.State(process).Starts)
c.Check(MONITOR_NOT, Equals, ctl.State(process).Monitor)
// stop all dependencies
for _, dname := range process.DependsOn {
- ctl.DoAction(dname, ACTION_STOP)
+ ctl.DoAction(dname, NewControlAction(ACTION_STOP))
}
// verify every process has been stopped
View
8 eventmonitor.go
@@ -112,7 +112,7 @@ type EventMonitor struct {
}
type ControlInterface interface {
- DoAction(name string, action int) error
+ DoAction(name string, action *ControlAction) error
IsMonitoring(process *Process) bool
}
@@ -161,21 +161,21 @@ func (e *EventMonitor) triggerAction(process *Process, event *ParsedEvent,
case "stop":
if e.TriggerProcessActions(process) {
e.printTriggeredMessage(event, resourceVal)
- return e.control.DoAction(event.processName, ACTION_STOP)
+ return e.control.DoAction(event.processName, NewControlAction(ACTION_STOP))
} else {
return nil
}
case "start":
if e.TriggerProcessActions(process) {
e.printTriggeredMessage(event, resourceVal)
- return e.control.DoAction(event.processName, ACTION_START)
+ return e.control.DoAction(event.processName, NewControlAction(ACTION_START))
} else {
return nil
}
case "restart":
if e.TriggerProcessActions(process) {
e.printTriggeredMessage(event, resourceVal)
- return e.control.DoAction(event.processName, ACTION_RESTART)
+ return e.control.DoAction(event.processName, NewControlAction(ACTION_RESTART))
} else {
return nil
}
View
4 eventmonitor_test.go
@@ -190,9 +190,9 @@ type FakeControl struct {
isMonitoring bool
}
-func (fc *FakeControl) DoAction(name string, action int) error {
+func (fc *FakeControl) DoAction(name string, action *ControlAction) error {
fc.numDoActionCalled++
- fc.lastActionCalled = action
+ fc.lastActionCalled = action.method
return nil
}
View
5 test/integration/api_test.go
@@ -22,7 +22,6 @@ type ApiIntSuite struct {
}
const (
- group = "api_test"
errorInProgressFmt = "ActionError: " + gonit.ERROR_IN_PROGRESS_FMT
)
@@ -46,7 +45,7 @@ func (s *ApiIntSuite) SetUpSuite(c *C) {
s.settings = helper.CreateGonitSettings("", s.dir, s.dir)
- helper.CreateProcessGroupCfg(group, s.dir,
+ helper.CreateProcessGroupCfg("api_test", s.dir,
&gonit.ProcessGroup{Processes: s.procs})
var err error
@@ -60,7 +59,7 @@ func (s *ApiIntSuite) SetUpSuite(c *C) {
c.Errorf("rpc.Dial: %v", err)
}
- pgs, err := s.statusGroup(group)
+ pgs, err := s.statusGroup("api_test")
c.Assert(err, IsNil)
c.Assert(pgs.Group, HasLen, len(s.procs))
for _, ps := range pgs.Group {
View
318 test/integration/depends_test.go
@@ -0,0 +1,318 @@
+// Copyright (c) 2012 VMware, Inc.
+
+package gonit_integration
+
+import (
+ "fmt"
+ "github.com/cloudfoundry/gonit"
+ "github.com/cloudfoundry/gonit/test/helper"
+ "io"
+ "io/ioutil"
+ . "launchpad.net/gocheck"
+ "net/rpc"
+ "net/rpc/jsonrpc"
+ "os/exec"
+)
+
+type DependsIntSuite struct {
+ gonitCmd *exec.Cmd
+ dir string
+ procs map[string]*gonit.Process
+ settings *gonit.Settings
+ client *rpc.Client
+}
+
+var _ = Suite(&DependsIntSuite{})
+
+func (s *DependsIntSuite) addProcess(name string) *gonit.Process {
+ flags := []string{"-s", "1h"}
+ process := helper.NewTestProcess(name, flags, true)
+ process.Description = name
+ s.procs[process.Name] = process
+ process.MonitorMode = gonit.MONITOR_MODE_MANUAL
+ return process
+}
+
+func (s *DependsIntSuite) SetUpSuite(c *C) {
+ s.procs = make(map[string]*gonit.Process)
+ s.addProcess("nginx")
+ s.addProcess("postgres")
+ s.addProcess("redis")
+ s.addProcess("nats")
+
+ s.addProcess("director").DependsOn = []string{"postgres", "redis", "nats"}
+
+ for i := 0; i < 3; i++ {
+ worker := fmt.Sprintf("worker_%d", i)
+ s.addProcess(worker).DependsOn = []string{"director"}
+ }
+
+ s.addProcess("aws_registry").DependsOn = []string{"postgres"}
+
+ s.dir = c.MkDir()
+
+ s.settings = helper.CreateGonitSettings("", s.dir, s.dir)
+
+ helper.CreateProcessGroupCfg("bosh", s.dir, &gonit.ProcessGroup{Processes: s.procs})
+
+ vcap := make(map[string]*gonit.Process)
+ for _, name := range []string{"dea", "router", "stager"} {
+ vcap[name] = s.addProcess(name)
+ }
+
+ helper.CreateProcessGroupCfg("vcap", s.dir, &gonit.ProcessGroup{Processes: vcap})
+
+ var err error
+ var stdout io.Reader
+ s.gonitCmd, stdout, err = helper.StartGonit(s.dir)
+ // TODO: log Writes block when the pipe buffer is full,
+ // so we must drain the pipe here
+ go io.Copy(ioutil.Discard, stdout)
+
+ if err != nil {
+ c.Errorf(err.Error())
+ }
+
+ s.client, err = jsonrpc.Dial("unix", s.settings.RpcServerUrl)
+ if err != nil {
+ c.Errorf("rpc.Dial: %v", err)
+ }
+}
+
+func (s *DependsIntSuite) TearDownSuite(c *C) {
+ if s.client != nil {
+ s.client.Close()
+ }
+
+ if err := helper.StopGonit(s.gonitCmd, s.dir); err != nil {
+ c.Errorf(err.Error())
+ }
+
+ for _, process := range s.procs {
+ helper.Cleanup(process)
+ }
+}
+
+func (s *DependsIntSuite) TestRestartAll(c *C) {
+ var err error
+ all := s.newGroupHelper("all")
+
+ // start all processes
+ err = all.runCmd("start")
+ c.Assert(err, IsNil)
+
+ err = all.status(all.before)
+ c.Assert(err, IsNil)
+
+ // check all processes are running
+ for _, bg := range all.before {
+ current := bg.Summary
+ comment := Commentf("process: %s", current.Name)
+ c.Check(current.Running, Equals, true, comment)
+ }
+
+ // restart all processes
+ err = all.runCmd("restart")
+ c.Assert(err, IsNil)
+
+ err = all.status(all.after)
+ c.Assert(err, IsNil)
+
+ // each process should only restart once
+ all.compare(func(previous, current *gonit.ProcessSummary) {
+ comment := Commentf("process: %s", current.Name)
+ c.Assert(previous.Name, Equals, current.Name)
+ c.Check(current.Running, Equals, true, comment)
+ c.Check(current.ControlState.Starts, Equals, previous.ControlState.Starts+1, comment)
+ })
+}
+
+func (s *DependsIntSuite) TestRestartGroup(c *C) {
+ var err error
+ bosh := s.newGroupHelper("bosh")
+ vcap := s.newGroupHelper("vcap")
+
+ // start bosh and vcap groups
+ for _, group := range []*groupHelper{bosh, vcap} {
+ err = group.runCmd("start")
+ c.Assert(err, IsNil)
+
+ err = group.status(group.before)
+ c.Assert(err, IsNil)
+
+ // check all processes are running
+ for _, bg := range group.before {
+ current := bg.Summary
+ comment := Commentf("process: %s", current.Name)
+ c.Check(current.Running, Equals, true, comment)
+ }
+ }
+
+ // restart bosh group
+ err = bosh.runCmd("restart")
+ c.Assert(err, IsNil)
+
+ err = bosh.status(bosh.after)
+ c.Assert(err, IsNil)
+
+ // each process should only restart once
+ bosh.compare(func(previous, current *gonit.ProcessSummary) {
+ comment := Commentf("process: %s", current.Name)
+ c.Assert(previous.Name, Equals, current.Name)
+ c.Check(current.Running, Equals, true, comment)
+ c.Check(current.ControlState.Starts, Equals, previous.ControlState.Starts+1, comment)
+ })
+
+ // vcap processes should not restart
+ err = vcap.status(vcap.after)
+ c.Assert(err, IsNil)
+ vcap.compare(func(previous, current *gonit.ProcessSummary) {
+ comment := Commentf("process: %s", current.Name)
+ c.Assert(previous.Name, Equals, current.Name)
+ c.Check(current.Running, Equals, true, comment)
+ c.Check(current.ControlState.Starts, Equals, previous.ControlState.Starts, comment)
+ })
+}
+
+func (s *DependsIntSuite) TestProcessDependencies(c *C) {
+ var err error
+ bosh := s.newGroupHelper("bosh")
+ process := s.procs["director"]
+
+ // stop all bosh processes
+ err = bosh.runCmd("stop")
+ c.Assert(err, IsNil)
+
+ err = bosh.status(bosh.before)
+ c.Assert(err, IsNil)
+
+ // check all processes are stopped
+ for _, bg := range bosh.before {
+ current := bg.Summary
+ comment := Commentf("process: %s", current.Name)
+ c.Check(current.Running, Equals, false, comment)
+ }
+
+ // start director process
+ err = helper.RunGonitCmd("start director", s.dir)
+ c.Assert(err, IsNil)
+
+ err = bosh.status(bosh.after)
+ c.Assert(err, IsNil)
+
+ bosh.compare(func(previous, current *gonit.ProcessSummary) {
+ running := false
+ delta := 0
+ // only director and its dependencies should start
+ if current.Name == process.Name || dependsOn(process, current.Name) {
+ running = true
+ delta = 1
+ }
+ comment := Commentf("process: %s", current.Name)
+ c.Assert(previous.Name, Equals, current.Name)
+ c.Check(current.Running, Equals, running, comment)
+ c.Check(current.ControlState.Starts, Equals, previous.ControlState.Starts+delta, comment)
+ })
+
+ bosh.before = bosh.after
+ // restart a director dependency
+ err = helper.RunGonitCmd("restart "+process.DependsOn[0], s.dir)
+ c.Assert(err, IsNil)
+
+ err = bosh.status(bosh.after)
+ c.Assert(err, IsNil)
+
+ bosh.compare(func(previous, current *gonit.ProcessSummary) {
+ running := false
+ delta := 0
+ // only director and its dependencies should be running
+ if current.Name == process.Name || dependsOn(process, current.Name) {
+ running = true
+ }
+ // only director and restarted dependency should restart
+ if current.Name == process.Name || current.Name == process.DependsOn[0] {
+ delta = 1
+ }
+
+ comment := Commentf("process: %s", current.Name)
+ c.Assert(previous.Name, Equals, current.Name)
+ c.Check(current.Running, Equals, running, comment)
+ c.Check(current.ControlState.Starts, Equals, previous.ControlState.Starts+delta, comment)
+ })
+
+ bosh.before = bosh.after
+ // stop director process
+ err = helper.RunGonitCmd("stop director", s.dir)
+ c.Assert(err, IsNil)
+
+ err = bosh.status(bosh.after)
+ c.Assert(err, IsNil)
+
+ bosh.compare(func(previous, current *gonit.ProcessSummary) {
+ running := false
+ // only director dependencies should still be running
+ if dependsOn(process, current.Name) {
+ running = true
+ }
+ comment := Commentf("process: %s", current.Name)
+ c.Assert(previous.Name, Equals, current.Name)
+ c.Check(current.Running, Equals, running, comment)
+ c.Check(current.ControlState.Starts, Equals, previous.ControlState.Starts, comment)
+ })
+}
+
+func dependsOn(process *gonit.Process, name string) bool {
+ for _, dep := range process.DependsOn {
+ if dep == name {
+ return true
+ }
+ }
+ return false
+}
+
+type groupHelper struct {
+ name string
+ suite *DependsIntSuite
+ before, after []gonit.ProcessStatus
+}
+
+func (d *groupHelper) compare(f func(previous, current *gonit.ProcessSummary)) {
+ for i := 0; i < len(d.before); i++ {
+ f(&d.before[i].Summary, &d.after[i].Summary)
+ }
+}
+
+func (d *groupHelper) isAll() bool {
+ return d.name == "all"
+}
+
+func (d *groupHelper) runCmd(name string) error {
+ cmd := ""
+ if !d.isAll() {
+ cmd += "-g "
+ }
+ cmd += name + " " + d.name
+ return helper.RunGonitCmd(cmd, d.suite.dir)
+}
+
+func (d *groupHelper) status(ps []gonit.ProcessStatus) error {
+ var method string
+ if d.isAll() {
+ method = "StatusAll"
+ } else {
+ method = "StatusGroup"
+ }
+ pgs := &gonit.ProcessGroupStatus{}
+ err := d.suite.client.Call("API."+method, d.name, pgs)
+ if err != nil {
+ copy(ps, pgs.Group)
+ }
+ return err
+}
+
+func (s *DependsIntSuite) newGroupHelper(name string) *groupHelper {
+ return &groupHelper{
+ name: name,
+ suite: s,
+ }
+}
View
2 watcher.go
@@ -36,7 +36,7 @@ func (w *Watcher) doCheckProcess(process *Process) error {
// TODO: flapping detection
Log.Debugf("Process %q: action start", process.Name)
- return w.Control.dispatchAction(process, ACTION_START)
+ return w.Control.dispatchAction(process, NewControlAction(ACTION_START))
}
func (w *Watcher) checkProcess(process *Process) {

0 comments on commit 045dc3a

Please sign in to comment.