god 0.6.0 → 0.7.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 +67 -1
- data/Manifest.txt +3 -4
- data/Rakefile +1 -1
- data/bin/god +19 -1
- data/lib/god.rb +86 -49
- data/lib/god/cli/command.rb +7 -1
- data/lib/god/cli/run.rb +58 -0
- data/lib/god/condition.rb +6 -2
- data/lib/god/conditions/cpu_usage.rb +7 -6
- data/lib/god/conditions/http_response_code.rb +5 -1
- data/lib/god/conditions/memory_usage.rb +7 -6
- data/lib/god/conditions/process_exits.rb +15 -10
- data/lib/god/conditions/process_running.rb +17 -13
- data/lib/god/diagnostics.rb +37 -0
- data/lib/god/driver.rb +108 -0
- data/lib/god/event_handler.rb +41 -1
- data/lib/god/logger.rb +69 -19
- data/lib/god/metric.rb +2 -2
- data/lib/god/process.rb +84 -27
- data/lib/god/task.rb +286 -29
- data/lib/god/timeline.rb +20 -31
- data/lib/god/watch.rb +26 -15
- data/test/configs/child_events/child_events.god +0 -5
- data/test/configs/child_polls/simple_server.rb +1 -1
- data/test/configs/daemon_events/simple_server_stop.rb +2 -0
- data/test/configs/stress/stress.god +1 -1
- data/test/configs/test.rb +12 -28
- data/test/test_condition.rb +8 -0
- data/test/test_conditions_http_response_code.rb +5 -5
- data/test/test_conditions_process_running.rb +6 -4
- data/test/test_driver.rb +11 -0
- data/test/test_event_handler.rb +7 -0
- data/test/test_god.rb +63 -62
- data/test/test_metric.rb +0 -16
- data/test/test_process.rb +29 -1
- data/test/test_task.rb +177 -1
- data/test/test_timeline.rb +2 -1
- data/test/test_watch.rb +24 -6
- metadata +6 -8
- data/lib/god/hub.rb +0 -222
- data/lib/god/timer.rb +0 -87
- data/test/test_hub.rb +0 -240
- data/test/test_timer.rb +0 -69
data/test/test_metric.rb
CHANGED
@@ -69,20 +69,4 @@ class TestMetric < Test::Unit::TestCase
|
|
69
69
|
@metric.condition(:invalid) { }
|
70
70
|
end
|
71
71
|
end
|
72
|
-
|
73
|
-
# enable
|
74
|
-
|
75
|
-
def test_enable_should_attach_conditions
|
76
|
-
@metric.condition(:fake_poll_condition)
|
77
|
-
Hub.expects(:attach).with(@metric.conditions.first, @metric)
|
78
|
-
@metric.enable
|
79
|
-
end
|
80
|
-
|
81
|
-
# disable
|
82
|
-
|
83
|
-
def test_disable_should_detach_conditions
|
84
|
-
@metric.condition(:fake_poll_condition)
|
85
|
-
Hub.expects(:detach).with(@metric.conditions.first)
|
86
|
-
@metric.disable
|
87
|
-
end
|
88
72
|
end
|
data/test/test_process.rb
CHANGED
@@ -144,6 +144,34 @@ class TestProcessDaemon < Test::Unit::TestCase
|
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
147
|
+
# pid
|
148
|
+
|
149
|
+
def test_pid_should_return_integer_for_valid_pid_files
|
150
|
+
File.stubs(:read).returns("123")
|
151
|
+
assert_equal 123, @p.pid
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_pid_should_return_nil_for_missing_files
|
155
|
+
@p.pid_file = ''
|
156
|
+
assert_equal nil, @p.pid
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_pid_should_return_nil_for_invalid_pid_files
|
160
|
+
File.stubs(:read).returns("four score and seven years ago")
|
161
|
+
assert_equal nil, @p.pid
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_pid_should_retain_last_pid_value_if_pid_file_is_removed
|
165
|
+
File.stubs(:read).returns("123")
|
166
|
+
assert_equal 123, @p.pid
|
167
|
+
|
168
|
+
File.stubs(:read).returns("")
|
169
|
+
assert_equal 123, @p.pid
|
170
|
+
|
171
|
+
File.stubs(:read).returns("246")
|
172
|
+
assert_equal 246, @p.pid
|
173
|
+
end
|
174
|
+
|
147
175
|
# defaul_pid_file
|
148
176
|
|
149
177
|
def test_default_pid_file
|
@@ -156,7 +184,7 @@ class TestProcessDaemon < Test::Unit::TestCase
|
|
156
184
|
def test_call_action_with_string_should_call_system
|
157
185
|
@p.start = "do something"
|
158
186
|
@p.expects(:fork)
|
159
|
-
Process.expects(:
|
187
|
+
Process.expects(:waitpid2).returns([123, 0])
|
160
188
|
@p.call_action(:start)
|
161
189
|
end
|
162
190
|
|
data/test/test_task.rb
CHANGED
@@ -67,20 +67,196 @@ class TestTask < Test::Unit::TestCase
|
|
67
67
|
|
68
68
|
def test_action_should_send_string_commands_to_system
|
69
69
|
@task.foo = 'foo'
|
70
|
+
Thread.current.stubs(:==).returns(true)
|
70
71
|
@task.expects(:system).with('foo')
|
71
72
|
no_stdout { @task.action(:foo, nil) }
|
72
73
|
end
|
73
74
|
|
74
|
-
def
|
75
|
+
def test_action_should_call_lambda_commands
|
75
76
|
@task.foo = lambda { }
|
77
|
+
Thread.current.stubs(:==).returns(true)
|
76
78
|
@task.foo.expects(:call)
|
77
79
|
no_stdout { @task.action(:foo, nil) }
|
78
80
|
end
|
79
81
|
|
80
82
|
def test_action_should_raise_not_implemented_on_non_string_or_lambda_action
|
83
|
+
Thread.current.stubs(:==).returns(true)
|
81
84
|
assert_raise NotImplementedError do
|
82
85
|
@task.foo = 7
|
83
86
|
@task.action(:foo, nil)
|
84
87
|
end
|
85
88
|
end
|
89
|
+
|
90
|
+
def test_action_from_outside_driver_should_send_message_to_driver
|
91
|
+
@task.foo = 'foo'
|
92
|
+
@task.driver.expects(:message).with(:action, [:foo, nil])
|
93
|
+
@task.action(:foo, nil)
|
94
|
+
end
|
95
|
+
|
96
|
+
# attach
|
97
|
+
|
98
|
+
def test_attach_should_schedule_for_poll_condition
|
99
|
+
c = Conditions::FakePollCondition.new
|
100
|
+
@task.driver.expects(:schedule).with(c, 0)
|
101
|
+
@task.attach(c)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_attach_should_regsiter_for_event_condition
|
105
|
+
c = Conditions::FakeEventCondition.new
|
106
|
+
c.expects(:register)
|
107
|
+
@task.attach(c)
|
108
|
+
end
|
109
|
+
|
110
|
+
# detach
|
111
|
+
|
112
|
+
def test_detach_should_reset_poll_condition
|
113
|
+
c = Conditions::FakePollCondition.new
|
114
|
+
c.expects(:reset)
|
115
|
+
c.expects(:deregister).never
|
116
|
+
@task.detach(c)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_detach_should_deregister_event_conditions
|
120
|
+
c = Conditions::FakeEventCondition.new
|
121
|
+
c.expects(:deregister).once
|
122
|
+
@task.detach(c)
|
123
|
+
end
|
124
|
+
|
125
|
+
# trigger
|
126
|
+
|
127
|
+
def test_trigger_should_send_message_to_driver
|
128
|
+
c = Conditions::FakePollCondition.new
|
129
|
+
@task.driver.expects(:message).with(:handle_event, [c])
|
130
|
+
@task.trigger(c)
|
131
|
+
end
|
132
|
+
|
133
|
+
# handle_poll
|
134
|
+
|
135
|
+
def test_handle_poll_no_change_should_reschedule
|
136
|
+
c = Conditions::FakePollCondition.new
|
137
|
+
c.watch = @task
|
138
|
+
c.interval = 10
|
139
|
+
|
140
|
+
m = Metric.new(@task, {true => :up})
|
141
|
+
@task.directory[c] = m
|
142
|
+
|
143
|
+
c.expects(:test).returns(false)
|
144
|
+
@task.driver.expects(:schedule)
|
145
|
+
|
146
|
+
no_stdout do
|
147
|
+
@task.handle_poll(c)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_handle_poll_change_should_move
|
152
|
+
c = Conditions::FakePollCondition.new
|
153
|
+
c.watch = @task
|
154
|
+
c.interval = 10
|
155
|
+
|
156
|
+
m = Metric.new(@task, {true => :up})
|
157
|
+
@task.directory[c] = m
|
158
|
+
|
159
|
+
c.expects(:test).returns(true)
|
160
|
+
@task.expects(:move).with(:up)
|
161
|
+
|
162
|
+
no_stdout do
|
163
|
+
@task.handle_poll(c)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_handle_poll_should_use_overridden_transition
|
168
|
+
c = Conditions::Tries.new
|
169
|
+
c.watch = @task
|
170
|
+
c.times = 1
|
171
|
+
c.transition = :start
|
172
|
+
c.prepare
|
173
|
+
|
174
|
+
m = Metric.new(@task, {true => :up})
|
175
|
+
@task.directory[c] = m
|
176
|
+
|
177
|
+
@task.expects(:move).with(:start)
|
178
|
+
|
179
|
+
no_stdout do
|
180
|
+
@task.handle_poll(c)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_handle_poll_should_notify_if_triggering
|
185
|
+
c = Conditions::FakePollCondition.new
|
186
|
+
c.watch = @task
|
187
|
+
c.interval = 10
|
188
|
+
c.notify = 'tom'
|
189
|
+
|
190
|
+
m = Metric.new(@task, {true => :up})
|
191
|
+
@task.directory[c] = m
|
192
|
+
|
193
|
+
c.expects(:test).returns(true)
|
194
|
+
@task.expects(:notify)
|
195
|
+
|
196
|
+
no_stdout do
|
197
|
+
@task.handle_poll(c)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_handle_poll_should_not_notify_if_not_triggering
|
202
|
+
c = Conditions::FakePollCondition.new
|
203
|
+
c.watch = @task
|
204
|
+
c.interval = 10
|
205
|
+
c.notify = 'tom'
|
206
|
+
|
207
|
+
m = Metric.new(@task, {true => :up})
|
208
|
+
@task.directory[c] = m
|
209
|
+
|
210
|
+
c.expects(:test).returns(false)
|
211
|
+
@task.expects(:notify).never
|
212
|
+
|
213
|
+
no_stdout do
|
214
|
+
@task.handle_poll(c)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# handle_event
|
219
|
+
|
220
|
+
def test_handle_event_should_move
|
221
|
+
c = Conditions::FakeEventCondition.new
|
222
|
+
c.watch = @task
|
223
|
+
|
224
|
+
m = Metric.new(@task, {true => :up})
|
225
|
+
@task.directory[c] = m
|
226
|
+
|
227
|
+
@task.expects(:move).with(:up)
|
228
|
+
|
229
|
+
no_stdout do
|
230
|
+
@task.handle_event(c)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_handle_event_should_notify_if_triggering
|
235
|
+
c = Conditions::FakeEventCondition.new
|
236
|
+
c.watch = @task
|
237
|
+
c.notify = 'tom'
|
238
|
+
|
239
|
+
m = Metric.new(@task, {true => :up})
|
240
|
+
@task.directory[c] = m
|
241
|
+
|
242
|
+
@task.expects(:notify)
|
243
|
+
|
244
|
+
no_stdout do
|
245
|
+
@task.handle_event(c)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_handle_event_should_not_notify_if_no_notify_set
|
250
|
+
c = Conditions::FakeEventCondition.new
|
251
|
+
c.watch = @task
|
252
|
+
|
253
|
+
m = Metric.new(@task, {true => :up})
|
254
|
+
@task.directory[c] = m
|
255
|
+
|
256
|
+
@task.expects(:notify).never
|
257
|
+
|
258
|
+
no_stdout do
|
259
|
+
@task.handle_event(c)
|
260
|
+
end
|
261
|
+
end
|
86
262
|
end
|
data/test/test_timeline.rb
CHANGED
data/test/test_watch.rb
CHANGED
@@ -37,12 +37,6 @@ class TestWatch < Test::Unit::TestCase
|
|
37
37
|
assert_equal :unmonitored, @watch.state
|
38
38
|
end
|
39
39
|
|
40
|
-
# mutex
|
41
|
-
|
42
|
-
def test_mutex_should_return_the_same_mutex_each_time
|
43
|
-
assert_equal @watch.mutex, @watch.mutex
|
44
|
-
end
|
45
|
-
|
46
40
|
# valid?
|
47
41
|
|
48
42
|
def test_valid?
|
@@ -132,6 +126,9 @@ class TestWatch < Test::Unit::TestCase
|
|
132
126
|
# move
|
133
127
|
|
134
128
|
def test_move_should_not_clean_up_if_from_state_is_nil
|
129
|
+
Thread.current.stubs(:==).returns(true)
|
130
|
+
@watch.driver.expects(:message).never
|
131
|
+
|
135
132
|
metric = nil
|
136
133
|
|
137
134
|
@watch.instance_eval do
|
@@ -150,6 +147,9 @@ class TestWatch < Test::Unit::TestCase
|
|
150
147
|
end
|
151
148
|
|
152
149
|
def test_move_should_clean_up_from_state_if_not_nil
|
150
|
+
Thread.current.stubs(:==).returns(true)
|
151
|
+
@watch.driver.expects(:message).never
|
152
|
+
|
153
153
|
metric = nil
|
154
154
|
|
155
155
|
@watch.instance_eval do
|
@@ -170,12 +170,18 @@ class TestWatch < Test::Unit::TestCase
|
|
170
170
|
end
|
171
171
|
|
172
172
|
def test_move_should_call_action
|
173
|
+
Thread.current.stubs(:==).returns(true)
|
174
|
+
@watch.driver.expects(:message).never
|
175
|
+
|
173
176
|
@watch.expects(:action).with(:start)
|
174
177
|
|
175
178
|
no_stdout { @watch.move(:start) }
|
176
179
|
end
|
177
180
|
|
178
181
|
def test_move_should_move_to_up_state_if_no_start_or_restart_metric
|
182
|
+
Thread.current.stubs(:==).returns(true)
|
183
|
+
@watch.driver.expects(:message).never
|
184
|
+
|
179
185
|
[:start, :restart].each do |state|
|
180
186
|
@watch.expects(:action)
|
181
187
|
no_stdout { @watch.move(state) }
|
@@ -184,6 +190,9 @@ class TestWatch < Test::Unit::TestCase
|
|
184
190
|
end
|
185
191
|
|
186
192
|
def test_move_should_enable_destination_metric
|
193
|
+
Thread.current.stubs(:==).returns(true)
|
194
|
+
@watch.driver.expects(:message).never
|
195
|
+
|
187
196
|
metric = nil
|
188
197
|
|
189
198
|
@watch.instance_eval do
|
@@ -204,6 +213,9 @@ class TestWatch < Test::Unit::TestCase
|
|
204
213
|
# action
|
205
214
|
|
206
215
|
def test_action_should_pass_start_and_stop_actions_to_call_action
|
216
|
+
Thread.current.stubs(:==).returns(true)
|
217
|
+
@watch.driver.expects(:message).never
|
218
|
+
|
207
219
|
c = Conditions::FakePollCondition.new
|
208
220
|
[:start, :stop].each do |cmd|
|
209
221
|
@watch.expects(:call_action).with(c, cmd)
|
@@ -212,6 +224,9 @@ class TestWatch < Test::Unit::TestCase
|
|
212
224
|
end
|
213
225
|
|
214
226
|
def test_action_should_do_stop_then_start_if_no_restart_command
|
227
|
+
Thread.current.stubs(:==).returns(true)
|
228
|
+
@watch.driver.expects(:message).never
|
229
|
+
|
215
230
|
c = Conditions::FakePollCondition.new
|
216
231
|
@watch.expects(:call_action).with(c, :stop)
|
217
232
|
@watch.expects(:call_action).with(c, :start)
|
@@ -219,6 +234,9 @@ class TestWatch < Test::Unit::TestCase
|
|
219
234
|
end
|
220
235
|
|
221
236
|
def test_action_should_restart_to_call_action_if_present
|
237
|
+
Thread.current.stubs(:==).returns(true)
|
238
|
+
@watch.driver.expects(:message).never
|
239
|
+
|
222
240
|
@watch.restart = lambda { }
|
223
241
|
c = Conditions::FakePollCondition.new
|
224
242
|
@watch.expects(:call_action).with(c, :restart)
|
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:
|
6
|
+
version: 0.7.0
|
7
|
+
date: 2008-02-01 00:00:00 -08:00
|
8
8
|
summary: Like monit, only awesome
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -66,12 +66,13 @@ files:
|
|
66
66
|
- lib/god/contact.rb
|
67
67
|
- lib/god/contacts/email.rb
|
68
68
|
- lib/god/dependency_graph.rb
|
69
|
+
- lib/god/diagnostics.rb
|
70
|
+
- lib/god/driver.rb
|
69
71
|
- lib/god/errors.rb
|
70
72
|
- lib/god/event_handler.rb
|
71
73
|
- lib/god/event_handlers/dummy_handler.rb
|
72
74
|
- lib/god/event_handlers/kqueue_handler.rb
|
73
75
|
- lib/god/event_handlers/netlink_handler.rb
|
74
|
-
- lib/god/hub.rb
|
75
76
|
- lib/god/logger.rb
|
76
77
|
- lib/god/metric.rb
|
77
78
|
- lib/god/process.rb
|
@@ -81,7 +82,6 @@ files:
|
|
81
82
|
- lib/god/system/process.rb
|
82
83
|
- lib/god/task.rb
|
83
84
|
- lib/god/timeline.rb
|
84
|
-
- lib/god/timer.rb
|
85
85
|
- lib/god/trigger.rb
|
86
86
|
- lib/god/watch.rb
|
87
87
|
- test/configs/child_events/child_events.god
|
@@ -116,10 +116,10 @@ files:
|
|
116
116
|
- test/test_conditions_tries.rb
|
117
117
|
- test/test_contact.rb
|
118
118
|
- test/test_dependency_graph.rb
|
119
|
+
- test/test_driver.rb
|
119
120
|
- test/test_event_handler.rb
|
120
121
|
- test/test_god.rb
|
121
122
|
- test/test_handlers_kqueue_handler.rb
|
122
|
-
- test/test_hub.rb
|
123
123
|
- test/test_logger.rb
|
124
124
|
- test/test_metric.rb
|
125
125
|
- test/test_process.rb
|
@@ -129,7 +129,6 @@ files:
|
|
129
129
|
- test/test_system_process.rb
|
130
130
|
- test/test_task.rb
|
131
131
|
- test/test_timeline.rb
|
132
|
-
- test/test_timer.rb
|
133
132
|
- test/test_trigger.rb
|
134
133
|
- test/test_watch.rb
|
135
134
|
test_files:
|
@@ -141,10 +140,10 @@ test_files:
|
|
141
140
|
- test/test_conditions_tries.rb
|
142
141
|
- test/test_contact.rb
|
143
142
|
- test/test_dependency_graph.rb
|
143
|
+
- test/test_driver.rb
|
144
144
|
- test/test_event_handler.rb
|
145
145
|
- test/test_god.rb
|
146
146
|
- test/test_handlers_kqueue_handler.rb
|
147
|
-
- test/test_hub.rb
|
148
147
|
- test/test_logger.rb
|
149
148
|
- test/test_metric.rb
|
150
149
|
- test/test_process.rb
|
@@ -154,7 +153,6 @@ test_files:
|
|
154
153
|
- test/test_system_process.rb
|
155
154
|
- test/test_task.rb
|
156
155
|
- test/test_timeline.rb
|
157
|
-
- test/test_timer.rb
|
158
156
|
- test/test_trigger.rb
|
159
157
|
- test/test_watch.rb
|
160
158
|
rdoc_options:
|
data/lib/god/hub.rb
DELETED
@@ -1,222 +0,0 @@
|
|
1
|
-
module God
|
2
|
-
|
3
|
-
class Hub
|
4
|
-
class << self
|
5
|
-
# directory to hold conditions and their corresponding metric
|
6
|
-
# {condition => metric}
|
7
|
-
attr_accessor :directory
|
8
|
-
end
|
9
|
-
|
10
|
-
self.directory = {}
|
11
|
-
|
12
|
-
def self.attach(condition, metric)
|
13
|
-
self.directory[condition] = metric
|
14
|
-
condition.reset
|
15
|
-
|
16
|
-
case condition
|
17
|
-
when PollCondition
|
18
|
-
Timer.get.schedule(condition, 0)
|
19
|
-
when EventCondition, TriggerCondition
|
20
|
-
condition.register
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.detach(condition)
|
25
|
-
self.directory.delete(condition)
|
26
|
-
|
27
|
-
case condition
|
28
|
-
when PollCondition
|
29
|
-
Timer.get.unschedule(condition)
|
30
|
-
when EventCondition, TriggerCondition
|
31
|
-
condition.deregister
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.trigger(condition)
|
36
|
-
case condition
|
37
|
-
when PollCondition
|
38
|
-
self.handle_poll(condition)
|
39
|
-
when EventCondition, TriggerCondition
|
40
|
-
self.handle_event(condition)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.handle_poll(condition)
|
45
|
-
Thread.new do
|
46
|
-
begin
|
47
|
-
metric = self.directory[condition]
|
48
|
-
|
49
|
-
# it's possible that the timer will trigger an event before it can be cleared
|
50
|
-
# by an exiting metric, in which case it should be ignored
|
51
|
-
unless metric.nil?
|
52
|
-
watch = metric.watch
|
53
|
-
|
54
|
-
watch.mutex.synchronize do
|
55
|
-
# run the test
|
56
|
-
result = condition.test
|
57
|
-
|
58
|
-
# log
|
59
|
-
messages = self.log(watch, metric, condition, result)
|
60
|
-
|
61
|
-
# notify
|
62
|
-
if condition.notify && self.trigger?(metric, result)
|
63
|
-
self.notify(condition, messages.last)
|
64
|
-
end
|
65
|
-
|
66
|
-
# after-condition
|
67
|
-
condition.after
|
68
|
-
|
69
|
-
# get the destination
|
70
|
-
dest =
|
71
|
-
if result && condition.transition
|
72
|
-
# condition override
|
73
|
-
condition.transition
|
74
|
-
else
|
75
|
-
# regular
|
76
|
-
metric.destination && metric.destination[result]
|
77
|
-
end
|
78
|
-
|
79
|
-
# transition or reschedule
|
80
|
-
if dest
|
81
|
-
# transition
|
82
|
-
begin
|
83
|
-
watch.move(dest)
|
84
|
-
rescue EventRegistrationFailedError
|
85
|
-
msg = watch.name + ' Event registration failed, moving back to previous state'
|
86
|
-
applog(watch, :info, msg)
|
87
|
-
|
88
|
-
dest = watch.state
|
89
|
-
retry
|
90
|
-
end
|
91
|
-
else
|
92
|
-
# reschedule
|
93
|
-
Timer.get.schedule(condition)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
rescue Exception => e
|
98
|
-
message = format("Unhandled exception (%s): %s\n%s",
|
99
|
-
e.class, e.message, e.backtrace.join("\n"))
|
100
|
-
applog(nil, :fatal, message)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.handle_event(condition)
|
106
|
-
Thread.new do
|
107
|
-
begin
|
108
|
-
metric = self.directory[condition]
|
109
|
-
|
110
|
-
unless metric.nil?
|
111
|
-
watch = metric.watch
|
112
|
-
|
113
|
-
watch.mutex.synchronize do
|
114
|
-
# log
|
115
|
-
messages = self.log(watch, metric, condition, true)
|
116
|
-
|
117
|
-
# notify
|
118
|
-
if condition.notify && self.trigger?(metric, true)
|
119
|
-
self.notify(condition, messages.last)
|
120
|
-
end
|
121
|
-
|
122
|
-
# get the destination
|
123
|
-
dest =
|
124
|
-
if condition.transition
|
125
|
-
# condition override
|
126
|
-
condition.transition
|
127
|
-
else
|
128
|
-
# regular
|
129
|
-
metric.destination && metric.destination[true]
|
130
|
-
end
|
131
|
-
|
132
|
-
if dest
|
133
|
-
watch.move(dest)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
rescue Exception => e
|
138
|
-
message = format("Unhandled exception (%s): %s\n%s",
|
139
|
-
e.class, e.message, e.backtrace.join("\n"))
|
140
|
-
applog(nil, :fatal, message)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# helpers
|
146
|
-
|
147
|
-
def self.trigger?(metric, result)
|
148
|
-
(metric.destination && metric.destination.keys.size == 2) || result == true
|
149
|
-
end
|
150
|
-
|
151
|
-
def self.log(watch, metric, condition, result)
|
152
|
-
status =
|
153
|
-
if self.trigger?(metric, result)
|
154
|
-
"[trigger]"
|
155
|
-
else
|
156
|
-
"[ok]"
|
157
|
-
end
|
158
|
-
|
159
|
-
messages = []
|
160
|
-
|
161
|
-
# log info if available
|
162
|
-
if condition.info
|
163
|
-
Array(condition.info).each do |condition_info|
|
164
|
-
messages << "#{watch.name} #{status} #{condition_info} (#{condition.base_name})"
|
165
|
-
applog(watch, :info, messages.last)
|
166
|
-
end
|
167
|
-
else
|
168
|
-
messages << "#{watch.name} #{status} (#{condition.base_name})"
|
169
|
-
applog(watch, :info, messages.last)
|
170
|
-
end
|
171
|
-
|
172
|
-
# log
|
173
|
-
debug_message = watch.name + ' ' + condition.base_name + " [#{result}] " + self.dest_desc(metric, condition)
|
174
|
-
applog(watch, :debug, debug_message)
|
175
|
-
|
176
|
-
messages
|
177
|
-
end
|
178
|
-
|
179
|
-
def self.dest_desc(metric, condition)
|
180
|
-
if condition.transition
|
181
|
-
{true => condition.transition}.inspect
|
182
|
-
else
|
183
|
-
if metric.destination
|
184
|
-
metric.destination.inspect
|
185
|
-
else
|
186
|
-
'none'
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def self.notify(condition, message)
|
192
|
-
spec = Contact.normalize(condition.notify)
|
193
|
-
unmatched = []
|
194
|
-
|
195
|
-
# resolve contacts
|
196
|
-
resolved_contacts =
|
197
|
-
spec[:contacts].inject([]) do |acc, contact_name_or_group|
|
198
|
-
cons = Array(God.contacts[contact_name_or_group] || God.contact_groups[contact_name_or_group])
|
199
|
-
unmatched << contact_name_or_group if cons.empty?
|
200
|
-
acc += cons
|
201
|
-
acc
|
202
|
-
end
|
203
|
-
|
204
|
-
# warn about unmatched contacts
|
205
|
-
unless unmatched.empty?
|
206
|
-
msg = "#{condition.watch.name} no matching contacts for '#{unmatched.join(", ")}'"
|
207
|
-
applog(condition.watch, :warn, msg)
|
208
|
-
end
|
209
|
-
|
210
|
-
# notify each contact
|
211
|
-
resolved_contacts.each do |c|
|
212
|
-
host = `hostname`.chomp rescue 'none'
|
213
|
-
c.notify(message, Time.now, spec[:priority], spec[:category], host)
|
214
|
-
|
215
|
-
msg = "#{condition.watch.name} #{c.info ? c.info : "notification sent for contact: #{c.name}"} (#{c.base_name})"
|
216
|
-
|
217
|
-
applog(condition.watch, :info, msg % [])
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
end
|