god 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +23 -0
- data/Manifest.txt +9 -0
- data/README.txt +9 -2
- data/Rakefile +8 -1
- data/bin/god +11 -214
- data/examples/single.god +66 -0
- data/ext/god/netlink_handler.c +16 -3
- data/lib/god.rb +153 -17
- data/lib/god/cli/command.rb +189 -0
- data/lib/god/cli/run.rb +120 -0
- data/lib/god/cli/version.rb +23 -0
- data/lib/god/conditions/complex.rb +86 -0
- data/lib/god/conditions/cpu_usage.rb +27 -0
- data/lib/god/conditions/disk_usage.rb +27 -0
- data/lib/god/conditions/flapping.rb +42 -11
- data/lib/god/conditions/http_response_code.rb +63 -3
- data/lib/god/conditions/memory_usage.rb +30 -1
- data/lib/god/conditions/process_exits.rb +24 -2
- data/lib/god/conditions/process_running.rb +32 -0
- data/lib/god/configurable.rb +5 -3
- data/lib/god/event_handler.rb +2 -2
- data/lib/god/hub.rb +12 -19
- data/lib/god/logger.rb +11 -2
- data/lib/god/process.rb +29 -20
- data/lib/god/socket.rb +41 -5
- data/lib/god/task.rb +6 -9
- data/lib/god/timer.rb +20 -13
- data/lib/god/watch.rb +3 -6
- data/test/configs/child_events/child_events.god +1 -1
- data/test/configs/complex/complex.god +59 -0
- data/test/configs/complex/simple_server.rb +3 -0
- data/test/test_conditions_disk_usage.rb +56 -0
- data/test/test_conditions_http_response_code.rb +15 -21
- data/test/test_god.rb +36 -0
- data/test/test_hub.rb +6 -4
- data/test/test_logger.rb +8 -0
- data/test/test_timer.rb +9 -0
- metadata +12 -2
data/lib/god/task.rb
CHANGED
@@ -40,19 +40,19 @@ module God
|
|
40
40
|
# a name must be specified
|
41
41
|
if self.name.nil?
|
42
42
|
valid = false
|
43
|
-
|
43
|
+
applog(self, :error, "No name was specified")
|
44
44
|
end
|
45
45
|
|
46
46
|
# valid_states must be specified
|
47
47
|
if self.valid_states.nil?
|
48
48
|
valid = false
|
49
|
-
|
49
|
+
applog(self, :error, "No valid_states array was specified")
|
50
50
|
end
|
51
51
|
|
52
52
|
# valid_states must be specified
|
53
53
|
if self.initial_state.nil?
|
54
54
|
valid = false
|
55
|
-
|
55
|
+
applog(self, :error, "No initial_state was specified")
|
56
56
|
end
|
57
57
|
|
58
58
|
valid
|
@@ -132,8 +132,7 @@ module God
|
|
132
132
|
from_state = self.state
|
133
133
|
|
134
134
|
msg = "#{self.name} move '#{from_state}' to '#{to_state}'"
|
135
|
-
|
136
|
-
LOG.log(self, :info, msg)
|
135
|
+
applog(self, :info, msg)
|
137
136
|
|
138
137
|
# cleanup from current state
|
139
138
|
self.metrics[from_state].each { |m| m.disable }
|
@@ -199,14 +198,12 @@ module God
|
|
199
198
|
case command
|
200
199
|
when String
|
201
200
|
msg = "#{self.name} #{a}: #{command}"
|
202
|
-
|
203
|
-
LOG.log(self, :info, msg)
|
201
|
+
applog(self, :info, msg)
|
204
202
|
|
205
203
|
system(command)
|
206
204
|
when Proc
|
207
205
|
msg = "#{self.name} #{a}: lambda"
|
208
|
-
|
209
|
-
LOG.log(self, :info, msg)
|
206
|
+
applog(self, :info, msg)
|
210
207
|
|
211
208
|
command.call
|
212
209
|
else
|
data/lib/god/timer.rb
CHANGED
@@ -31,23 +31,30 @@ module God
|
|
31
31
|
|
32
32
|
@timer = Thread.new do
|
33
33
|
loop do
|
34
|
-
|
35
|
-
|
34
|
+
begin
|
35
|
+
# get the current time
|
36
|
+
t = Time.now.to_i
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
# iterate over each event and trigger any that are due
|
39
|
+
@events.each do |event|
|
40
|
+
if t >= event.at
|
41
|
+
self.trigger(event)
|
42
|
+
@mutex.synchronize do
|
43
|
+
@events.delete(event)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
break
|
43
47
|
end
|
44
|
-
else
|
45
|
-
break
|
46
48
|
end
|
47
|
-
end
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
# sleep until next check
|
51
|
+
sleep INTERVAL
|
52
|
+
rescue Exception => e
|
53
|
+
message = format("Unhandled exception (%s): %s\n%s",
|
54
|
+
e.class, e.message, e.backtrace.join("\n"))
|
55
|
+
applog(nil, :fatal, message)
|
56
|
+
sleep INTERVAL
|
57
|
+
end
|
51
58
|
end
|
52
59
|
end
|
53
60
|
end
|
data/lib/god/watch.rb
CHANGED
@@ -123,16 +123,14 @@ module God
|
|
123
123
|
info = b.send("before_#{action}")
|
124
124
|
if info
|
125
125
|
msg = "#{self.name} before_#{action}: #{info} (#{b.base_name})"
|
126
|
-
|
127
|
-
LOG.log(self, :info, msg)
|
126
|
+
applog(self, :info, msg)
|
128
127
|
end
|
129
128
|
end
|
130
129
|
|
131
130
|
# log
|
132
131
|
if self.send(action)
|
133
132
|
msg = "#{self.name} #{action}: #{self.send(action).to_s}"
|
134
|
-
|
135
|
-
LOG.log(self, :info, msg)
|
133
|
+
applog(self, :info, msg)
|
136
134
|
end
|
137
135
|
|
138
136
|
@process.call_action(action)
|
@@ -144,8 +142,7 @@ module God
|
|
144
142
|
info = b.send("after_#{action}")
|
145
143
|
if info
|
146
144
|
msg = "#{self.name} after_#{action}: #{info} (#{b.base_name})"
|
147
|
-
|
148
|
-
LOG.log(self, :info, msg)
|
145
|
+
applog(self, :info, msg)
|
149
146
|
end
|
150
147
|
end
|
151
148
|
end
|
@@ -7,7 +7,7 @@ God.watch do |w|
|
|
7
7
|
w.name = "child-events"
|
8
8
|
w.interval = 5.seconds
|
9
9
|
w.start = File.join(GOD_ROOT, *%w[test configs child_events simple_server.rb])
|
10
|
-
w.log = File.join(GOD_ROOT, *%w[test configs child_events god.log])
|
10
|
+
# w.log = File.join(GOD_ROOT, *%w[test configs child_events god.log])
|
11
11
|
|
12
12
|
# determine the state on startup
|
13
13
|
w.transition(:init, { true => :up, false => :start }) do |on|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
God.watch do |w|
|
2
|
+
w.name = "complex"
|
3
|
+
w.interval = 5.seconds
|
4
|
+
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
|
5
|
+
# w.log = File.join(GOD_ROOT, *%w[test configs child_events god.log])
|
6
|
+
|
7
|
+
# determine the state on startup
|
8
|
+
w.transition(:init, { true => :up, false => :start }) do |on|
|
9
|
+
on.condition(:process_running) do |c|
|
10
|
+
c.running = true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# determine when process has finished starting
|
15
|
+
w.transition([:start, :restart], :up) do |on|
|
16
|
+
on.condition(:process_running) do |c|
|
17
|
+
c.running = true
|
18
|
+
end
|
19
|
+
|
20
|
+
# failsafe
|
21
|
+
on.condition(:tries) do |c|
|
22
|
+
c.times = 2
|
23
|
+
c.transition = :start
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# start if process is not running
|
28
|
+
w.transition(:up, :start) do |on|
|
29
|
+
on.condition(:process_exits)
|
30
|
+
end
|
31
|
+
|
32
|
+
# restart if process is misbehaving
|
33
|
+
w.transition(:up, :restart) do |on|
|
34
|
+
on.condition(:complex) do |cc|
|
35
|
+
cc.and(:cpu_usage) do |c|
|
36
|
+
c.above = 0.percent
|
37
|
+
c.times = 1
|
38
|
+
end
|
39
|
+
|
40
|
+
cc.and(:memory_usage) do |c|
|
41
|
+
c.above = 0.megabytes
|
42
|
+
c.times = 3
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# lifecycle
|
48
|
+
w.lifecycle do |on|
|
49
|
+
on.condition(:flapping) do |c|
|
50
|
+
c.to_state = [:start, :restart]
|
51
|
+
c.times = 5
|
52
|
+
c.within = 20.seconds
|
53
|
+
c.transition = :unmonitored
|
54
|
+
c.retry_in = 10.seconds
|
55
|
+
c.retry_times = 2
|
56
|
+
c.retry_within = 5.minutes
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TestConditionsDiskUsage < Test::Unit::TestCase
|
4
|
+
# valid?
|
5
|
+
|
6
|
+
def test_valid_should_return_false_if_no_above_given
|
7
|
+
c = Conditions::DiskUsage.new
|
8
|
+
c.mount_point = '/'
|
9
|
+
c.watch = stub(:name => 'foo')
|
10
|
+
|
11
|
+
no_stdout do
|
12
|
+
assert_equal false, c.valid?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_valid_should_return_false_if_no_mount_point_given
|
17
|
+
c = Conditions::DiskUsage.new
|
18
|
+
c.above = 90
|
19
|
+
c.watch = stub(:name => 'foo')
|
20
|
+
|
21
|
+
no_stdout do
|
22
|
+
assert_equal false, c.valid?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_valid_should_return_true_if_required_options_all_set
|
27
|
+
c = Conditions::DiskUsage.new
|
28
|
+
c.above = 90
|
29
|
+
c.mount_point = '/'
|
30
|
+
c.watch = stub(:name => 'foo')
|
31
|
+
|
32
|
+
assert_equal true, c.valid?
|
33
|
+
end
|
34
|
+
|
35
|
+
# test
|
36
|
+
|
37
|
+
def test_test_should_return_true_if_above_limit
|
38
|
+
c = Conditions::DiskUsage.new
|
39
|
+
c.above = 90
|
40
|
+
c.mount_point = '/'
|
41
|
+
|
42
|
+
c.expects(:`).returns('91')
|
43
|
+
|
44
|
+
assert_equal true, c.test
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_test_should_return_false_if_below_limit
|
48
|
+
c = Conditions::DiskUsage.new
|
49
|
+
c.above = 90
|
50
|
+
c.mount_point = '/'
|
51
|
+
|
52
|
+
c.expects(:`).returns('90')
|
53
|
+
|
54
|
+
assert_equal false, c.test
|
55
|
+
end
|
56
|
+
end
|
@@ -36,27 +36,6 @@ class TestHttpResponseCode < Test::Unit::TestCase
|
|
36
36
|
no_stdout { assert !c.valid? }
|
37
37
|
end
|
38
38
|
|
39
|
-
def test_valid_should_return_false_if_no_port_set
|
40
|
-
c = valid_condition do |cc|
|
41
|
-
cc.port = nil
|
42
|
-
end
|
43
|
-
no_stdout { assert !c.valid? }
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_valid_should_return_false_if_no_path_set
|
47
|
-
c = valid_condition do |cc|
|
48
|
-
cc.path = nil
|
49
|
-
end
|
50
|
-
no_stdout { assert !c.valid? }
|
51
|
-
end
|
52
|
-
|
53
|
-
def test_valid_should_return_false_if_no_timeout_set
|
54
|
-
c = valid_condition do |cc|
|
55
|
-
cc.timeout = nil
|
56
|
-
end
|
57
|
-
no_stdout { assert !c.valid? }
|
58
|
-
end
|
59
|
-
|
60
39
|
# test
|
61
40
|
|
62
41
|
def test_test_should_return_false_if_code_is_is_set_to_200_but_response_is_500
|
@@ -104,6 +83,21 @@ class TestHttpResponseCode < Test::Unit::TestCase
|
|
104
83
|
assert_equal true, c.test
|
105
84
|
end
|
106
85
|
|
86
|
+
def test_test_should_return_false_if_code_is_is_set_to_200_but_cant_connect
|
87
|
+
c = valid_condition
|
88
|
+
Net::HTTP.expects(:start).raises(Errno::ECONNREFUSED, '')
|
89
|
+
assert_equal false, c.test
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_test_should_return_true_if_code_is_not_is_set_to_200_and_cant_connect
|
93
|
+
c = valid_condition do |cc|
|
94
|
+
cc.code_is = nil
|
95
|
+
cc.code_is_not = [200]
|
96
|
+
end
|
97
|
+
Net::HTTP.expects(:start).raises(Errno::ECONNREFUSED, '')
|
98
|
+
assert_equal true, c.test
|
99
|
+
end
|
100
|
+
|
107
101
|
def test_test_should_return_true_if_code_is_is_set_to_200_and_response_is_200_twice_for_times_two_of_two
|
108
102
|
c = valid_condition do |cc|
|
109
103
|
cc.times = [2, 2]
|
data/test/test_god.rb
CHANGED
@@ -12,6 +12,13 @@ class TestGod < Test::Unit::TestCase
|
|
12
12
|
Timer.get.timer.kill
|
13
13
|
end
|
14
14
|
|
15
|
+
# applog
|
16
|
+
|
17
|
+
def test_applog
|
18
|
+
LOG.expects(:log).with(nil, :debug, 'foo')
|
19
|
+
applog(nil, :debug, 'foo')
|
20
|
+
end
|
21
|
+
|
15
22
|
# internal_init
|
16
23
|
|
17
24
|
def test_init_should_initialize_watches_to_empty_array
|
@@ -297,6 +304,15 @@ class TestGod < Test::Unit::TestCase
|
|
297
304
|
God.control('foo', 'unmonitor')
|
298
305
|
end
|
299
306
|
|
307
|
+
def test_control_should_unwatch_on_remove
|
308
|
+
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
|
309
|
+
|
310
|
+
w = God.watches['foo']
|
311
|
+
w.state = :up
|
312
|
+
God.expects(:unwatch)
|
313
|
+
God.control('foo', 'remove')
|
314
|
+
end
|
315
|
+
|
300
316
|
def test_control_should_raise_on_invalid_command
|
301
317
|
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
|
302
318
|
|
@@ -329,6 +345,15 @@ class TestGod < Test::Unit::TestCase
|
|
329
345
|
# terminate
|
330
346
|
|
331
347
|
def test_terminate_should_exit
|
348
|
+
God.pid = nil
|
349
|
+
FileUtils.expects(:rm_f).never
|
350
|
+
God.expects(:exit!)
|
351
|
+
God.terminate
|
352
|
+
end
|
353
|
+
|
354
|
+
def test_terminate_should_delete_pid
|
355
|
+
God.pid = '/foo/bar'
|
356
|
+
FileUtils.expects(:rm_f).with("/foo/bar")
|
332
357
|
God.expects(:exit!)
|
333
358
|
God.terminate
|
334
359
|
end
|
@@ -504,6 +529,17 @@ class TestGod < Test::Unit::TestCase
|
|
504
529
|
God.expects(:start).once
|
505
530
|
God.at_exit
|
506
531
|
end
|
532
|
+
|
533
|
+
# pattern_match
|
534
|
+
|
535
|
+
def test_pattern_match
|
536
|
+
list = %w{ mongrel-3000 mongrel-3001 fuzed fuzed2 apache mysql}
|
537
|
+
|
538
|
+
assert_equal %w{ mongrel-3000 }, God.pattern_match('m3000', list)
|
539
|
+
assert_equal %w{ mongrel-3001 }, God.pattern_match('m31', list)
|
540
|
+
assert_equal %w{ fuzed fuzed2 }, God.pattern_match('fu', list)
|
541
|
+
assert_equal %w{ mysql }, God.pattern_match('sql', list)
|
542
|
+
end
|
507
543
|
end
|
508
544
|
|
509
545
|
|
data/test/test_hub.rb
CHANGED
@@ -125,7 +125,7 @@ class TestHub < Test::Unit::TestCase
|
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
|
-
def
|
128
|
+
def test_handle_poll_should_not_abort_on_exception
|
129
129
|
c = Conditions::FakePollCondition.new
|
130
130
|
c.interval = 10
|
131
131
|
|
@@ -134,9 +134,11 @@ class TestHub < Test::Unit::TestCase
|
|
134
134
|
|
135
135
|
c.expects(:test).raises(StandardError.new)
|
136
136
|
|
137
|
-
|
138
|
-
|
139
|
-
|
137
|
+
assert_nothing_raised do
|
138
|
+
no_stdout do
|
139
|
+
t = Hub.handle_poll(c)
|
140
|
+
t.join
|
141
|
+
end
|
140
142
|
end
|
141
143
|
end
|
142
144
|
|
data/test/test_logger.rb
CHANGED
@@ -19,6 +19,14 @@ class TestLogger < Test::Unit::TestCase
|
|
19
19
|
assert_match(/qux/, @log.logs['foo'][0][1])
|
20
20
|
end
|
21
21
|
|
22
|
+
def test_log_should_send_to_syslog
|
23
|
+
Syslog.expects(:crit).with('foo')
|
24
|
+
|
25
|
+
no_stdout do
|
26
|
+
@log.log(stub(:name => 'foo'), :fatal, "foo")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
22
30
|
# watch_log_since
|
23
31
|
|
24
32
|
def test_watch_log_since
|
data/test/test_timer.rb
CHANGED
@@ -51,6 +51,15 @@ class TestTimer < Test::Unit::TestCase
|
|
51
51
|
assert_equal 1, @t.events.size
|
52
52
|
end
|
53
53
|
|
54
|
+
def test_time_should_recover_from_exceptions
|
55
|
+
@t.expects(:trigger).raises(Exception.new)
|
56
|
+
no_stdout do
|
57
|
+
@t.schedule(stub(:interval => 0))
|
58
|
+
sleep(0.3)
|
59
|
+
@t.schedule(stub(:interval => 0))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
54
63
|
# join
|
55
64
|
|
56
65
|
def test_join_should_join
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: god
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.6.0
|
7
|
+
date: 2007-12-04 00:00:00 -08:00
|
8
8
|
summary: Like monit, only awesome
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- bin/god
|
38
38
|
- examples/events.god
|
39
39
|
- examples/gravatar.god
|
40
|
+
- examples/single.god
|
40
41
|
- ext/god/extconf.rb
|
41
42
|
- ext/god/kqueue_handler.c
|
42
43
|
- ext/god/netlink_handler.c
|
@@ -45,10 +46,15 @@ files:
|
|
45
46
|
- lib/god/behavior.rb
|
46
47
|
- lib/god/behaviors/clean_pid_file.rb
|
47
48
|
- lib/god/behaviors/notify_when_flapping.rb
|
49
|
+
- lib/god/cli/command.rb
|
50
|
+
- lib/god/cli/run.rb
|
51
|
+
- lib/god/cli/version.rb
|
48
52
|
- lib/god/condition.rb
|
49
53
|
- lib/god/conditions/always.rb
|
54
|
+
- lib/god/conditions/complex.rb
|
50
55
|
- lib/god/conditions/cpu_usage.rb
|
51
56
|
- lib/god/conditions/degrading_lambda.rb
|
57
|
+
- lib/god/conditions/disk_usage.rb
|
52
58
|
- lib/god/conditions/flapping.rb
|
53
59
|
- lib/god/conditions/http_response_code.rb
|
54
60
|
- lib/god/conditions/lambda.rb
|
@@ -82,6 +88,8 @@ files:
|
|
82
88
|
- test/configs/child_events/simple_server.rb
|
83
89
|
- test/configs/child_polls/child_polls.god
|
84
90
|
- test/configs/child_polls/simple_server.rb
|
91
|
+
- test/configs/complex/complex.god
|
92
|
+
- test/configs/complex/simple_server.rb
|
85
93
|
- test/configs/contact/contact.god
|
86
94
|
- test/configs/contact/simple_server.rb
|
87
95
|
- test/configs/daemon_events/daemon_events.god
|
@@ -102,6 +110,7 @@ files:
|
|
102
110
|
- test/suite.rb
|
103
111
|
- test/test_behavior.rb
|
104
112
|
- test/test_condition.rb
|
113
|
+
- test/test_conditions_disk_usage.rb
|
105
114
|
- test/test_conditions_http_response_code.rb
|
106
115
|
- test/test_conditions_process_running.rb
|
107
116
|
- test/test_conditions_tries.rb
|
@@ -126,6 +135,7 @@ files:
|
|
126
135
|
test_files:
|
127
136
|
- test/test_behavior.rb
|
128
137
|
- test/test_condition.rb
|
138
|
+
- test/test_conditions_disk_usage.rb
|
129
139
|
- test/test_conditions_http_response_code.rb
|
130
140
|
- test/test_conditions_process_running.rb
|
131
141
|
- test/test_conditions_tries.rb
|