god 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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