Skip to content
This repository has been archived by the owner on Jan 26, 2022. It is now read-only.

Commit

Permalink
Start/stop/restart actions and main integration.
Browse files Browse the repository at this point in the history
This change adds the ability to use start/stop/restart actions in
event rules. It also integrates the eventmonitor into the main code,
so it runs when gonit is running.

Change-Id: I617024ccbc83b02e0fb80c6eb34a7c4d0eac46c5
  • Loading branch information
lisbakke committed Sep 19, 2012
1 parent 8d7c5a5 commit cb0d39f
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 132 deletions.
50 changes: 25 additions & 25 deletions api.go
Expand Up @@ -11,7 +11,7 @@ import (
var notimpl = errors.New("Method not implemented")

type API struct {
control *Control
Control *Control
}

type ProcessSummary struct {
Expand Down Expand Up @@ -64,7 +64,7 @@ func (e *ActionError) Error() string {

func NewAPI(config *ConfigManager) *API {
return &API{
control: &Control{configManager: config},
Control: &Control{configManager: config},
}
}

Expand All @@ -83,23 +83,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, 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, 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, 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, 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, ACTION_UNMONITOR)
}

func (c *Control) processSummary(process *Process, summary *ProcessSummary) {
Expand Down Expand Up @@ -129,13 +129,13 @@ func (c *Control) processStatus(process *Process, status *ProcessStatus) error {
}

func (a *API) StatusProcess(name string, r *ProcessStatus) error {
process, err := a.control.Config().FindProcess(name)
process, err := a.Control.Config().FindProcess(name)

if err != nil {
return err
}

return a.control.processStatus(process, r)
return a.Control.processStatus(process, r)
}

// *Group methods apply to a service group
Expand All @@ -155,23 +155,23 @@ func (c *Control) groupAction(name string, r *ActionResult, action int) error {
}

func (a *API) StartGroup(name string, r *ActionResult) error {
return a.control.groupAction(name, r, ACTION_START)
return a.Control.groupAction(name, r, ACTION_START)
}

func (a *API) StopGroup(name string, r *ActionResult) error {
return a.control.groupAction(name, r, ACTION_STOP)
return a.Control.groupAction(name, r, ACTION_STOP)
}

func (a *API) RestartGroup(name string, r *ActionResult) error {
return a.control.groupAction(name, r, ACTION_RESTART)
return a.Control.groupAction(name, r, ACTION_RESTART)
}

func (a *API) MonitorGroup(name string, r *ActionResult) error {
return a.control.groupAction(name, r, ACTION_MONITOR)
return a.Control.groupAction(name, r, ACTION_MONITOR)
}

func (a *API) UnmonitorGroup(name string, r *ActionResult) error {
return a.control.groupAction(name, r, ACTION_UNMONITOR)
return a.Control.groupAction(name, r, ACTION_UNMONITOR)
}

func (c *Control) groupStatus(group *ProcessGroup,
Expand All @@ -187,14 +187,14 @@ func (c *Control) groupStatus(group *ProcessGroup,
}

func (a *API) StatusGroup(name string, r *ProcessGroupStatus) error {
group, err := a.control.Config().FindGroup(name)
group, err := a.Control.Config().FindGroup(name)

if err != nil {
return err
}

r.Name = name
a.control.groupStatus(group, r)
a.Control.groupStatus(group, r)

return nil
}
Expand All @@ -211,40 +211,40 @@ func (c *Control) allAction(r *ActionResult, action int) error {
}

func (a *API) StartAll(unused interface{}, r *ActionResult) error {
return a.control.allAction(r, ACTION_START)
return a.Control.allAction(r, ACTION_START)
}

func (a *API) StopAll(unused interface{}, r *ActionResult) error {
return a.control.allAction(r, ACTION_STOP)
return a.Control.allAction(r, ACTION_STOP)
}

func (a *API) RestartAll(unused interface{}, r *ActionResult) error {
return a.control.allAction(r, ACTION_RESTART)
return a.Control.allAction(r, ACTION_RESTART)
}

func (a *API) MonitorAll(unused interface{}, r *ActionResult) error {
return a.control.allAction(r, ACTION_MONITOR)
return a.Control.allAction(r, ACTION_MONITOR)
}

func (a *API) UnmonitorAll(unused interface{}, r *ActionResult) error {
return a.control.allAction(r, ACTION_UNMONITOR)
return a.Control.allAction(r, ACTION_UNMONITOR)
}

func (a *API) StatusAll(name string, r *ProcessGroupStatus) error {
r.Name = name

for _, processGroup := range a.control.Config().ProcessGroups {
a.control.groupStatus(processGroup, r)
for _, processGroup := range a.Control.Config().ProcessGroups {
a.Control.groupStatus(processGroup, r)
}

return nil
}

func (a *API) Summary(unused interface{}, s *Summary) error {
for _, group := range a.control.Config().ProcessGroups {
for _, group := range a.Control.Config().ProcessGroups {
for _, process := range group.Processes {
summary := ProcessSummary{}
a.control.processSummary(process, &summary)
a.Control.processSummary(process, &summary)
s.Processes = append(s.Processes, summary)
}
}
Expand Down
34 changes: 31 additions & 3 deletions configmanager.go
Expand Up @@ -63,15 +63,16 @@ type Process struct {
Description string
DependsOn []string
Actions map[string][]string
// TODO How do we make it so Monitor is true by default and only false when
// explicitly set in yaml?
Monitor bool
MonitorMode string
}

const (
CONFIG_FILE_POSTFIX = "-gonit.yml"
SETTINGS_FILENAME = "gonit.yml"
UNIX_SOCKET_TRANSPORT = "unix_socket"
MONITOR_MODE_ACTIVE = "active"
MONITOR_MODE_PASSIVE = "passive"
MONITOR_MODE_MANUAL = "manual"
)

const (
Expand Down Expand Up @@ -217,12 +218,27 @@ func (c *ConfigManager) Parse(paths ...string) error {
log.Printf("No settings found, using defaults.")
}
c.applyDefaultSettings()
c.applyDefaultConfigOpts()
if err := c.validate(); err != nil {
return err
}
return nil
}

func (c *ConfigManager) applyDefaultMonitorMode() {
for _, pg := range c.ProcessGroups {
for _, process := range pg.Processes {
if process.MonitorMode == "" {
process.MonitorMode = MONITOR_MODE_ACTIVE
}
}
}
}

func (c *ConfigManager) applyDefaultConfigOpts() {
c.applyDefaultMonitorMode()
}

// Validates that certain fields exist in the config file.
func (pg ProcessGroup) validateRequiredFieldsExist() error {
for name, process := range pg.Processes {
Expand Down Expand Up @@ -283,3 +299,15 @@ func (c *ConfigManager) validate() error {
}
return nil
}

func (p *Process) IsMonitoringModeActive() bool {
return p.MonitorMode == MONITOR_MODE_ACTIVE
}

func (p *Process) IsMonitoringModePassive() bool {
return p.MonitorMode == MONITOR_MODE_PASSIVE
}

func (p *Process) IsMonitoringModeManual() bool {
return p.MonitorMode == MONITOR_MODE_MANUAL
}
62 changes: 42 additions & 20 deletions control.go
Expand Up @@ -5,6 +5,7 @@ package gonit
import (
"fmt"
"log"
"sync"
"time"
)

Expand All @@ -28,8 +29,14 @@ const (
processStarted
)

// So we can mock it in tests.
type EventMonitorInterface interface {
StartMonitoringProcess(process *Process)
}

type Control struct {
configManager *ConfigManager
EventMonitor EventMonitorInterface
visits map[string]*visitor
states map[string]*processState
}
Expand All @@ -43,8 +50,9 @@ type visitor struct {

// XXX TODO should state be attached to Process type?
type processState struct {
Monitor int
Starts int
Monitor int
MonitorLock sync.Mutex
Starts int
}

// XXX TODO needed for tests, a form of this should probably be in ConfigManager
Expand All @@ -69,6 +77,7 @@ func (c *ConfigManager) AddProcess(groupName string, process *Process) error {
return nil
}

// BUG(lisbakke): If there are two processes named the same thing in different process groups, this could return the wrong process. ConfigManager should enforce unique group/process names.
// XXX TODO should probably be in configmanager.go
// Helper methods to find a Process by name
func (c *ConfigManager) FindProcess(name string) (*Process, error) {
Expand Down Expand Up @@ -137,6 +146,12 @@ func (c *Control) State(process *Process) *processState {
return c.states[process.Name]
}

// Registers the event monitor with Control so that it can turn event monitoring
// on/off when processes are started/stopped.
func (c *Control) RegisterEventMonitor(eventMonitor *EventMonitor) {
c.EventMonitor = eventMonitor
}

// Invoke given action for the given process and its
// dependents and/or dependencies
func (c *Control) DoAction(name string, action int) error {
Expand All @@ -155,19 +170,19 @@ func (c *Control) DoAction(name string, action int) error {
c.monitorSet(process)
return nil
}
c.doDepend(process, ACTION_STOP, false)
c.doDepend(process, ACTION_STOP)
c.doStart(process)
c.doDepend(process, ACTION_START, false)
c.doDepend(process, ACTION_START)

case ACTION_STOP:
c.doDepend(process, ACTION_STOP, true)
c.doStop(process, true)
c.doDepend(process, ACTION_STOP)
c.doStop(process)

case ACTION_RESTART:
c.doDepend(process, ACTION_STOP, false)
if c.doStop(process, false) {
c.doDepend(process, ACTION_STOP)
if c.doStop(process) {
c.doStart(process)
c.doDepend(process, ACTION_START, false)
c.doDepend(process, ACTION_START)
} else {
c.monitorSet(process)
}
Expand All @@ -176,7 +191,7 @@ func (c *Control) DoAction(name string, action int) error {
c.doMonitor(process)

case ACTION_UNMONITOR:
c.doDepend(process, ACTION_UNMONITOR, false)
c.doDepend(process, ACTION_UNMONITOR)
c.doUnmonitor(process)

default:
Expand Down Expand Up @@ -215,9 +230,8 @@ func (c *Control) doStart(process *Process) {
}

// Stop the given Process.
// Monitoring is disabled when unmonitor flag is true.
// Waits for process to stop or until Process.Timeout is reached.
func (c *Control) doStop(process *Process, unmonitor bool) bool {
func (c *Control) doStop(process *Process) bool {
visitor := c.visitorOf(process)
var rv = true
if visitor.stopped {
Expand All @@ -232,9 +246,7 @@ func (c *Control) doStop(process *Process, unmonitor bool) bool {
}
}

if unmonitor {
c.monitorUnset(process)
}
c.monitorUnset(process)

return rv
}
Expand Down Expand Up @@ -268,7 +280,7 @@ func (c *Control) doUnmonitor(process *Process) {
}

// Apply actions to processes that depend on the given Process
func (c *Control) doDepend(process *Process, action int, unmonitor bool) {
func (c *Control) doDepend(process *Process, action int) {
c.configManager.VisitProcesses(func(child *Process) bool {
for _, dep := range child.DependsOn {
if dep == process.Name {
Expand All @@ -279,11 +291,11 @@ func (c *Control) doDepend(process *Process, action int, unmonitor bool) {
c.doMonitor(child)
}

c.doDepend(child, action, unmonitor)
c.doDepend(child, action)

switch action {
case ACTION_STOP:
c.doStop(child, unmonitor)
c.doStop(child)
case ACTION_UNMONITOR:
c.doUnmonitor(child)
}
Expand All @@ -296,22 +308,32 @@ func (c *Control) doDepend(process *Process, action int, unmonitor bool) {

func (c *Control) monitorSet(process *Process) {
state := c.State(process)

state.MonitorLock.Lock()
defer state.MonitorLock.Unlock()
if state.Monitor == MONITOR_NOT {
state.Monitor = MONITOR_INIT
c.EventMonitor.StartMonitoringProcess(process)
log.Printf("%q monitoring enabled", process.Name)
}
}

func (c *Control) monitorUnset(process *Process) {
state := c.State(process)

state.MonitorLock.Lock()
defer state.MonitorLock.Unlock()
if state.Monitor != MONITOR_NOT {
state.Monitor = MONITOR_NOT
log.Printf("%q monitoring disabled", process.Name)
}
}

func (c *Control) IsMonitoring(process *Process) bool {
state := c.State(process)
state.MonitorLock.Lock()
defer state.MonitorLock.Unlock()
return state.Monitor == MONITOR_INIT || state.Monitor == MONITOR_YES
}

// Poll process for expected state change
func (p *Process) pollState(timeout time.Duration, expect int) bool {
isRunning := false
Expand Down

0 comments on commit cb0d39f

Please sign in to comment.