god 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -1
- data/god.gemspec +2 -3
- data/lib/god.rb +30 -22
- data/lib/god/contact.rb +8 -0
- data/lib/god/contacts/campfire.rb +97 -59
- data/lib/god/contacts/email.rb +80 -48
- data/lib/god/contacts/jabber.rb +50 -101
- data/lib/god/contacts/prowl.rb +25 -45
- data/lib/god/contacts/scout.rb +25 -34
- data/lib/god/contacts/twitter.rb +33 -20
- data/lib/god/contacts/webhook.rb +50 -24
- data/test/configs/contact/contact.god +59 -41
- data/test/test_campfire.rb +14 -32
- data/test/test_email.rb +22 -33
- data/test/test_jabber.rb +17 -24
- data/test/test_webhook.rb +7 -9
- metadata +37 -105
data/History.txt
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
==
|
1
|
+
== 0.11.0 / 2010-07-01
|
2
|
+
* Major Changes
|
3
|
+
* Rewrite notification system to be more consistent and flexible.
|
4
|
+
|
5
|
+
== 0.10.1 / 2010-05-17
|
6
|
+
* Bug Fixes
|
7
|
+
* Fix date in gemspec
|
8
|
+
|
9
|
+
== 0.10.0 / 2010-05-17
|
2
10
|
* Minor Enhancements
|
3
11
|
* Add stop_timeout and stop_signal options to Watch
|
4
12
|
* Bug Fixes
|
data/god.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'god'
|
6
|
-
s.version = '0.
|
7
|
-
s.date = '2010-
|
6
|
+
s.version = '0.11.0'
|
7
|
+
s.date = '2010-07-01'
|
8
8
|
|
9
9
|
s.summary = "Process monitoring framework."
|
10
10
|
s.description = "An easy to configure, easy to extend monitoring framework written in Ruby."
|
@@ -26,7 +26,6 @@ Gem::Specification.new do |s|
|
|
26
26
|
|
27
27
|
s.add_development_dependency('twitter', [">= 0.3.7"])
|
28
28
|
s.add_development_dependency('prowly', [">= 0.2.1"])
|
29
|
-
s.add_development_dependency('tinder', [">= 1.3.1", "< 2.0.0"])
|
30
29
|
s.add_development_dependency('xmpp4r', [">= 0.4.0"])
|
31
30
|
s.add_development_dependency('dike', [">= 0.0.3"])
|
32
31
|
s.add_development_dependency('snapshot', [">= 1.0.0", "< 2.0.0"])
|
data/lib/god.rb
CHANGED
@@ -48,27 +48,6 @@ require 'god/conditions/disk_usage'
|
|
48
48
|
require 'god/conditions/complex'
|
49
49
|
require 'god/conditions/file_mtime'
|
50
50
|
|
51
|
-
require 'god/contact'
|
52
|
-
require 'god/contacts/email'
|
53
|
-
require 'god/contacts/webhook'
|
54
|
-
begin
|
55
|
-
require 'god/contacts/twitter'
|
56
|
-
rescue LoadError
|
57
|
-
end
|
58
|
-
begin
|
59
|
-
require 'god/contacts/jabber'
|
60
|
-
rescue LoadError
|
61
|
-
end
|
62
|
-
begin
|
63
|
-
require 'god/contacts/campfire'
|
64
|
-
rescue LoadError
|
65
|
-
end
|
66
|
-
begin
|
67
|
-
require 'god/contacts/prowl'
|
68
|
-
rescue LoadError
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
51
|
require 'god/socket'
|
73
52
|
require 'god/driver'
|
74
53
|
|
@@ -87,6 +66,25 @@ require 'god/cli/command'
|
|
87
66
|
|
88
67
|
require 'god/diagnostics'
|
89
68
|
|
69
|
+
CONTACT_DEPS = { }
|
70
|
+
CONTACT_LOAD_SUCCESS = { }
|
71
|
+
|
72
|
+
def load_contact(name)
|
73
|
+
require "god/contacts/#{name}"
|
74
|
+
CONTACT_LOAD_SUCCESS[name] = true
|
75
|
+
rescue LoadError
|
76
|
+
CONTACT_LOAD_SUCCESS[name] = false
|
77
|
+
end
|
78
|
+
|
79
|
+
require 'god/contact'
|
80
|
+
load_contact(:campfire)
|
81
|
+
load_contact(:email)
|
82
|
+
load_contact(:jabber)
|
83
|
+
load_contact(:prowl)
|
84
|
+
load_contact(:scout)
|
85
|
+
load_contact(:twitter)
|
86
|
+
load_contact(:webhook)
|
87
|
+
|
90
88
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. ext god])
|
91
89
|
|
92
90
|
# App wide logging system
|
@@ -150,7 +148,7 @@ class Module
|
|
150
148
|
end
|
151
149
|
|
152
150
|
module God
|
153
|
-
VERSION = '0.
|
151
|
+
VERSION = '0.11.0'
|
154
152
|
LOG_BUFFER_SIZE_DEFAULT = 100
|
155
153
|
PID_FILE_DIRECTORY_DEFAULTS = ['/var/run/god', '~/.god/pids']
|
156
154
|
DRB_PORT_DEFAULT = 17165
|
@@ -352,6 +350,16 @@ module God
|
|
352
350
|
def self.contact(kind)
|
353
351
|
self.internal_init
|
354
352
|
|
353
|
+
# verify contact has been loaded
|
354
|
+
if CONTACT_LOAD_SUCCESS[kind] == false
|
355
|
+
applog(nil, :error, "A required dependency for the #{kind} contact is unavailable.")
|
356
|
+
applog(nil, :error, "Run the following commands to install the dependencies:")
|
357
|
+
CONTACT_DEPS[kind].each do |d|
|
358
|
+
applog(nil, :error, " [sudo] gem install #{d}")
|
359
|
+
end
|
360
|
+
abort
|
361
|
+
end
|
362
|
+
|
355
363
|
# create the contact
|
356
364
|
begin
|
357
365
|
c = Contact.generate(kind)
|
data/lib/god/contact.rb
CHANGED
@@ -24,6 +24,14 @@ module God
|
|
24
24
|
valid
|
25
25
|
end
|
26
26
|
|
27
|
+
def self.defaults
|
28
|
+
yield self
|
29
|
+
end
|
30
|
+
|
31
|
+
def arg(name)
|
32
|
+
self.instance_variable_get("@#{name}") || self.class.instance_variable_get("@#{name}")
|
33
|
+
end
|
34
|
+
|
27
35
|
# Normalize the given notify specification into canonical form.
|
28
36
|
# +spec+ is the notify spec as a String, Array of Strings, or Hash
|
29
37
|
#
|
@@ -1,81 +1,119 @@
|
|
1
|
-
#
|
1
|
+
# Send a notice to a Campfire room (http://campfirenow.com).
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
3
|
+
# subdomain - The String subdomain of the Campfire account. If your URL is
|
4
|
+
# "foo.campfirenow.com" then your subdomain is "foo".
|
5
|
+
# token - The String token used for authentication.
|
6
|
+
# room - The String room name to which the message should be sent.
|
7
|
+
# ssl - A Boolean determining whether or not to use SSL
|
8
|
+
# (default: false).
|
9
|
+
|
10
|
+
require 'net/http'
|
11
|
+
require 'net/https'
|
12
|
+
|
13
|
+
CONTACT_DEPS[:campfire] = ['json']
|
14
|
+
CONTACT_DEPS[:campfire].each do |d|
|
15
|
+
require d
|
16
|
+
end
|
17
|
+
|
18
|
+
module Marshmallow
|
19
|
+
class Connection
|
20
|
+
def initialize(options)
|
21
|
+
raise "Required option :subdomain not set." unless options[:subdomain]
|
22
|
+
raise "Required option :token not set." unless options[:token]
|
23
|
+
@options = options
|
24
|
+
end
|
25
|
+
|
26
|
+
def base_url
|
27
|
+
scheme = @options[:ssl] ? 'https' : 'http'
|
28
|
+
subdomain = @options[:subdomain]
|
29
|
+
"#{scheme}://#{subdomain}.campfirenow.com"
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_room_id_by_name(room)
|
33
|
+
url = URI.parse("#{base_url}/rooms.json")
|
34
|
+
|
35
|
+
http = Net::HTTP.new(url.host, url.port)
|
36
|
+
http.use_ssl = true if @options[:ssl]
|
37
|
+
|
38
|
+
req = Net::HTTP::Get.new(url.path)
|
39
|
+
req.basic_auth(@options[:token], 'X')
|
28
40
|
|
29
|
-
|
41
|
+
res = http.request(req)
|
42
|
+
case res
|
43
|
+
when Net::HTTPSuccess
|
44
|
+
rooms = JSON.parse(res.body)
|
45
|
+
room = rooms['rooms'].select { |x| x['name'] == room }
|
46
|
+
rooms.empty? ? nil : room.first['id']
|
47
|
+
else
|
48
|
+
raise res.error!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def speak(room, message)
|
53
|
+
room_id = find_room_id_by_name(room)
|
54
|
+
raise "No such room: #{room}." unless room_id
|
55
|
+
|
56
|
+
url = URI.parse("#{base_url}/room/#{room_id}/speak.json")
|
57
|
+
|
58
|
+
http = Net::HTTP.new(url.host, url.port)
|
59
|
+
http.use_ssl = true if @options[:ssl]
|
60
|
+
|
61
|
+
req = Net::HTTP::Post.new(url.path)
|
62
|
+
req.basic_auth(@options[:token], 'X')
|
63
|
+
req.set_content_type('application/json')
|
64
|
+
req.body = { 'message' => { 'body' => message } }.to_json
|
65
|
+
|
66
|
+
res = http.request(req)
|
67
|
+
case res
|
68
|
+
when Net::HTTPSuccess
|
69
|
+
true
|
70
|
+
else
|
71
|
+
raise res.error!
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
30
76
|
|
31
77
|
module God
|
32
78
|
module Contacts
|
33
79
|
|
34
80
|
class Campfire < Contact
|
35
81
|
class << self
|
36
|
-
attr_accessor :
|
82
|
+
attr_accessor :subdomain, :token, :room, :ssl
|
83
|
+
attr_accessor :format
|
37
84
|
end
|
38
85
|
|
39
|
-
self.
|
40
|
-
:user_name => '',
|
41
|
-
:password => '',
|
42
|
-
:room => '',
|
43
|
-
:ssl => false}
|
86
|
+
self.ssl = false
|
44
87
|
|
45
|
-
self.format = lambda do |message, host|
|
46
|
-
|
47
|
-
#{host} - #{message}
|
48
|
-
EOF
|
88
|
+
self.format = lambda do |message, time, priority, category, host|
|
89
|
+
"[#{time.strftime('%H:%M:%S')}] #{host} - #{message}"
|
49
90
|
end
|
50
91
|
|
51
|
-
|
52
|
-
|
92
|
+
attr_accessor :subdomain, :token, :room, :ssl
|
93
|
+
|
94
|
+
def valid?
|
95
|
+
valid = true
|
96
|
+
valid &= complain("Attribute 'subdomain' must be specified", self) unless arg(:subdomain)
|
97
|
+
valid &= complain("Attribute 'token' must be specified", self) unless arg(:token)
|
98
|
+
valid &= complain("Attribute 'room' must be specified", self) unless arg(:room)
|
99
|
+
valid
|
53
100
|
end
|
54
101
|
|
55
102
|
def notify(message, time, priority, category, host)
|
56
|
-
|
57
|
-
body = Campfire.format.call(message,host)
|
58
|
-
|
59
|
-
room.speak body
|
60
|
-
|
61
|
-
self.info = "notified campfire: #{Campfire.server_settings[:subdomain]}"
|
62
|
-
rescue => e
|
63
|
-
applog(nil, :info, "failed to notify campfire: #{e.message}")
|
64
|
-
applog(nil, :debug, e.backtrace.join("\n"))
|
65
|
-
end
|
66
|
-
end
|
103
|
+
body = Campfire.format.call(message, time, priority, category, host)
|
67
104
|
|
68
|
-
|
105
|
+
conn = Marshmallow::Connection.new(
|
106
|
+
:subdomain => arg(:subdomain),
|
107
|
+
:token => arg(:token),
|
108
|
+
:ssl => arg(:ssl)
|
109
|
+
)
|
69
110
|
|
70
|
-
|
71
|
-
unless @room
|
72
|
-
applog(nil,:debug, "initializing campfire connection using credentials: #{Campfire.server_settings.inspect}")
|
111
|
+
conn.speak(arg(:room), body)
|
73
112
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
@room
|
113
|
+
self.info = "notified campfire: #{arg(:subdomain)}"
|
114
|
+
rescue Object => e
|
115
|
+
applog(nil, :info, "failed to notify campfire: #{e.message}")
|
116
|
+
applog(nil, :debug, e.backtrace.join("\n"))
|
79
117
|
end
|
80
118
|
end
|
81
119
|
|
data/lib/god/contacts/email.rb
CHANGED
@@ -1,36 +1,59 @@
|
|
1
|
+
# Send a notice to an email address.
|
2
|
+
#
|
3
|
+
# to_email - The String email address to which the email will be sent.
|
4
|
+
# to_name - The String name corresponding to the recipient.
|
5
|
+
# from_email - The String email address from which the email will be sent.
|
6
|
+
# from_name - The String name corresponding to the sender.
|
7
|
+
# delivery_method - The Symbol delivery method. [ :smtp | :sendmail ]
|
8
|
+
# (default: :smtp).
|
9
|
+
#
|
10
|
+
# === SMTP Options (when delivery_method = :smtp) ===
|
11
|
+
# server_host - The String hostname of the SMTP server (default: localhost).
|
12
|
+
# server_port - The Integer port of the SMTP server (default: 25).
|
13
|
+
# server_auth - The Boolean of whether or not to use authentication
|
14
|
+
# (default: false).
|
15
|
+
#
|
16
|
+
# === SMTP Auth Options (when server_auth = true) ===
|
17
|
+
# server_domain - The String domain.
|
18
|
+
# server_user - The String username.
|
19
|
+
# server_password - The String password.
|
20
|
+
#
|
21
|
+
# === Sendmail Options (when delivery_method = :sendmail) ===
|
22
|
+
# sendmail_path - The String path to the sendmail executable
|
23
|
+
# (default: "/usr/sbin/sendmail").
|
24
|
+
# sendmail_args - The String args to send to sendmail (default "-i -t").
|
25
|
+
|
1
26
|
require 'time'
|
2
27
|
require 'net/smtp'
|
3
28
|
|
4
29
|
module God
|
5
30
|
module Contacts
|
6
|
-
|
31
|
+
|
7
32
|
class Email < Contact
|
8
33
|
class << self
|
9
|
-
attr_accessor :
|
34
|
+
attr_accessor :to_email, :to_name, :from_email, :from_name,
|
35
|
+
:delivery_method, :server_host, :server_port,
|
36
|
+
:server_auth, :server_domain, :server_user,
|
37
|
+
:server_password, :sendmail_path, :sendmail_args
|
38
|
+
attr_accessor :format
|
10
39
|
end
|
11
|
-
|
12
|
-
self.message_settings = {:from => 'god@example.com'}
|
13
|
-
|
14
|
-
self.delivery_method = :smtp # or :sendmail
|
15
|
-
|
16
|
-
self.server_settings = {:address => 'localhost',
|
17
|
-
:port => 25}
|
18
|
-
# :domain
|
19
|
-
# :user_name
|
20
|
-
# :password
|
21
|
-
# :authentication
|
22
40
|
|
23
|
-
self.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
self.
|
41
|
+
self.from_email = 'god@example.com'
|
42
|
+
self.from_name = 'God Process Monitoring'
|
43
|
+
self.delivery_method = :smtp
|
44
|
+
self.server_auth = false
|
45
|
+
self.server_host = 'localhost'
|
46
|
+
self.server_port = 25
|
47
|
+
self.sendmail_path = '/usr/sbin/sendmail'
|
48
|
+
self.sendmail_args = '-i -t'
|
49
|
+
|
50
|
+
self.format = lambda do |name, from_email, from_name, to_email, to_name, message, time, priority, category, host|
|
28
51
|
<<-EOF
|
29
|
-
From:
|
30
|
-
To: #{name} <#{
|
52
|
+
From: #{from_name} <#{from_email}>
|
53
|
+
To: #{to_name || name} <#{to_email}>
|
31
54
|
Subject: [god] #{message}
|
32
|
-
Date: #{
|
33
|
-
Message-Id: <#{rand(1000000000).to_s(36)}.#{$$}.#{
|
55
|
+
Date: #{time.httpdate}
|
56
|
+
Message-Id: <#{rand(1000000000).to_s(36)}.#{$$}.#{from_email}>
|
34
57
|
|
35
58
|
Message: #{message}
|
36
59
|
Host: #{host}
|
@@ -38,53 +61,62 @@ Priority: #{priority}
|
|
38
61
|
Category: #{category}
|
39
62
|
EOF
|
40
63
|
end
|
41
|
-
|
42
|
-
attr_accessor :
|
43
|
-
|
64
|
+
|
65
|
+
attr_accessor :to_email, :to_name, :from_email, :from_name,
|
66
|
+
:delivery_method, :server_host, :server_port,
|
67
|
+
:server_auth, :server_domain, :server_user,
|
68
|
+
:server_password, :sendmail_path, :sendmail_args
|
69
|
+
|
44
70
|
def valid?
|
45
71
|
valid = true
|
46
|
-
valid &= complain("Attribute '
|
72
|
+
valid &= complain("Attribute 'to_email' must be specified", self) unless arg(:to_email)
|
73
|
+
valid &= complain("Attribute 'delivery_method' must be one of [ :smtp | :sendmail ]", self) unless [:smtp, :sendmail].include?(arg(:delivery_method))
|
74
|
+
if arg(:delivery_method) == :smtp
|
75
|
+
valid &= complain("Attribute 'server_host' must be specified", self) unless arg(:server_host)
|
76
|
+
valid &= complain("Attribute 'server_port' must be specified", self) unless arg(:server_port)
|
77
|
+
if arg(:server_auth)
|
78
|
+
valid &= complain("Attribute 'server_domain' must be specified", self) unless arg(:server_domain)
|
79
|
+
valid &= complain("Attribute 'server_user' must be specified", self) unless arg(:server_user)
|
80
|
+
valid &= complain("Attribute 'server_password' must be specified", self) unless arg(:server_password)
|
81
|
+
end
|
82
|
+
end
|
47
83
|
valid
|
48
84
|
end
|
49
|
-
|
85
|
+
|
50
86
|
def notify(message, time, priority, category, host)
|
51
|
-
|
52
|
-
|
87
|
+
body = Email.format.call(self.name, arg(:from_email), arg(:from_name),
|
88
|
+
arg(:to_email), arg(:to_name), message, time,
|
89
|
+
priority, category, host)
|
53
90
|
|
54
|
-
|
91
|
+
case arg(:delivery_method)
|
55
92
|
when :smtp
|
56
93
|
notify_smtp(body)
|
57
94
|
when :sendmail
|
58
95
|
notify_sendmail(body)
|
59
|
-
else
|
60
|
-
raise "unknown delivery method: #{Email.delivery_method}"
|
61
|
-
end
|
62
|
-
|
63
|
-
self.info = "sent email to #{self.email}"
|
64
|
-
rescue => e
|
65
|
-
applog(nil, :info, "failed to send email to #{self.email}: #{e.message}")
|
66
|
-
applog(nil, :debug, e.backtrace.join("\n"))
|
67
96
|
end
|
68
|
-
end
|
69
97
|
|
70
|
-
|
98
|
+
self.info = "sent email to #{arg(:to_email)} via #{arg(:delivery_method).to_s}"
|
99
|
+
rescue Object => e
|
100
|
+
applog(nil, :info, "failed to send email to #{arg(:to_email)} via #{arg(:delivery_method).to_s}: #{e.message}")
|
101
|
+
applog(nil, :debug, e.backtrace.join("\n"))
|
102
|
+
end
|
71
103
|
|
72
104
|
def notify_smtp(mail)
|
73
|
-
args = [
|
74
|
-
if
|
75
|
-
args <<
|
76
|
-
args <<
|
77
|
-
args <<
|
78
|
-
args <<
|
105
|
+
args = [arg(:server_host), arg(:server_port)]
|
106
|
+
if arg(:server_auth)
|
107
|
+
args << arg(:server_domain)
|
108
|
+
args << arg(:server_user)
|
109
|
+
args << arg(:server_password)
|
110
|
+
args << arg(:server_auth)
|
79
111
|
end
|
80
112
|
|
81
113
|
Net::SMTP.start(*args) do |smtp|
|
82
|
-
smtp.send_message
|
114
|
+
smtp.send_message(mail, arg(:from_email), arg(:to_email))
|
83
115
|
end
|
84
116
|
end
|
85
117
|
|
86
118
|
def notify_sendmail(mail)
|
87
|
-
IO.popen("#{
|
119
|
+
IO.popen("#{arg(:sendmail_path)} #{arg(:sendmail_args)}","w+") do |sm|
|
88
120
|
sm.print(mail.gsub(/\r/, ''))
|
89
121
|
sm.flush
|
90
122
|
end
|