averell23-watchdogger 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/watchdogger.rb +21 -3
- data/lib/watcher/base.rb +4 -15
- data/lib/watcher/http_watcher.rb +9 -3
- data/lib/watcher/log_watcher.rb +1 -0
- data/lib/watcher_action.rb +5 -0
- data/lib/watcher_action/kill_process.rb +21 -4
- data/lib/watcher_action/meta_action.rb +8 -6
- data/lib/watcher_action/send_mail.rb +21 -10
- data/sample_config.yml +10 -0
- metadata +11 -1
data/lib/watchdogger.rb
CHANGED
@@ -105,17 +105,23 @@ module WatchDogger # :nodoc:
|
|
105
105
|
# daemon is still running.
|
106
106
|
def check_daemon
|
107
107
|
return false unless(File.exists?(@pidfile))
|
108
|
-
|
108
|
+
check_process(get_pid)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns true if the system thinks that the given process is still alive
|
112
|
+
def check_process(pid)
|
109
113
|
begin
|
110
114
|
Process.kill(0, pid)
|
115
|
+
dog_log.debug('Watchdogger') { "Process #{pid} is alive" }
|
111
116
|
true
|
112
117
|
rescue Errno::EPERM
|
118
|
+
dog_log.debug('Watchdogger') { "No permissions for process #{pid} - seems to be running."}
|
113
119
|
true
|
114
120
|
rescue Errno::ESRCH
|
115
|
-
dog_log.
|
121
|
+
dog_log.debug('Watchdogger') { "Found stale process for #{pid}." }
|
116
122
|
false
|
117
123
|
rescue Exception => e
|
118
|
-
dog_log.
|
124
|
+
dog_log.info('Watchdogger') { "Could not find out if process #{pid} still runs (#{e.message}). Hoping for the best..." }
|
119
125
|
false
|
120
126
|
end
|
121
127
|
end
|
@@ -174,4 +180,16 @@ class Hash # :nodoc:
|
|
174
180
|
value
|
175
181
|
end
|
176
182
|
|
183
|
+
# Gets the given key as an array. If it's already an array, it will be returned,
|
184
|
+
# otherwise we'll check if it's a comma-separated list. The
|
185
|
+
# default will be processed in the same way as if was read from the Hash.
|
186
|
+
def get_list(sym_or_string, default = nil)
|
187
|
+
value = get_value(sym_or_string, default)
|
188
|
+
return value if(value.is_a?(Array))
|
189
|
+
assit(value.is_a?(String) || value.is_a?(Symbol))
|
190
|
+
value = value.to_s.split(',').collect do |val|
|
191
|
+
val.strip
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
177
195
|
end
|
data/lib/watcher/base.rb
CHANGED
@@ -36,21 +36,10 @@ module Watcher
|
|
36
36
|
|
37
37
|
# Sets up all actions for this watcher
|
38
38
|
def setup_actions(configuration)
|
39
|
-
action_config = configuration.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
else
|
44
|
-
assit(action_config.is_a?(String) || action_config.is_a?(Symbol))
|
45
|
-
add_action_to(actions, action_config)
|
46
|
-
end
|
47
|
-
warn_config = configuration.get_value(:warn_actions)
|
48
|
-
if(warn_config.is_a?(Array))
|
49
|
-
warn_config.each { |ac| add_action_to(warn_actions, ac) }
|
50
|
-
elsif(warn_config)
|
51
|
-
assit_kind_of(String, warn_config)
|
52
|
-
add_action_to(warn_actions, warn_config)
|
53
|
-
end
|
39
|
+
action_config = configuration.get_list(:actions, false)
|
40
|
+
action_config.each { |ac| add_action_to(actions, ac) }
|
41
|
+
warn_config = configuration.get_list(:warn_actions, [])
|
42
|
+
warn_config.each { |ac| add_action_to(warn_actions, ac) }
|
54
43
|
end
|
55
44
|
|
56
45
|
private
|
data/lib/watcher/http_watcher.rb
CHANGED
@@ -11,12 +11,16 @@ module Watcher
|
|
11
11
|
# [*content_match*] A regular expression that is matched against the result.
|
12
12
|
# The watcher fails if the expression doesn't match
|
13
13
|
# [*timeout*] The timeout for the connection attempt. Defaults to 10 sec
|
14
|
-
#
|
14
|
+
# [*falloff*] If a successful connection is made, this is subtracted from
|
15
|
+
# the internal severity. (Default: 100, completely reset previous
|
16
|
+
# failures)
|
17
|
+
#
|
15
18
|
# If neither response nor content_match are given, the watcher will expect a
|
16
19
|
# 200 OK response from the server.
|
17
20
|
#
|
18
21
|
# This watcher resets the current severity on each successful connect, so that
|
19
|
-
# only continuous failures count against the trigger condition
|
22
|
+
# only continuous failures count against the trigger condition - see the falloff
|
23
|
+
# option.
|
20
24
|
class HttpWatcher < Watcher::Base
|
21
25
|
|
22
26
|
def initialize(config)
|
@@ -26,6 +30,8 @@ module Watcher
|
|
26
30
|
response = config.get_value(:response)
|
27
31
|
@response = ((!response && !match) ? "200" : response)
|
28
32
|
@timeout = config.get_value(:timeout, 10).to_i
|
33
|
+
@falloff = config.get_value(:falloff, 100).to_i
|
34
|
+
@current_severity = 0
|
29
35
|
end
|
30
36
|
|
31
37
|
def watch_it!
|
@@ -40,7 +46,7 @@ module Watcher
|
|
40
46
|
elsif(@content_match && !@content_match.match(res.body))
|
41
47
|
test_failed = "Did not find #{@content_match.to_s} at #{@url}"
|
42
48
|
end
|
43
|
-
@current_severity = 0 unless(test_failed)
|
49
|
+
@current_severity = [0, @current_severity - @falloff].min unless(test_failed)
|
44
50
|
dog_log.debug('HttpWatcher') { "Watch of #{@url} resulted in #{test_failed}" }
|
45
51
|
test_failed
|
46
52
|
rescue Exception => e
|
data/lib/watcher/log_watcher.rb
CHANGED
data/lib/watcher_action.rb
CHANGED
@@ -34,6 +34,11 @@ module WatcherAction
|
|
34
34
|
def has_action?(name)
|
35
35
|
registered_actions[name.to_sym] != nil
|
36
36
|
end
|
37
|
+
|
38
|
+
# Checks if the given action is registered with that name
|
39
|
+
def is_action?(name, action)
|
40
|
+
registered_actions[name.to_sym] == action
|
41
|
+
end
|
37
42
|
|
38
43
|
private
|
39
44
|
|
@@ -5,17 +5,34 @@ module WatcherAction
|
|
5
5
|
# =Options
|
6
6
|
#
|
7
7
|
# [*pidfile*] The file containing the process id
|
8
|
-
# [*signal*] The signal to send to the process.
|
8
|
+
# [*signal*] The signal to send to the process.
|
9
|
+
# This may be an array or a comma-separated
|
10
|
+
# list of signals. If there is more than one signal, this
|
11
|
+
# will wait for _wait_ seconds before trying the next
|
12
|
+
# signal, if the process didn't die.
|
13
|
+
# Defaults to KILL
|
14
|
+
# [*wait*] Time to wait between signals (Default: 5)
|
9
15
|
class KillProcess
|
10
16
|
|
11
17
|
def initialize(config)
|
12
18
|
@pidfile = config.get_value(:pidfile, false)
|
13
|
-
@
|
19
|
+
@signals = config.get_list(:signal, 'KILL')
|
20
|
+
@wait = config.get_value(:wait, 5).to_i
|
14
21
|
end
|
15
22
|
|
16
23
|
def execute(event)
|
17
|
-
|
18
|
-
|
24
|
+
Thread.new(@signals, @wait, @pidfile) do |signals, wait, pidfile|
|
25
|
+
pid = File.open(pidfile) { |io| io.read }.to_i
|
26
|
+
signals.each_with_index do |signal, index|
|
27
|
+
sleep(wait) if(index > 0)
|
28
|
+
if(WatchDogger.check_process(pid))
|
29
|
+
dog_log.debug('KillerThread') { "Sending signal #{signal} to process #{pid}" }
|
30
|
+
Process.kill(signal, pid)
|
31
|
+
else
|
32
|
+
dog_log.debug('KillerThread') { "Process #{pid} is dead." }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
19
36
|
rescue Exception => e
|
20
37
|
dog_log.warn { "Unable to kill process: #{e}" }
|
21
38
|
end
|
@@ -10,18 +10,20 @@ module WatcherAction
|
|
10
10
|
class MetaAction
|
11
11
|
|
12
12
|
def initialize(config)
|
13
|
-
actions = config.
|
14
|
-
|
15
|
-
@actions = actions
|
16
|
-
else
|
17
|
-
@actions = [ actions ]
|
18
|
-
end
|
13
|
+
actions = config.get_list(:actions, false)
|
14
|
+
actions.each { |ac| add_action(ac) }
|
19
15
|
end
|
20
16
|
|
21
17
|
def execute(event)
|
22
18
|
@actions.each { |ac| WatcherAction.run_action(ac, event) }
|
23
19
|
end
|
24
20
|
|
21
|
+
def add_action(action)
|
22
|
+
@actions ||= []
|
23
|
+
raise(ArgumentError, "Trying to add myself, creating a loop.") if(WatcherAction.is_action?(action, self))
|
24
|
+
@actions << action
|
25
|
+
end
|
26
|
+
|
25
27
|
end
|
26
28
|
|
27
29
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'rmail'
|
2
|
+
require 'tlsmail' if(/^1.8/ =~ RUBY_VERSION) # Include the hack for ruby 1.8
|
2
3
|
require 'net/smtp'
|
4
|
+
require 'time'
|
3
5
|
|
4
6
|
module WatcherAction
|
5
7
|
|
6
8
|
# This action will send an email to a given receipient. It doesn't support any
|
7
|
-
# fancy features (you may want to do that handling externally)
|
8
|
-
# use unencrypted smtp network connections.
|
9
|
+
# fancy features (you may want to do that handling externally).
|
9
10
|
#
|
10
11
|
# =Options
|
11
12
|
#
|
@@ -21,18 +22,20 @@ module WatcherAction
|
|
21
22
|
# [*user*] Mail server user name
|
22
23
|
# [*pass*] Mail server password
|
23
24
|
# [*authentication*] Authentication method (default: plain)
|
25
|
+
# [*enable_tls*] Use the TLS encryption (default: false)
|
24
26
|
class SendMail
|
25
27
|
|
26
28
|
def initialize(config)
|
27
29
|
@mail_to = config.get_value(:to, false)
|
28
30
|
@sender = config.get_value(:sender, false)
|
29
|
-
@subject = config.get_value(:subject, "Watchdogger
|
31
|
+
@subject = config.get_value(:subject, "Watchdogger needs your attention.")
|
30
32
|
@body = config.get_value(:body)
|
31
33
|
@server = config.get_value(:server, 'localhost')
|
32
34
|
@port = config.get_value(:port, '25')
|
33
35
|
@user = config.get_value(:user)
|
34
36
|
@pass = config.get_value(:pass)
|
35
37
|
@authentication = config.get_value(:authentication, :plain).to_sym
|
38
|
+
@enable_tls = config.get_value(:enable_tls) || false
|
36
39
|
end
|
37
40
|
|
38
41
|
def execute(event)
|
@@ -40,7 +43,8 @@ module WatcherAction
|
|
40
43
|
msg.header.to = @mail_to
|
41
44
|
receipient = msg.header.to.to_s.split(',').first
|
42
45
|
msg.header.from = @sender
|
43
|
-
msg.header.subject =
|
46
|
+
msg.header.subject = @subject % [event.message]
|
47
|
+
msg.header.date = Time.now
|
44
48
|
if(@body.to_s == 'xml')
|
45
49
|
msg.body = event.to_xml
|
46
50
|
elsif(@body)
|
@@ -48,18 +52,25 @@ module WatcherAction
|
|
48
52
|
else
|
49
53
|
msg.body = "The #{event.watcher.class.name} watcher of your watchdog triggered\nan event at #{event.timestamp}:\n#{event.message}"
|
50
54
|
end
|
51
|
-
|
55
|
+
|
52
56
|
smtp_params = [@server, @port]
|
53
57
|
if(@user && @pass)
|
54
|
-
smtp_params
|
58
|
+
smtp_params.concat([nil, @user, @pass, @authentication])
|
55
59
|
end
|
56
60
|
|
57
|
-
Net::SMTP.
|
58
|
-
|
61
|
+
Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE) if(@enable_tls)
|
62
|
+
Thread.new(smtp_params, msg, @sender, @mail_to) do |params, msg, sender, mail_to|
|
63
|
+
begin
|
64
|
+
Net::SMTP.start(*params) do |smtp|
|
65
|
+
smtp.send_message(msg.to_s, sender, mail_to)
|
66
|
+
end
|
67
|
+
dog_log.debug('SMTP Thread') { "Sent mail to #{mail_to} through #{params.first}" }
|
68
|
+
rescue Exception => e
|
69
|
+
dog_log.error('SMTP Thread') { "Could not send mail to #{mail_to} on #{params.first}: #{e.message}" }
|
70
|
+
end
|
59
71
|
end
|
60
|
-
dog_log.debug('SMTP Action') { "Sent mail to #{@mail_to} through #{@server}" }
|
61
72
|
rescue Exception => e
|
62
|
-
dog_log.
|
73
|
+
dog_log.error('SMTP Action') { "Could not send mail to #{@mail_to} on #{@server}: #{e.message}" }
|
63
74
|
end
|
64
75
|
|
65
76
|
end
|
data/sample_config.yml
CHANGED
@@ -3,6 +3,16 @@
|
|
3
3
|
actions:
|
4
4
|
log_it:
|
5
5
|
type: log_action
|
6
|
+
mail_message:
|
7
|
+
type: send_mail
|
8
|
+
to: one@gmail.com
|
9
|
+
sender: myself@gmail.com
|
10
|
+
server: smtp.gmail.com
|
11
|
+
user: test@gmail.com
|
12
|
+
pass: secret
|
13
|
+
port: 587
|
14
|
+
authentication: login
|
15
|
+
enable_tls: true
|
6
16
|
|
7
17
|
watchers:
|
8
18
|
test_hn:
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: averell23-watchdogger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Hahn
|
@@ -62,6 +62,16 @@ dependencies:
|
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: 0.6.5
|
64
64
|
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: tlsmail
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.0.1
|
74
|
+
version:
|
65
75
|
description: A small flexible watchdog system to monitor servers.
|
66
76
|
email: ghub@limitedcreativity.org
|
67
77
|
executables:
|