fix problem where triggered events could call the hub even after a state change
[god.git] / lib / god.rb
blob573cdeecd9f10e73f1fc65352326c4f83fb8b83e
1 $:.unshift File.dirname(__FILE__)     # For use/testing when no gem is installed
3 require 'syslog'
5 # internal requires
6 require 'god/errors'
8 require 'god/system/process'
10 require 'god/behavior'
11 require 'god/behaviors/clean_pid_file'
13 require 'god/condition'
14 require 'god/conditions/timeline'
15 require 'god/conditions/process_running'
16 require 'god/conditions/process_exits'
17 require 'god/conditions/memory_usage'
18 require 'god/conditions/cpu_usage'
19 require 'god/conditions/always'
21 require 'god/reporter'
22 require 'god/server'
23 require 'god/timer'
24 require 'god/hub'
26 require 'god/metric'
27 require 'god/watch'
29 require 'god/event_handler'
30 require 'god/registry'
31 require 'god/process'
33 require 'god/sugar'
35 $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext god])
37 begin
38   Syslog.open('god')
39 rescue RuntimeError
40   Syslog.reopen('god')
41 end
43 God::EventHandler.load
45 module God
46   VERSION = '0.3.0'
47   
48   class << self
49     attr_accessor :inited, :host, :port
50     
51     # drb
52     attr_accessor :server
53     
54     # api
55     attr_accessor :watches, :groups
56   end
57   
58   def self.init
59     # only do this once
60     return if self.inited
61     
62     # variable init
63     self.watches = {}
64     self.groups = {}
65     
66     # yield to the config file
67     yield self if block_given?
68     
69     # instantiate server
70     self.server = Server.new(self.host, self.port)
71     
72     # init has been executed
73     self.inited = true
74   end
75     
76   # Where pid files created by god will go by default
77   def self.pid_file_directory
78     @pid_file_directory ||= '/var/run/god'
79   end
80   
81   def self.pid_file_directory=(value)
82     @pid_file_directory = value
83   end
84   
85   # Instantiate a new, empty Watch object and pass it to the mandatory
86   # block. The attributes of the watch will be set by the configuration
87   # file.
88   def self.watch
89     self.init
90     
91     w = Watch.new
92     yield(w)
93     
94     # ensure the new watch has a unique name
95     if self.watches[w.name] || self.groups[w.name]
96       abort "Watch name '#{w.name}' already used for a Watch or Group"
97     end
98     
99     # add to list of watches
100     self.watches[w.name] = w
101     
102     # add to group if specified
103     if w.group
104       # ensure group name hasn't been used for a watch already
105       if self.watches[w.group]
106         abort "Group name '#{w.group}' already used for a Watch"
107       end
108     
109       self.groups[w.group] ||= []
110       self.groups[w.group] << w.name
111     end
113     # register watch
114     w.register!
115   end
116   
117   def self.control(name, command)
118     # get the list of watches
119     watches = Array(self.watches[name] || self.groups[name])
120   
121     # do the command
122     case command
123       when "start", "monitor"
124         watches.each { |w| w.monitor }
125       when "restart"
126         watches.each { |w| w.move(:restart) }
127       when "stop"
128         watches.each { |w| w.unmonitor.action(:stop) }
129       when "unmonitor"
130         watches.each { |w| w.unmonitor }
131       else
132         raise InvalidCommandError.new
133     end
134     
135     watches
136   end
137     
138   def self.start
139     # make sure there's something to do
140     if self.watches.nil? || self.watches.empty?
141       abort "You must specify at least one watch!"
142     end
143     
144     # start event handler system
145     EventHandler.start if EventHandler.loaded?
146     
147     # start the timer system
148     Timer.get
150     # start monitoring any watches set to autostart
151     self.watches.values.each { |w| w.monitor if w.autostart? }
152     
153     # join the timer thread so we don't exit
154     Timer.get.join
155   end
156   
157   def self.at_exit
158     self.start
159   end
160   
161   def self.load(glob)
162     Dir[glob].each do |f|
163       Kernel.load f
164     end
165   end
168 at_exit do
169   God.at_exit