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.
@@ -1,124 +1,73 @@
1
- # To add Jabber notifications you must have xmpp4r gem installed.
2
- # Configure your watches like this:
1
+ # Send a notice to a Jabber address.
3
2
  #
4
- # God::Contacts::Jabber.settings = { :jabber_id => 'sender@example.com',
5
- # :password => 'secret' }
6
- # God.contact(:jabber) do |c|
7
- # c.name = 'Tester'
8
- # c.jabber_id = 'receiver@example.com'
9
- # c.group = 'developers'
10
- # end
3
+ # host - The String hostname of the Jabber server.
4
+ # port - The Integer port of the Jabber server (default: 5222).
5
+ # from_jid - The String Jabber ID of the sender.
6
+ # password - The String password of the sender.
7
+ # to_jid - The String Jabber ID of the recipient.
8
+ # subject - The String subject of the message (default: "God Notification").
11
9
 
12
- module XMPP4R
13
- require 'xmpp4r'
14
- include Jabber
10
+ CONTACT_DEPS[:jabber] = ['xmpp4r']
11
+ CONTACT_DEPS[:jabber].each do |d|
12
+ require d
15
13
  end
16
14
 
17
15
  module God
18
16
  module Contacts
19
- class Jabber < Contact
17
+
18
+ class Jabber < Contact
20
19
  class << self
21
- attr_accessor :settings, :format, :client
20
+ attr_accessor :host, :port, :from_jid, :password, :to_jid, :subject
21
+ attr_accessor :format
22
22
  end
23
-
24
- self.format = lambda do |message, priority, category, host|
23
+
24
+ self.port = 5222
25
+ self.subject = 'God Notification'
26
+
27
+ self.format = lambda do |message, time, priority, category, host|
25
28
  text = "Message: #{message}\n"
26
29
  text += "Host: #{host}\n" if host
27
30
  text += "Priority: #{priority}\n" if priority
28
31
  text += "Category: #{category}\n" if category
29
- return text
32
+ text
30
33
  end
31
-
32
- attr_accessor :jabber_id
33
-
34
+
35
+ attr_accessor :host, :port, :from_jid, :password, :to_jid, :subject
36
+
34
37
  def valid?
35
38
  valid = true
39
+ valid &= complain("Attribute 'host' must be specified", self) unless arg(:host)
40
+ valid &= complain("Attribute 'port' must be specified", self) unless arg(:port)
41
+ valid &= complain("Attribute 'from_jid' must be specified", self) unless arg(:from_jid)
42
+ valid &= complain("Attribute 'to_jid' must be specified", self) unless arg(:to_jid)
43
+ valid &= complain("Attribute 'password' must be specified", self) unless arg(:password)
44
+ valid
36
45
  end
37
-
46
+
38
47
  def notify(message, time, priority, category, host)
39
- connect
40
-
41
- body = Jabber.format.call message, priority, category, host
42
-
43
- message = XMPP4R::Message::new self.jabber_id, body
44
- message.set_type :normal
45
- message.set_id '1'
46
- message.set_subject 'God'
47
-
48
- self.send!(message)
49
-
50
- self.info = "sent jabber message to #{self.jabber_id}"
51
- rescue => e
52
- puts e.message
53
- puts e.backtrace.join("\n")
54
-
55
- self.info = "failed to send jabber message to #{self.jabber_id}: #{e.message}"
56
- end
57
-
58
- def send!(msg)
59
- attempts = 0
60
- begin
61
- attempts += 1
62
- client.send(msg)
63
- rescue Errno::EPIPE, IOError => e
64
- sleep 1
65
- disconnect!
66
- reconnect!
67
- retry unless attempts > 3
68
- raise e
69
- rescue Errno::ECONNRESET => e
70
- sleep (attempts^2) * 60 + 60
71
- disconnect!
72
- reconnect!
73
- retry unless attempts > 3
74
- raise e
75
- end
76
- end
77
-
78
- def connect
79
- connect! unless connected?
80
- end
81
-
82
- def connected?
83
- connected = client.respond_to?(:is_connected?) && client.is_connected?
84
- return connected
85
- end
86
-
87
- def connect!
88
- disconnect! if connected?
48
+ body = Jabber.format.call(message, time, priority, category, host)
89
49
 
90
- @connect_mutex ||= Mutex.new
91
- # don't try to connect if another thread is already connecting.
92
- return if @connect_mutex.locked?
93
- @connect_mutex.lock
94
-
95
- jabber_id = XMPP4R::JID::new "#{Jabber.settings[:jabber_id]}/God"
96
- jabber_client = XMPP4R::Client::new jabber_id
97
- jabber_client.connect Jabber.settings[:host]
98
- jabber_client.auth Jabber.settings[:password]
99
- self.client = jabber_client
100
-
101
- @connect_mutex.unlock
102
- end
103
-
104
- def disconnect!
105
- if client.respond_to?(:is_connected?) && client.is_connected?
106
- begin
107
- client.close
108
- rescue Errno::EPIPE, IOError => e
109
- self.info "Failed to disconnect: #{e}"
110
- nil
111
- end
112
- end
113
- client = nil
114
- end
50
+ message = ::Jabber::Message.new(arg(:to_jid), body)
51
+ message.set_type(:normal)
52
+ message.set_id('1')
53
+ message.set_subject(arg(:subject))
115
54
 
116
- def client
117
- Jabber.client
118
- end
55
+ jabber_id = ::Jabber::JID.new("#{arg(:from_jid)}/God")
119
56
 
120
- def client=(jc)
121
- Jabber.client = jc
57
+ client = ::Jabber::Client.new(jabber_id)
58
+ client.connect(arg(:host), arg(:port))
59
+ client.auth(arg(:password))
60
+ client.send(message)
61
+ client.close
62
+
63
+ self.info = "sent jabber message to #{self.to_jid}"
64
+ rescue Object => e
65
+ if e.respond_to?(:message)
66
+ applog(nil, :info, "failed to send jabber message to #{arg(:to_jid)}: #{e.message}")
67
+ else
68
+ applog(nil, :info, "failed to send jabber message to #{arg(:to_jid)}: #{e.class}")
69
+ end
70
+ applog(nil, :debug, e.backtrace.join("\n"))
122
71
  end
123
72
 
124
73
  end
@@ -1,38 +1,19 @@
1
- # For Prowl notifications you need the 'prowly' gem
2
- # (gem install prowly)
1
+ # Send a notice to Prowl (http://prowl.weks.net/).
3
2
  #
4
- # Configure your watches like this:
5
- #
6
- # God.contact(:prowl) do |c|
7
- # c.name = 'georgette'
8
- # c.apikey = 'ffffffffffffffffffffffffffffffffffffffff'
9
- # c.group = 'developers'
10
- # end
11
- #
12
- #
13
- # God.contact(:prowl) do |c|
14
- # c.name = 'johnny'
15
- # c.apikey = 'ffffffffffffffffffffffffffffffffffffffff'
16
- # c.group = 'developers'
17
- # end
18
- #
19
- #
20
- # Define a transition for the process running event
21
- #
22
- # w.transition(:up, :start) do |on|
23
- # on.condition(:process_running) do |c|
24
- # c.running = true
25
- # c.notify = 'developers'
26
- # end
27
- # end
3
+ # apikey - The String API key.
28
4
 
29
- require 'prowly'
5
+ CONTACT_DEPS[:prowl] = ['prowly']
6
+ CONTACT_DEPS[:prowl].each do |d|
7
+ require d
8
+ end
30
9
 
31
10
  module God
32
11
  module Contacts
33
12
  class Prowl < Contact
34
13
 
35
- attr_accessor :apikey
14
+ class << self
15
+ attr_accessor :apikey
16
+ end
36
17
 
37
18
  def valid?
38
19
  valid = true
@@ -40,28 +21,27 @@ module God
40
21
  valid
41
22
  end
42
23
 
24
+ attr_accessor :apikey
25
+
43
26
  def notify(message, time, priority, category, host)
44
- begin
45
- result = Prowly.notify do |n|
46
- n.apikey = self.apikey
47
- n.priority = map_priority(priority.to_i)
48
- n.application = category || "God"
49
- n.event = "on " + host.to_s
50
- n.description = message.to_s + " at " + time.to_s
51
- end
27
+ result = Prowly.notify do |n|
28
+ n.apikey = arg(:apikey)
29
+ n.priority = map_priority(priority.to_i)
30
+ n.application = category || "God"
31
+ n.event = "on " + host.to_s
32
+ n.description = message.to_s + " at " + time.to_s
33
+ end
52
34
 
53
- if result.succeeded?
54
- self.info = "sent prowl notification to #{self.name}"
55
- else
56
- self.info = "failed to send prowl notification to #{self.name}: #{result.message}"
57
- end
35
+ if result.succeeded?
36
+ self.info = "sent prowl notification to #{self.name}"
37
+ else
38
+ self.info = "failed to send prowl notification to #{self.name}: #{result.message}"
58
39
  end
59
40
  rescue Object => e
60
- self.info = "failed to send prowl notification to #{self.name}: #{e.message}"
41
+ applog(nil, :info, "failed to send prowl notification to #{self.name}: #{e.message}")
42
+ applog(nil, :debug, e.backtrace.join("\n"))
61
43
  end
62
44
 
63
- private
64
-
65
45
  def map_priority(priority)
66
46
  case priority
67
47
  when 1 then Prowly::Notification::Priority::EMERGENCY
@@ -74,4 +54,4 @@ module God
74
54
  end
75
55
  end
76
56
  end
77
- end
57
+ end
@@ -1,33 +1,19 @@
1
- # Configure your Scout client key:
1
+ # Send a notice to Scout (http://scoutapp.com/).
2
2
  #
3
- # God::Contacts::Scout.client_key = '1qpw29ie38ur37yt5
4
- #
5
- # A client key is configured per god process. Inside this God process,
6
- # you can create multiple Scout 'contacts' - which are actually Scout
7
- # plugins. This allows you to use Scout's UI to configure who gets
8
- # notifications for each plugin, and to disable notifications when you
9
- # go on vacation, etc.
10
- #
11
- # God.contact(:scout) do |c|
12
- # c.name = 'scout_delayed_job_plugin'
13
- # c.plugin_id = '12345
14
- # end
15
- #
16
- # God.contact(:scout) do |c|
17
- # c.name = 'scout_apache_plugin'
18
- # c.plugin_id = '54312
19
- # end
3
+ # client_key - The String client key.
4
+ # plugin_id - The String plugin id.
20
5
 
21
6
  require 'net/http'
22
7
  require 'uri'
23
8
 
24
9
  module God
25
10
  module Contacts
11
+
26
12
  class Scout < Contact
27
13
  class << self
28
- attr_accessor :client_key, :format
14
+ attr_accessor :client_key, :plugin_id
15
+ attr_accessor :format
29
16
  end
30
- attr_accessor :plugin_id
31
17
 
32
18
  self.format = lambda do |message, priority, category, host|
33
19
  text = "Message: #{message}\n"
@@ -37,28 +23,33 @@ module God
37
23
  return text
38
24
  end
39
25
 
26
+ attr_accessor :client_key, :plugin_id
27
+
40
28
  def valid?
41
29
  valid = true
30
+ valid &= complain("Attribute 'client_key' must be specified", self) unless arg(:client_key)
31
+ valid &= complain("Attribute 'plugin_id' must be specified", self) unless arg(:plugin_id)
32
+ valid
42
33
  end
43
34
 
44
35
  def notify(message, time, priority, category, host)
45
- begin
46
- data = {
47
- :client_key => Scout.client_key,
48
- :plugin_id => plugin_id,
49
- :format => 'xml',
50
- 'alert[subject]' => message,
51
- 'alert[body]' => Scout.format.call(message, priority, category, host)
52
- }
36
+ data = {
37
+ :client_key => arg(:client_key),
38
+ :plugin_id => arg(:plugin_id),
39
+ :format => 'xml',
40
+ 'alert[subject]' => message,
41
+ 'alert[body]' => Scout.format.call(message, priority, category, host)
42
+ }
53
43
 
54
- uri = URI.parse('http://scoutapp.com/alerts/create')
55
- Net::HTTP.post_form(uri, data)
44
+ uri = URI.parse('http://scoutapp.com/alerts/create')
45
+ Net::HTTP.post_form(uri, data)
56
46
 
57
- self.info = "sent scout alert to plugin ##{plugin_id}"
58
- rescue => e
59
- self.info = "failed to send scout alert to plugin ##{plugin_id}: #{e.message}"
60
- end
47
+ self.info = "sent scout alert to plugin ##{plugin_id}"
48
+ rescue => e
49
+ applog(nil, :info, "failed to send scout alert to plugin ##{plugin_id}: #{e.message}")
50
+ applog(nil, :debug, e.backtrace.join("\n"))
61
51
  end
62
52
  end
53
+
63
54
  end
64
55
  end
@@ -1,37 +1,50 @@
1
- # For Twitter updates you need the 'twitter' gem
2
- # (gem install twitter)
1
+ # Send a notice to a Twitter account (http://twitter.com/).
3
2
  #
4
- # Configure your watches like this:
5
- #
6
- # God::Contacts::Twitter.settings = { :username => 'sender@example.com',
7
- # :password => 'secret' }
8
- # God.contact(:twitter) do |c|
9
- # c.name = 'Tester'
10
- # c.group = 'developers'
11
- # end
3
+ # consumer_token - The String OAuth consumer token (defaults to God's
4
+ # existing consumer token).
5
+ # consumer_secret - The String OAuth consumer secret (defaults to God's
6
+ # existing consumer secret).
7
+ # access_token - The String OAuth access token.
8
+ # access_secret - The String OAuth access secret.
12
9
 
13
- require 'twitter'
10
+ CONTACT_DEPS[:twitter] = ['twitter']
11
+ CONTACT_DEPS[:twitter].each do |d|
12
+ require d
13
+ end
14
14
 
15
15
  module God
16
16
  module Contacts
17
17
  class Twitter < Contact
18
18
  class << self
19
- attr_accessor :settings
19
+ attr_accessor :consumer_token, :consumer_secret,
20
+ :access_token, :access_secret
20
21
  end
21
22
 
23
+ self.consumer_token = 'gOhjax6s0L3mLeaTtBWPw'
24
+ self.consumer_secret = 'yz4gpAVXJHKxvsGK85tEyzQJ7o2FEy27H1KEWL75jfA'
25
+
22
26
  def valid?
23
27
  valid = true
28
+ valid &= complain("Attribute 'consumer_token' must be specified", self) unless arg(:consumer_token)
29
+ valid &= complain("Attribute 'consumer_secret' must be specified", self) unless arg(:consumer_secret)
30
+ valid &= complain("Attribute 'access_token' must be specified", self) unless arg(:access_token)
31
+ valid &= complain("Attribute 'access_secret' must be specified", self) unless arg(:access_secret)
32
+ valid
24
33
  end
25
34
 
35
+ attr_accessor :consumer_token, :consumer_secret,
36
+ :access_token, :access_secret
37
+
26
38
  def notify(message, time, priority, category, host)
27
- begin
28
- ::Twitter::Base.new(Twitter.settings[:username],
29
- Twitter.settings[:password]).update(message)
30
-
31
- self.info = "sent twitter update as #{Twitter.settings[:username]}"
32
- rescue => e
33
- self.info = "failed to send twitter update from #{self.twitter_id}: #{e.message}"
34
- end
39
+ oauth = ::Twitter::OAuth.new(arg(:consumer_token), arg(:consumer_secret))
40
+ oauth.authorize_from_access(arg(:access_token), arg(:access_secret))
41
+
42
+ ::Twitter::Base.new(oauth).update(message)
43
+
44
+ self.info = "sent twitter update"
45
+ rescue => e
46
+ applog(nil, :info, "failed to send twitter update: #{e.message}")
47
+ applog(nil, :debug, e.backtrace.join("\n"))
35
48
  end
36
49
  end
37
50
  end
@@ -1,44 +1,70 @@
1
- # Configure your watches like this:
1
+ # Send a notice to a webhook.
2
2
  #
3
- # God.contact(:webhook) do |c|
4
- # c.name = 'Tester'
5
- # c.hook_url = 'http://hook/url'
6
- # end
3
+ # url - The String webhook URL.
4
+ # format - The Symbol format [ :form | :json ] (default: :form).
7
5
 
8
6
  require 'net/http'
9
7
  require 'uri'
10
8
 
9
+ CONTACT_DEPS[:webhook] = ['json']
10
+ CONTACT_DEPS[:webhook].each do |d|
11
+ require d
12
+ end
13
+
11
14
  module God
12
15
  module Contacts
13
16
 
14
17
  class Webhook < Contact
18
+ class << self
19
+ attr_accessor :url, :format
20
+ end
15
21
 
16
- attr_accessor :hook_url
22
+ self.format = :form
17
23
 
18
24
  def valid?
19
25
  valid = true
26
+ valid &= complain("Attribute 'url' must be specified", self) unless arg(:url)
27
+ valid &= complain("Attribute 'format' must be one of [ :form | :json ]", self) unless [:form, :json].include?(arg(:format))
28
+ valid
20
29
  end
21
30
 
31
+ attr_accessor :url, :format
32
+
22
33
  def notify(message, time, priority, category, host)
23
- begin
24
- data = {
25
- :message => message,
26
- :time => time,
27
- :priority => priority,
28
- :category => category,
29
- :host => host
30
- }
31
-
32
- uri = URI.parse(self.hook_url)
33
- Net::HTTP.post_form(uri, data)
34
-
35
- self.info = "sent webhook to #{self.hook_url}"
36
- rescue => e
37
- puts e.message
38
- puts e.backtrace.join("\n")
39
-
40
- self.info = "failed to send webhook to #{self.hook_url}: #{e.message}"
34
+ data = {
35
+ :message => message,
36
+ :time => time,
37
+ :priority => priority,
38
+ :category => category,
39
+ :host => host
40
+ }
41
+
42
+ uri = URI.parse(arg(:url))
43
+ http = Net::HTTP.new(uri.host, uri.port)
44
+
45
+ req = nil
46
+ res = nil
47
+
48
+ case arg(:format)
49
+ when :form
50
+ req = Net::HTTP::Post.new(uri.path)
51
+ req.set_form_data(data)
52
+ when :json
53
+ req = Net::HTTP::Post.new(uri.path)
54
+ req.body = data.to_json
55
+ end
56
+
57
+ res = http.request(req)
58
+
59
+ case res
60
+ when Net::HTTPSuccess
61
+ self.info = "sent webhook to #{arg(:url)}"
62
+ else
63
+ self.info = "failed to send webhook to #{arg(:url)}: #{res.error!}"
41
64
  end
65
+ rescue Object => e
66
+ applog(nil, :info, "failed to send email to #{arg(:url)}: #{e.message}")
67
+ applog(nil, :debug, e.backtrace.join("\n"))
42
68
  end
43
69
 
44
70
  end