resurrected_god 0.14.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +559 -0
- data/README.md +9 -4
- data/bin/god +26 -28
- data/ext/god/extconf.rb +9 -9
- data/lib/god/behavior.rb +3 -5
- data/lib/god/behaviors/clean_pid_file.rb +4 -6
- data/lib/god/behaviors/clean_unix_socket.rb +4 -6
- data/lib/god/behaviors/notify_when_flapping.rb +13 -15
- data/lib/god/cli/command.rb +109 -89
- data/lib/god/cli/run.rb +51 -75
- data/lib/god/cli/version.rb +2 -4
- data/lib/god/condition.rb +12 -14
- data/lib/god/conditions/always.rb +3 -2
- data/lib/god/conditions/complex.rb +23 -24
- data/lib/god/conditions/cpu_usage.rb +12 -16
- data/lib/god/conditions/degrading_lambda.rb +15 -19
- data/lib/god/conditions/disk_usage.rb +7 -8
- data/lib/god/conditions/file_mtime.rb +3 -7
- data/lib/god/conditions/file_touched.rb +4 -5
- data/lib/god/conditions/flapping.rb +57 -62
- data/lib/god/conditions/http_response_code.rb +27 -32
- data/lib/god/conditions/lambda.rb +3 -5
- data/lib/god/conditions/memory_usage.rb +12 -16
- data/lib/god/conditions/process_exits.rb +12 -12
- data/lib/god/conditions/process_running.rb +8 -10
- data/lib/god/conditions/socket_responding.rb +23 -28
- data/lib/god/conditions/tries.rb +12 -14
- data/lib/god/configurable.rb +7 -10
- data/lib/god/contact.rb +41 -52
- data/lib/god/contacts/airbrake.rb +10 -12
- data/lib/god/contacts/campfire.rb +18 -20
- data/lib/god/contacts/email.rb +27 -28
- data/lib/god/contacts/prowl.rb +16 -17
- data/lib/god/contacts/scout.rb +2 -5
- data/lib/god/contacts/sensu.rb +15 -11
- data/lib/god/contacts/slack.rb +23 -33
- data/lib/god/contacts/statsd.rb +8 -8
- data/lib/god/contacts/twitter.rb +2 -2
- data/lib/god/contacts/webhook.rb +21 -24
- data/lib/god/driver.rb +12 -18
- data/lib/god/errors.rb +0 -2
- data/lib/god/event_handler.rb +40 -49
- data/lib/god/event_handlers/dummy_handler.rb +1 -1
- data/lib/god/event_handlers/kqueue_handler.rb +2 -2
- data/lib/god/event_handlers/netlink_handler.rb +1 -1
- data/lib/god/logger.rb +5 -13
- data/lib/god/metric.rb +13 -15
- data/lib/god/process.rb +93 -98
- data/lib/god/simple_logger.rb +13 -15
- data/lib/god/socket.rb +21 -23
- data/lib/god/sugar.rb +8 -8
- data/lib/god/sys_logger.rb +6 -8
- data/lib/god/system/portable_poller.rb +1 -9
- data/lib/god/system/process.rb +4 -6
- data/lib/god/system/slash_proc_poller.rb +17 -19
- data/lib/god/task.rb +110 -136
- data/lib/god/timeline.rb +2 -4
- data/lib/god/trigger.rb +7 -11
- data/lib/god/version.rb +1 -1
- data/lib/god/watch.rb +51 -57
- data/lib/god.rb +122 -148
- metadata +17 -370
- data/Announce.txt +0 -135
- data/Gemfile +0 -5
- data/Rakefile +0 -129
- data/doc/god.asciidoc +0 -1592
- data/doc/intro.asciidoc +0 -20
- data/ext/god/.gitignore +0 -5
- data/lib/god/compat19.rb +0 -33
- data/lib/god/contacts/hipchat.rb +0 -117
- data/lib/god/contacts/jabber.rb +0 -75
- data/test/configs/child_events/child_events.god +0 -44
- data/test/configs/child_events/simple_server.rb +0 -3
- data/test/configs/child_polls/child_polls.god +0 -37
- data/test/configs/child_polls/simple_server.rb +0 -12
- data/test/configs/complex/complex.god +0 -59
- data/test/configs/complex/simple_server.rb +0 -3
- data/test/configs/contact/contact.god +0 -118
- data/test/configs/contact/simple_server.rb +0 -3
- data/test/configs/daemon_events/daemon_events.god +0 -37
- data/test/configs/daemon_events/simple_server.rb +0 -8
- data/test/configs/daemon_events/simple_server_stop.rb +0 -11
- data/test/configs/daemon_polls/daemon_polls.god +0 -17
- data/test/configs/daemon_polls/simple_server.rb +0 -6
- data/test/configs/degrading_lambda/degrading_lambda.god +0 -31
- data/test/configs/degrading_lambda/tcp_server.rb +0 -15
- data/test/configs/keepalive/keepalive.god +0 -9
- data/test/configs/keepalive/keepalive.rb +0 -12
- data/test/configs/lifecycle/lifecycle.god +0 -25
- data/test/configs/matias/matias.god +0 -50
- data/test/configs/real.rb +0 -59
- data/test/configs/running_load/running_load.god +0 -16
- data/test/configs/stop_options/simple_server.rb +0 -12
- data/test/configs/stop_options/stop_options.god +0 -39
- data/test/configs/stress/simple_server.rb +0 -3
- data/test/configs/stress/stress.god +0 -15
- data/test/configs/task/logs/.placeholder +0 -0
- data/test/configs/task/task.god +0 -26
- data/test/configs/test.rb +0 -61
- data/test/configs/usr1_trapper.rb +0 -10
- data/test/helper.rb +0 -172
- data/test/suite.rb +0 -6
- data/test/test_airbrake.rb +0 -14
- data/test/test_behavior.rb +0 -18
- data/test/test_campfire.rb +0 -22
- data/test/test_condition.rb +0 -52
- data/test/test_conditions_disk_usage.rb +0 -50
- data/test/test_conditions_http_response_code.rb +0 -109
- data/test/test_conditions_process_running.rb +0 -40
- data/test/test_conditions_socket_responding.rb +0 -176
- data/test/test_conditions_tries.rb +0 -67
- data/test/test_contact.rb +0 -109
- data/test/test_driver.rb +0 -26
- data/test/test_email.rb +0 -34
- data/test/test_event_handler.rb +0 -82
- data/test/test_god.rb +0 -710
- data/test/test_god_system.rb +0 -201
- data/test/test_handlers_kqueue_handler.rb +0 -16
- data/test/test_hipchat.rb +0 -23
- data/test/test_jabber.rb +0 -29
- data/test/test_logger.rb +0 -55
- data/test/test_metric.rb +0 -74
- data/test/test_process.rb +0 -263
- data/test/test_prowl.rb +0 -15
- data/test/test_registry.rb +0 -15
- data/test/test_sensu.rb +0 -11
- data/test/test_slack.rb +0 -57
- data/test/test_socket.rb +0 -34
- data/test/test_statsd.rb +0 -22
- data/test/test_sugar.rb +0 -42
- data/test/test_system_portable_poller.rb +0 -17
- data/test/test_system_process.rb +0 -30
- data/test/test_task.rb +0 -246
- data/test/test_timeline.rb +0 -37
- data/test/test_trigger.rb +0 -63
- data/test/test_watch.rb +0 -286
- data/test/test_webhook.rb +0 -22
@@ -1,13 +1,12 @@
|
|
1
1
|
module God
|
2
2
|
module Conditions
|
3
|
-
|
4
3
|
# Condition Symbol :flapping
|
5
4
|
# Type: Trigger
|
6
5
|
#
|
7
6
|
# Trigger when a Task transitions to or from a state or states a given number
|
8
7
|
# of times within a given period.
|
9
8
|
#
|
10
|
-
#
|
9
|
+
# Parameters
|
11
10
|
# Required
|
12
11
|
# +times+ is the number of times that the Task must transition before
|
13
12
|
# triggering.
|
@@ -17,7 +16,7 @@ module God
|
|
17
16
|
# your code (see examples).
|
18
17
|
# --one or both of--
|
19
18
|
# +from_state+ is the state (as a Symbol) from which the transition must occur.
|
20
|
-
# +to_state is the state (as a Symbol) to which the transition must occur.
|
19
|
+
# +to_state+ is the state (as a Symbol) to which the transition must occur.
|
21
20
|
#
|
22
21
|
# Optional:
|
23
22
|
# +retry_in+ is the number of seconds after which to re-monitor the Task after
|
@@ -39,90 +38,86 @@ module God
|
|
39
38
|
:retry_within
|
40
39
|
|
41
40
|
def initialize
|
42
|
-
|
41
|
+
super
|
42
|
+
self.info = 'process is flapping'
|
43
43
|
end
|
44
44
|
|
45
45
|
def prepare
|
46
|
-
@timeline = Timeline.new(
|
47
|
-
@retry_timeline = Timeline.new(
|
46
|
+
@timeline = Timeline.new(times)
|
47
|
+
@retry_timeline = Timeline.new(retry_times)
|
48
48
|
end
|
49
49
|
|
50
50
|
def valid?
|
51
51
|
valid = true
|
52
|
-
valid &= complain("Attribute 'times' must be specified", self) if
|
53
|
-
valid &= complain("Attribute 'within' must be specified", self) if
|
54
|
-
valid &= complain("Attributes 'from_state', 'to_state', or both must be specified", self) if
|
52
|
+
valid &= complain("Attribute 'times' must be specified", self) if times.nil?
|
53
|
+
valid &= complain("Attribute 'within' must be specified", self) if within.nil?
|
54
|
+
valid &= complain("Attributes 'from_state', 'to_state', or both must be specified", self) if from_state.nil? && to_state.nil?
|
55
55
|
valid
|
56
56
|
end
|
57
57
|
|
58
58
|
def process(event, payload)
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
return if event != :state_change
|
60
|
+
|
61
|
+
event_from_state, event_to_state = *payload
|
62
62
|
|
63
|
-
|
64
|
-
|
63
|
+
from_state_match = !from_state || Array(from_state).include?(event_from_state)
|
64
|
+
to_state_match = !to_state || Array(to_state).include?(event_to_state)
|
65
65
|
|
66
|
-
|
67
|
-
|
66
|
+
if from_state_match && to_state_match
|
67
|
+
@timeline << Time.now
|
68
68
|
|
69
|
-
|
70
|
-
|
69
|
+
consensus = (@timeline.size == times)
|
70
|
+
duration = (@timeline.last - @timeline.first) < within
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
72
|
+
if consensus && duration
|
73
|
+
@timeline.clear
|
74
|
+
trigger
|
75
|
+
retry_mechanism
|
78
76
|
end
|
79
|
-
rescue => e
|
80
|
-
puts e.message
|
81
|
-
puts e.backtrace.join("\n")
|
82
77
|
end
|
78
|
+
rescue => e
|
79
|
+
puts e.message
|
80
|
+
puts e.backtrace.join("\n")
|
83
81
|
end
|
84
82
|
|
85
83
|
private
|
86
84
|
|
87
85
|
def retry_mechanism
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
121
|
-
end
|
86
|
+
return unless retry_in
|
87
|
+
|
88
|
+
@retry_timeline << Time.now
|
89
|
+
|
90
|
+
consensus = (@retry_timeline.size == retry_times)
|
91
|
+
duration = (@retry_timeline.last - @retry_timeline.first) < retry_within
|
92
|
+
|
93
|
+
if consensus && duration
|
94
|
+
# give up
|
95
|
+
Thread.new do
|
96
|
+
sleep 1
|
97
|
+
|
98
|
+
# log
|
99
|
+
msg = "#{watch.name} giving up"
|
100
|
+
applog(watch, :info, msg)
|
101
|
+
end
|
102
|
+
else
|
103
|
+
# try again later
|
104
|
+
Thread.new do
|
105
|
+
sleep 1
|
106
|
+
|
107
|
+
# log
|
108
|
+
msg = "#{watch.name} auto-reenable monitoring in #{retry_in} seconds"
|
109
|
+
applog(watch, :info, msg)
|
110
|
+
|
111
|
+
sleep retry_in
|
112
|
+
|
113
|
+
# log
|
114
|
+
msg = "#{watch.name} auto-reenabling monitoring"
|
115
|
+
applog(watch, :info, msg)
|
116
|
+
|
117
|
+
watch.monitor if watch.state == :unmonitored
|
122
118
|
end
|
123
119
|
end
|
124
120
|
end
|
125
121
|
end
|
126
|
-
|
127
122
|
end
|
128
123
|
end
|
@@ -3,13 +3,12 @@ require 'net/https'
|
|
3
3
|
|
4
4
|
module God
|
5
5
|
module Conditions
|
6
|
-
|
7
6
|
# Condition Symbol :http_response_code
|
8
7
|
# Type: Poll
|
9
8
|
#
|
10
9
|
# Trigger based on the response from an HTTP request.
|
11
10
|
#
|
12
|
-
#
|
11
|
+
# Parameters
|
13
12
|
# Required
|
14
13
|
# +host+ is the hostname to connect [required]
|
15
14
|
# --one of code_is or code_is_not--
|
@@ -88,15 +87,13 @@ module God
|
|
88
87
|
end
|
89
88
|
|
90
89
|
def prepare
|
91
|
-
self.code_is = Array(
|
92
|
-
self.code_is_not = Array(
|
90
|
+
self.code_is = Array(code_is).map(&:to_i) if code_is
|
91
|
+
self.code_is_not = Array(code_is_not).map(&:to_i) if code_is_not
|
93
92
|
|
94
|
-
|
95
|
-
self.times = [self.times, self.times]
|
96
|
-
end
|
93
|
+
self.times = [times, times] if times.is_a?(Integer)
|
97
94
|
|
98
|
-
@timeline = Timeline.new(
|
99
|
-
@history = Timeline.new(
|
95
|
+
@timeline = Timeline.new(times[1])
|
96
|
+
@history = Timeline.new(times[1])
|
100
97
|
end
|
101
98
|
|
102
99
|
def reset
|
@@ -106,57 +103,57 @@ module God
|
|
106
103
|
|
107
104
|
def valid?
|
108
105
|
valid = true
|
109
|
-
valid &= complain("Attribute 'host' must be specified", self) if
|
106
|
+
valid &= complain("Attribute 'host' must be specified", self) if host.nil?
|
110
107
|
valid &= complain("One (and only one) of attributes 'code_is' and 'code_is_not' must be specified", self) if
|
111
|
-
(
|
108
|
+
(code_is.nil? && code_is_not.nil?) || (code_is && code_is_not)
|
112
109
|
valid
|
113
110
|
end
|
114
111
|
|
115
112
|
def test
|
116
113
|
response = nil
|
117
114
|
|
118
|
-
connection = Net::HTTP.new(
|
119
|
-
connection.use_ssl =
|
115
|
+
connection = Net::HTTP.new(host, port)
|
116
|
+
connection.use_ssl = port == 443 ? true : ssl
|
120
117
|
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE if connection.use_ssl?
|
121
118
|
|
122
|
-
if connection.use_ssl? &&
|
123
|
-
|
124
|
-
connection.ca_file =
|
119
|
+
if connection.use_ssl? && ca_file
|
120
|
+
File.read(ca_file) # it may raise EOFError
|
121
|
+
connection.ca_file = ca_file
|
125
122
|
connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
126
123
|
end
|
127
124
|
|
128
125
|
connection.start do |http|
|
129
|
-
http.read_timeout =
|
130
|
-
response = http.get(
|
126
|
+
http.read_timeout = timeout
|
127
|
+
response = http.get(path, headers)
|
131
128
|
end
|
132
129
|
|
133
130
|
actual_response_code = response.code.to_i
|
134
|
-
if
|
131
|
+
if code_is&.include?(actual_response_code)
|
135
132
|
pass(actual_response_code)
|
136
|
-
elsif
|
133
|
+
elsif code_is_not && !code_is_not.include?(actual_response_code)
|
137
134
|
pass(actual_response_code)
|
138
135
|
else
|
139
136
|
fail(actual_response_code)
|
140
137
|
end
|
141
138
|
rescue Errno::ECONNREFUSED
|
142
|
-
|
139
|
+
code_is ? fail('Refused') : pass('Refused')
|
143
140
|
rescue Errno::ECONNRESET
|
144
|
-
|
141
|
+
code_is ? fail('Reset') : pass('Reset')
|
145
142
|
rescue EOFError
|
146
|
-
|
143
|
+
code_is ? fail('EOF') : pass('EOF')
|
147
144
|
rescue Timeout::Error
|
148
|
-
|
145
|
+
code_is ? fail('Timeout') : pass('Timeout')
|
149
146
|
rescue Errno::ETIMEDOUT
|
150
|
-
|
151
|
-
rescue Exception =>
|
152
|
-
|
147
|
+
code_is ? fail('Timedout') : pass('Timedout')
|
148
|
+
rescue Exception => e
|
149
|
+
code_is ? fail(e.class.name) : pass(e.class.name)
|
153
150
|
end
|
154
151
|
|
155
152
|
private
|
156
153
|
|
157
154
|
def pass(code)
|
158
155
|
@timeline << true
|
159
|
-
if @timeline.
|
156
|
+
if @timeline.count { |x| x } >= times.first
|
160
157
|
self.info = "http response abnormal #{history(code, true)}"
|
161
158
|
true
|
162
159
|
else
|
@@ -173,12 +170,10 @@ module God
|
|
173
170
|
|
174
171
|
def history(code, passed)
|
175
172
|
entry = code.to_s.dup
|
176
|
-
entry =
|
173
|
+
entry = "*#{entry}" if passed
|
177
174
|
@history << entry
|
178
|
-
|
175
|
+
"[#{@history.join(', ')}]"
|
179
176
|
end
|
180
|
-
|
181
177
|
end
|
182
|
-
|
183
178
|
end
|
184
179
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module God
|
2
2
|
module Conditions
|
3
|
-
|
4
3
|
class Lambda < PollCondition
|
5
4
|
attr_accessor :lambda
|
6
5
|
|
@@ -11,15 +10,14 @@ module God
|
|
11
10
|
end
|
12
11
|
|
13
12
|
def test
|
14
|
-
if self.lambda.call
|
15
|
-
self.info =
|
13
|
+
if self.lambda.call
|
14
|
+
self.info = 'lambda condition was satisfied'
|
16
15
|
true
|
17
16
|
else
|
18
|
-
self.info =
|
17
|
+
self.info = 'lambda condition was not satisfied'
|
19
18
|
false
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
23
|
-
|
24
22
|
end
|
25
23
|
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module God
|
2
2
|
module Conditions
|
3
|
-
|
4
3
|
# Condition Symbol :memory_usage
|
5
4
|
# Type: Poll
|
6
5
|
#
|
7
6
|
# Trigger when the resident memory of a process is above a specified limit.
|
8
7
|
#
|
9
|
-
#
|
8
|
+
# Parameters
|
10
9
|
# Required
|
11
10
|
# +pid_file+ is the pid file of the process in question. Automatically
|
12
11
|
# populated for Watches.
|
@@ -40,11 +39,9 @@ module God
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def prepare
|
43
|
-
|
44
|
-
self.times = [self.times, self.times]
|
45
|
-
end
|
42
|
+
self.times = [times, times] if times.is_a?(Integer)
|
46
43
|
|
47
|
-
@timeline = Timeline.new(
|
44
|
+
@timeline = Timeline.new(times[1])
|
48
45
|
end
|
49
46
|
|
50
47
|
def reset
|
@@ -52,31 +49,30 @@ module God
|
|
52
49
|
end
|
53
50
|
|
54
51
|
def pid
|
55
|
-
|
52
|
+
pid_file ? File.read(pid_file).strip.to_i : watch.pid
|
56
53
|
end
|
57
54
|
|
58
55
|
def valid?
|
59
56
|
valid = true
|
60
|
-
valid &= complain("Attribute 'pid_file' must be specified", self) if
|
61
|
-
valid &= complain("Attribute 'above' must be specified", self) if
|
57
|
+
valid &= complain("Attribute 'pid_file' must be specified", self) if pid_file.nil? && watch.pid_file.nil?
|
58
|
+
valid &= complain("Attribute 'above' must be specified", self) if above.nil?
|
62
59
|
valid
|
63
60
|
end
|
64
61
|
|
65
62
|
def test
|
66
|
-
process = System::Process.new(
|
63
|
+
process = System::Process.new(pid)
|
67
64
|
@timeline.push(process.memory)
|
68
65
|
self.info = []
|
69
66
|
|
70
|
-
history =
|
67
|
+
history = @timeline.map { |x| "#{x > above ? '*' : ''}#{x}kb" }.join(', ')
|
71
68
|
|
72
|
-
if @timeline.
|
73
|
-
self.info = "memory out of bounds #{history}"
|
74
|
-
|
69
|
+
if @timeline.count { |x| x > above } >= times.first
|
70
|
+
self.info = "memory out of bounds [#{history}]"
|
71
|
+
true
|
75
72
|
else
|
76
|
-
|
73
|
+
false
|
77
74
|
end
|
78
75
|
end
|
79
76
|
end
|
80
|
-
|
81
77
|
end
|
82
78
|
end
|
@@ -20,7 +20,8 @@ module God
|
|
20
20
|
attr_accessor :pid_file
|
21
21
|
|
22
22
|
def initialize
|
23
|
-
|
23
|
+
super
|
24
|
+
self.info = 'process exited'
|
24
25
|
end
|
25
26
|
|
26
27
|
def valid?
|
@@ -28,7 +29,7 @@ module God
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def pid
|
31
|
-
|
32
|
+
pid_file ? File.read(pid_file).strip.to_i : watch.pid
|
32
33
|
end
|
33
34
|
|
34
35
|
def register
|
@@ -36,15 +37,15 @@ module God
|
|
36
37
|
|
37
38
|
begin
|
38
39
|
EventHandler.register(pid, :proc_exit) do |extra|
|
39
|
-
formatted_extra = extra.
|
40
|
+
formatted_extra = extra.empty? ? '' : " #{extra.inspect}"
|
40
41
|
self.info = "process #{pid} exited#{formatted_extra}"
|
41
|
-
|
42
|
+
watch.trigger(self)
|
42
43
|
end
|
43
44
|
|
44
|
-
msg = "#{
|
45
|
-
applog(
|
45
|
+
msg = "#{watch.name} registered 'proc_exit' event for pid #{pid}"
|
46
|
+
applog(watch, :info, msg)
|
46
47
|
rescue StandardError
|
47
|
-
raise EventRegistrationFailedError
|
48
|
+
raise EventRegistrationFailedError
|
48
49
|
end
|
49
50
|
end
|
50
51
|
|
@@ -53,14 +54,13 @@ module God
|
|
53
54
|
if pid
|
54
55
|
EventHandler.deregister(pid, :proc_exit)
|
55
56
|
|
56
|
-
msg = "#{
|
57
|
-
applog(
|
57
|
+
msg = "#{watch.name} deregistered 'proc_exit' event for pid #{pid}"
|
58
|
+
applog(watch, :info, msg)
|
58
59
|
else
|
59
|
-
pid_file_location =
|
60
|
-
applog(
|
60
|
+
pid_file_location = pid_file || watch.pid_file
|
61
|
+
applog(watch, :error, "#{watch.name} could not deregister: no cached PID or PID file #{pid_file_location} (#{base_name})")
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
64
|
-
|
65
65
|
end
|
66
66
|
end
|
@@ -29,13 +29,13 @@ module God
|
|
29
29
|
attr_accessor :pid_file
|
30
30
|
|
31
31
|
def pid
|
32
|
-
|
32
|
+
pid_file ? File.read(pid_file).strip.to_i : watch.pid
|
33
33
|
end
|
34
34
|
|
35
35
|
def valid?
|
36
36
|
valid = true
|
37
|
-
valid &= complain("Attribute 'pid_file' must be specified", self) if
|
38
|
-
valid &= complain("Attribute 'running' must be specified", self) if
|
37
|
+
valid &= complain("Attribute 'pid_file' must be specified", self) if pid_file.nil? && watch.pid_file.nil?
|
38
|
+
valid &= complain("Attribute 'running' must be specified", self) if running.nil?
|
39
39
|
valid
|
40
40
|
end
|
41
41
|
|
@@ -45,16 +45,14 @@ module God
|
|
45
45
|
pid = self.pid
|
46
46
|
active = pid && System::Process.new(pid).exists?
|
47
47
|
|
48
|
-
if
|
49
|
-
|
48
|
+
if running && active
|
49
|
+
info.concat(['process is running'])
|
50
50
|
true
|
51
|
-
elsif
|
52
|
-
|
51
|
+
elsif !running && !active
|
52
|
+
info.concat(['process is not running'])
|
53
53
|
true
|
54
54
|
else
|
55
|
-
if
|
56
|
-
self.info.concat(["process is not running"])
|
57
|
-
end
|
55
|
+
info.concat(['process is not running']) if running
|
58
56
|
false
|
59
57
|
end
|
60
58
|
end
|
@@ -72,12 +72,10 @@ module God
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def prepare
|
75
|
-
|
76
|
-
self.times = [self.times, self.times]
|
77
|
-
end
|
75
|
+
self.times = [times, times] if times.is_a?(Integer)
|
78
76
|
|
79
|
-
@timeline = Timeline.new(
|
80
|
-
@history = Timeline.new(
|
77
|
+
@timeline = Timeline.new(times[1])
|
78
|
+
@history = Timeline.new(times[1])
|
81
79
|
end
|
82
80
|
|
83
81
|
def reset
|
@@ -85,15 +83,15 @@ module God
|
|
85
83
|
@history.clear
|
86
84
|
end
|
87
85
|
|
88
|
-
def socket=(
|
89
|
-
components =
|
86
|
+
def socket=(socket)
|
87
|
+
components = socket.split(':')
|
90
88
|
if components.size == 3
|
91
|
-
@family
|
89
|
+
@family, @addr, @port = components
|
92
90
|
@port = @port.to_i
|
93
|
-
elsif components[0]
|
91
|
+
elsif /^tcp$/.match?(components[0])
|
94
92
|
@family = components[0]
|
95
93
|
@port = components[1].to_i
|
96
|
-
elsif components[0]
|
94
|
+
elsif /^unix$/.match?(components[0])
|
97
95
|
@family = components[0]
|
98
96
|
@path = components[1]
|
99
97
|
end
|
@@ -101,40 +99,37 @@ module God
|
|
101
99
|
|
102
100
|
def valid?
|
103
101
|
valid = true
|
104
|
-
if
|
105
|
-
|
106
|
-
|
107
|
-
if self.family == 'unix' and self.path.nil?
|
108
|
-
valid &= complain("Attribute 'path' must be specified for unix sockets", self)
|
109
|
-
end
|
110
|
-
valid = false unless %w{tcp unix}.member?(self.family)
|
102
|
+
valid &= complain("Attribute 'port' must be specified for tcp sockets", self) if family == 'tcp' && @port == 0
|
103
|
+
valid &= complain("Attribute 'path' must be specified for unix sockets", self) if family == 'unix' && path.nil?
|
104
|
+
valid = false unless %w[tcp unix].member?(family)
|
111
105
|
valid
|
112
106
|
end
|
113
107
|
|
114
108
|
def test
|
115
109
|
self.info = []
|
116
|
-
|
110
|
+
case family
|
111
|
+
when 'tcp'
|
117
112
|
begin
|
118
|
-
s = TCPSocket.new(
|
113
|
+
s = TCPSocket.new(addr, port)
|
119
114
|
rescue SystemCallError
|
120
115
|
end
|
121
|
-
status =
|
122
|
-
|
116
|
+
status = responding != s.nil?
|
117
|
+
when 'unix'
|
123
118
|
begin
|
124
|
-
s = UNIXSocket.new(
|
119
|
+
s = UNIXSocket.new(path)
|
125
120
|
rescue SystemCallError
|
126
121
|
end
|
127
|
-
status =
|
122
|
+
status = responding != s.nil?
|
128
123
|
else
|
129
124
|
status = false
|
130
125
|
end
|
131
126
|
@timeline.push(status)
|
132
|
-
history =
|
133
|
-
if @timeline.
|
134
|
-
self.info = "socket out of bounds #{history}"
|
135
|
-
|
127
|
+
history = @timeline.map { |t| t ? '*' : '' }.join(',')
|
128
|
+
if @timeline.count { |x| x } >= times.first
|
129
|
+
self.info = "socket out of bounds [#{history}]"
|
130
|
+
true
|
136
131
|
else
|
137
|
-
|
132
|
+
false
|
138
133
|
end
|
139
134
|
end
|
140
135
|
end
|
data/lib/god/conditions/tries.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
module God
|
2
2
|
module Conditions
|
3
|
-
|
4
3
|
class Tries < PollCondition
|
5
4
|
attr_accessor :times, :within
|
6
5
|
|
7
6
|
def prepare
|
8
|
-
@timeline = Timeline.new(
|
7
|
+
@timeline = Timeline.new(times)
|
9
8
|
end
|
10
9
|
|
11
10
|
def reset
|
@@ -14,31 +13,30 @@ module God
|
|
14
13
|
|
15
14
|
def valid?
|
16
15
|
valid = true
|
17
|
-
valid &= complain("Attribute 'times' must be specified", self) if
|
16
|
+
valid &= complain("Attribute 'times' must be specified", self) if times.nil?
|
18
17
|
valid
|
19
18
|
end
|
20
19
|
|
21
20
|
def test
|
22
21
|
@timeline << Time.now
|
23
22
|
|
24
|
-
|
25
|
-
duration =
|
23
|
+
consensus = (@timeline.size == times)
|
24
|
+
duration = within.nil? || (@timeline.last - @timeline.first) < within
|
26
25
|
|
27
|
-
if within
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
history = if within
|
27
|
+
"[#{@timeline.size}/#{times} within #{(@timeline.last - @timeline.first).to_i}s]"
|
28
|
+
else
|
29
|
+
"[#{@timeline.size}/#{times}]"
|
30
|
+
end
|
32
31
|
|
33
|
-
if
|
32
|
+
if consensus && duration
|
34
33
|
self.info = "tries exceeded #{history}"
|
35
|
-
|
34
|
+
true
|
36
35
|
else
|
37
36
|
self.info = "tries within bounds #{history}"
|
38
|
-
|
37
|
+
false
|
39
38
|
end
|
40
39
|
end
|
41
40
|
end
|
42
|
-
|
43
41
|
end
|
44
42
|
end
|