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.
@@ -40,19 +40,19 @@ module God
40
40
  # a name must be specified
41
41
  if self.name.nil?
42
42
  valid = false
43
- LOG.log(self, :error, "No name was specified")
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
- LOG.log(self, :error, "No valid_states array was specified")
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
- LOG.log(self, :error, "No initial_state was specified")
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
- Syslog.debug(msg)
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
- Syslog.debug(msg)
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
- Syslog.debug(msg)
209
- LOG.log(self, :info, msg)
206
+ applog(self, :info, msg)
210
207
 
211
208
  command.call
212
209
  else
@@ -31,23 +31,30 @@ module God
31
31
 
32
32
  @timer = Thread.new do
33
33
  loop do
34
- # get the current time
35
- t = Time.now.to_i
34
+ begin
35
+ # get the current time
36
+ t = Time.now.to_i
36
37
 
37
- # iterate over each event and trigger any that are due
38
- @events.each do |event|
39
- if t >= event.at
40
- self.trigger(event)
41
- @mutex.synchronize do
42
- @events.delete(event)
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
- # sleep until next check
50
- sleep INTERVAL
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
@@ -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
- Syslog.debug(msg)
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
- Syslog.debug(msg)
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
- Syslog.debug(msg)
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,3 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ loop { puts 'server'; sleep 1 }
@@ -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]
@@ -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
 
@@ -125,7 +125,7 @@ class TestHub < Test::Unit::TestCase
125
125
  end
126
126
  end
127
127
 
128
- def test_handle_poll_should_abort_on_exception
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
- assert_abort do
138
- t = Hub.handle_poll(c)
139
- t.join
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
 
@@ -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
@@ -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.5.0
7
- date: 2007-10-05 00:00:00 -07:00
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