god 0.10.1 → 0.11.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 +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
|