flapjack 0.6.46 → 0.6.47
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/bin/flapjack-nagios-receiver +1 -2
- data/bin/flapjack-populator +5 -9
- data/features/notifications.feature +0 -2
- data/features/steps/notifications_steps.rb +45 -32
- data/features/support/env.rb +3 -6
- data/lib/flapjack/coordinator.rb +2 -2
- data/lib/flapjack/data/contact.rb +8 -8
- data/lib/flapjack/data/entity.rb +31 -1
- data/lib/flapjack/data/event.rb +2 -0
- data/lib/flapjack/data/tag.rb +51 -0
- data/lib/flapjack/executive.rb +2 -2
- data/lib/flapjack/gateways/email.rb +57 -42
- data/lib/flapjack/gateways/oobetet.rb +1 -1
- data/lib/flapjack/gateways/sms_messagenet.rb +105 -0
- data/lib/flapjack/version.rb +1 -1
- data/spec/lib/flapjack/data/entity_spec.rb +54 -1
- data/spec/lib/flapjack/data/tag_spec.rb +12 -0
- data/spec/lib/flapjack/gateways/sms_messagenet.spec.rb +6 -0
- data/tasks/events.rake +7 -2
- metadata +8 -6
- data/lib/flapjack/gateways/sms.rb +0 -53
- data/lib/flapjack/gateways/sms/messagenet.rb +0 -49
- data/spec/lib/flapjack/gateways/sms_spec.rb +0 -6
@@ -35,7 +35,6 @@ config = Flapjack::Configuration.new
|
|
35
35
|
config.load(options.config)
|
36
36
|
@config_env = config.all
|
37
37
|
@redis_options = config.for_redis
|
38
|
-
puts @redis_options.inspect
|
39
38
|
|
40
39
|
if @config_env.nil? || @config_env.empty?
|
41
40
|
puts "No config data for environment '#{FLAPJACK_ENV}' found in '#{options.config}'"
|
@@ -95,7 +94,7 @@ def process_input(redis)
|
|
95
94
|
end
|
96
95
|
|
97
96
|
def main
|
98
|
-
redis = Redis.new(@redis_options
|
97
|
+
redis = Redis.new(@redis_options)
|
99
98
|
|
100
99
|
while true
|
101
100
|
process_input(redis)
|
data/bin/flapjack-populator
CHANGED
@@ -64,14 +64,12 @@ when "import-contacts"
|
|
64
64
|
|
65
65
|
if contacts && contacts.is_a?(Enumerable) && contacts.any? {|e| !e['id'].nil?}
|
66
66
|
@persistence = Redis.new(redis_options)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
next
|
72
|
-
end
|
73
|
-
Flapjack::Data::Contact.add(contact, :redis => @persistence)
|
67
|
+
contacts.each do |contact|
|
68
|
+
unless contact['id']
|
69
|
+
puts "Contact not imported as it has no id: " + contact.inspect
|
70
|
+
next
|
74
71
|
end
|
72
|
+
Flapjack::Data::Contact.add(contact, :redis => @persistence)
|
75
73
|
end
|
76
74
|
@persistence.quit
|
77
75
|
end
|
@@ -81,7 +79,6 @@ when "import-entities"
|
|
81
79
|
|
82
80
|
if entities && entities.is_a?(Enumerable) && entities.any? {|e| !e['id'].nil?}
|
83
81
|
@persistence = Redis.new(redis_options)
|
84
|
-
@persistence.multi
|
85
82
|
entities.each do |entity|
|
86
83
|
unless entity['id']
|
87
84
|
puts "Entity not imported as it has no id: " + entity.inspect
|
@@ -89,7 +86,6 @@ when "import-entities"
|
|
89
86
|
end
|
90
87
|
Flapjack::Data::Entity.add(entity, :redis => @persistence)
|
91
88
|
end
|
92
|
-
@persistence.exec
|
93
89
|
@persistence.quit
|
94
90
|
end
|
95
91
|
|
@@ -44,13 +44,11 @@ Feature: notifications
|
|
44
44
|
When the SMS notification handler fails to send an SMS
|
45
45
|
Then the user should not receive an SMS notification
|
46
46
|
|
47
|
-
@email
|
48
47
|
Scenario: Send a queued email notification
|
49
48
|
Given a user email notification has been queued for entity 'example.com'
|
50
49
|
When the email notification handler runs successfully
|
51
50
|
Then the user should receive an email notification
|
52
51
|
|
53
|
-
@email
|
54
52
|
Scenario: Handle a failure to send a queued email notification
|
55
53
|
Given a user email notification has been queued for entity 'example.com'
|
56
54
|
When the email notification handler fails to send an email
|
@@ -1,6 +1,4 @@
|
|
1
1
|
|
2
|
-
include Mail::Matchers
|
3
|
-
|
4
2
|
# copied from flapjack-populator
|
5
3
|
# TODO use Flapjack::Data::Contact.add
|
6
4
|
def add_contact(contact = {})
|
@@ -125,57 +123,72 @@ end
|
|
125
123
|
|
126
124
|
# TODO may need to get more complex, depending which SMS provider is used
|
127
125
|
When /^the SMS notification handler runs successfully$/ do
|
128
|
-
|
129
|
-
stub_request(:get, /.*/)
|
130
|
-
# TODO load config from cfg file instead?
|
131
|
-
Flapjack::Gateways::Sms.instance_variable_set('@config', {'username' => 'abcd', 'password' => 'efgh'})
|
126
|
+
@request = stub_request(:get, /^#{Regexp.escape(Flapjack::Gateways::SmsMessagenet::MESSAGENET_URL)}/)
|
132
127
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
@
|
128
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_set('@config', {'username' => 'abcd', 'password' => 'efgh'})
|
129
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_set('@logger', @logger)
|
130
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_set('@sent', 0)
|
131
|
+
Flapjack::Gateways::SmsMessagenet.perform(@sms_notification)
|
137
132
|
end
|
138
133
|
|
139
134
|
When /^the SMS notification handler fails to send an SMS$/ do
|
140
|
-
stub_request(:
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
@sms_sent = false
|
135
|
+
@request = stub_request(:get, /^#{Regexp.escape(Flapjack::Gateways::SmsMessagenet::MESSAGENET_URL)}/).to_return(:status => [500, "Internal Server Error"])
|
136
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_set('@config', {'username' => 'abcd', 'password' => 'efgh'})
|
137
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_set('@logger', @logger)
|
138
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_set('@sent', 0)
|
139
|
+
Flapjack::Gateways::SmsMessagenet.perform(@sms_notification)
|
146
140
|
end
|
147
141
|
|
148
142
|
When /^the email notification handler runs successfully$/ do
|
149
143
|
Resque.redis = @redis
|
150
|
-
Flapjack::Gateways::Email.bootstrap(:config => {})
|
151
|
-
|
152
|
-
|
153
|
-
|
144
|
+
Flapjack::Gateways::Email.bootstrap(:config => {'smtp_config' => {'host' => '127.0.0.1', 'port' => 2525}})
|
145
|
+
Flapjack::Gateways::Email.instance_variable_set('@logger', @logger)
|
146
|
+
Flapjack::Gateways::Email.instance_variable_set('@sent', 0)
|
147
|
+
|
148
|
+
# poor man's stubbing
|
149
|
+
EM::P::SmtpClient.class_eval {
|
150
|
+
def self.send(args = {})
|
151
|
+
me = MockEmailer.new
|
152
|
+
me.set_deferred_status :succeeded, OpenStruct.new(:code => 250)
|
153
|
+
me
|
154
|
+
end
|
155
|
+
}
|
156
|
+
|
157
|
+
Flapjack::Gateways::Email.perform(@email_notification)
|
154
158
|
end
|
155
159
|
|
156
|
-
# This doesn't work as I have it here -- sends a mail with an empty To: header instead.
|
157
|
-
# Might have to introduce Rspec's stubs here to fake bad mailer behaviour -- or if mail sending
|
158
|
-
# won't ever fail, don't test for failure?
|
159
160
|
When /^the email notification handler fails to send an email$/ do
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
161
|
+
Resque.redis = @redis
|
162
|
+
Flapjack::Gateways::Email.bootstrap(:config => {'smtp_config' => {'host' => '127.0.0.1', 'port' => 2525}})
|
163
|
+
Flapjack::Gateways::Email.instance_variable_set('@logger', @logger)
|
164
|
+
Flapjack::Gateways::Email.instance_variable_set('@sent', 0)
|
165
|
+
|
166
|
+
# poor man's stubbing
|
167
|
+
EM::P::SmtpClient.class_eval {
|
168
|
+
def self.send(args = {})
|
169
|
+
me = MockEmailer.new
|
170
|
+
me.set_deferred_status :failed, OpenStruct.new(:code => 500)
|
171
|
+
me
|
172
|
+
end
|
173
|
+
}
|
174
|
+
|
175
|
+
Flapjack::Gateways::Email.perform(@email_notification)
|
165
176
|
end
|
166
177
|
|
167
178
|
Then /^the user should receive an SMS notification$/ do
|
168
|
-
@
|
179
|
+
@request.should have_been_requested
|
180
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_get('@sent').should == 1
|
169
181
|
end
|
170
182
|
|
171
183
|
Then /^the user should receive an email notification$/ do
|
172
|
-
|
184
|
+
Flapjack::Gateways::Email.instance_variable_get('@sent').should == 1
|
173
185
|
end
|
174
186
|
|
175
187
|
Then /^the user should not receive an SMS notification$/ do
|
176
|
-
@
|
188
|
+
@request.should have_been_requested
|
189
|
+
Flapjack::Gateways::SmsMessagenet.instance_variable_get('@sent').should == 0
|
177
190
|
end
|
178
191
|
|
179
192
|
Then /^the user should not receive an email notification$/ do
|
180
|
-
|
193
|
+
Flapjack::Gateways::Email.instance_variable_get('@sent').should == 0
|
181
194
|
end
|
data/features/support/env.rb
CHANGED
@@ -38,8 +38,9 @@ class MockLogger
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
# poor man's stubbing
|
42
|
+
class MockEmailer
|
43
|
+
include EM::Deferrable
|
43
44
|
end
|
44
45
|
|
45
46
|
redis_opts = { :db => 14, :driver => :ruby }
|
@@ -79,10 +80,6 @@ Before('@resque') do
|
|
79
80
|
ResqueSpec.reset!
|
80
81
|
end
|
81
82
|
|
82
|
-
Before('@email') do
|
83
|
-
Mail::TestMailer.deliveries.clear
|
84
|
-
end
|
85
|
-
|
86
83
|
After('@time') do
|
87
84
|
Delorean.back_to_the_present
|
88
85
|
end
|
data/lib/flapjack/coordinator.rb
CHANGED
@@ -27,7 +27,7 @@ require 'flapjack/gateways/jabber'
|
|
27
27
|
require 'flapjack/gateways/oobetet'
|
28
28
|
require 'flapjack/gateways/pagerduty'
|
29
29
|
require 'flapjack/gateways/email'
|
30
|
-
require 'flapjack/gateways/
|
30
|
+
require 'flapjack/gateways/sms_messagenet'
|
31
31
|
require 'flapjack/gateways/web'
|
32
32
|
|
33
33
|
module Flapjack
|
@@ -270,7 +270,7 @@ module Flapjack
|
|
270
270
|
'pagerduty' => Flapjack::Gateways::Pagerduty,
|
271
271
|
'oobetet' => Flapjack::Gateways::Oobetet,
|
272
272
|
'email' => Flapjack::Gateways::Email,
|
273
|
-
'sms' => Flapjack::Gateways::
|
273
|
+
'sms' => Flapjack::Gateways::SmsMessagenet}
|
274
274
|
|
275
275
|
|
276
276
|
def pikelets(config_env)
|
@@ -36,24 +36,24 @@ module Flapjack
|
|
36
36
|
redis.keys('contacts_for:*') )
|
37
37
|
end
|
38
38
|
|
39
|
-
def self.find_by_id(
|
39
|
+
def self.find_by_id(contact_id, options = {})
|
40
40
|
raise "Redis connection not set" unless redis = options[:redis]
|
41
|
-
raise "No id value passed" unless
|
41
|
+
raise "No id value passed" unless contact_id
|
42
42
|
logger = options[:logger]
|
43
43
|
|
44
|
-
return unless redis.hexists("contact:#{
|
44
|
+
return unless redis.hexists("contact:#{contact_id}", 'first_name')
|
45
45
|
|
46
|
-
fn, ln, em = redis.hmget("contact:#{
|
47
|
-
me = redis.hgetall("contact_media:#{
|
46
|
+
fn, ln, em = redis.hmget("contact:#{contact_id}", 'first_name', 'last_name', 'email')
|
47
|
+
me = redis.hgetall("contact_media:#{contact_id}")
|
48
48
|
|
49
49
|
# similar to code in instance method pagerduty_credentials
|
50
50
|
pc = nil
|
51
|
-
if service_key = redis.hget("contact_media:#{
|
52
|
-
pc = redis.hgetall("contact_pagerduty:#{
|
51
|
+
if service_key = redis.hget("contact_media:#{contact_id}", 'pagerduty')
|
52
|
+
pc = redis.hgetall("contact_pagerduty:#{contact_id}").merge('service_key' => service_key)
|
53
53
|
end
|
54
54
|
|
55
55
|
self.new(:first_name => fn, :last_name => ln,
|
56
|
-
:email => em, :id =>
|
56
|
+
:email => em, :id => contact_id, :media => me, :pagerduty_credentials => pc, :redis => redis )
|
57
57
|
end
|
58
58
|
|
59
59
|
|
data/lib/flapjack/data/entity.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'flapjack/data/contact'
|
4
|
+
require 'flapjack/data/tag'
|
4
5
|
|
5
6
|
module Flapjack
|
6
7
|
|
@@ -8,7 +9,7 @@ module Flapjack
|
|
8
9
|
|
9
10
|
class Entity
|
10
11
|
|
11
|
-
attr_accessor :name, :id
|
12
|
+
attr_accessor :name, :id, :tags
|
12
13
|
|
13
14
|
def self.all(options = {})
|
14
15
|
raise "Redis connection not set" unless redis = options[:redis]
|
@@ -38,10 +39,14 @@ module Flapjack
|
|
38
39
|
redis.sadd("contacts_for:#{entity['id']}", contact_id)
|
39
40
|
}
|
40
41
|
end
|
42
|
+
self.new(:name => entity['name'],
|
43
|
+
:id => entity['id'],
|
44
|
+
:redis => redis)
|
41
45
|
else
|
42
46
|
# empty string is the redis equivalent of a Ruby nil, i.e. key with
|
43
47
|
# no value
|
44
48
|
redis.set("entity_id:#{entity['name']}", '')
|
49
|
+
nil
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
@@ -102,6 +107,21 @@ module Flapjack
|
|
102
107
|
checks.length
|
103
108
|
end
|
104
109
|
|
110
|
+
def add_tags(*enum)
|
111
|
+
enum.each do |t|
|
112
|
+
Flapjack::Data::Tag.create("#{@tag_prefix}:#{t}", [@id], :redis => @redis)
|
113
|
+
@tags.add(t)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def delete_tags(*enum)
|
118
|
+
enum.each do |t|
|
119
|
+
tag = Flapjack::Data::Tag.find("#{@tag_prefix}:#{t}", :redis => @redis)
|
120
|
+
tag.delete(@id)
|
121
|
+
@tags.delete(t)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
105
125
|
private
|
106
126
|
|
107
127
|
# NB: initializer should not be used directly -- instead one of the finder methods
|
@@ -111,6 +131,16 @@ module Flapjack
|
|
111
131
|
raise "Entity name not set" unless @name = options[:name]
|
112
132
|
@id = options[:id]
|
113
133
|
@logger = options[:logger]
|
134
|
+
|
135
|
+
@tag_prefix = 'entity_tag'
|
136
|
+
@tags = ::Set.new
|
137
|
+
tag_data = @redis.keys("#{@tag_prefix}:*").inject([]) do |memo, entity_tag|
|
138
|
+
tag = Flapjack::Data::Tag.find(entity_tag, :redis => @redis)
|
139
|
+
memo << entity_tag.sub(%r(^#{@tag_prefix}:), '') if tag.include?(@id.to_s)
|
140
|
+
memo
|
141
|
+
end
|
142
|
+
@tags.merge(tag_data)
|
143
|
+
|
114
144
|
end
|
115
145
|
|
116
146
|
end
|
data/lib/flapjack/data/event.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require 'redis'
|
5
|
+
|
6
|
+
module Flapjack
|
7
|
+
module Data
|
8
|
+
|
9
|
+
class Tag < ::Set
|
10
|
+
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
def initialize(opts)
|
14
|
+
@name = opts[:name]
|
15
|
+
@redis = opts[:redis]
|
16
|
+
preset = @redis.smembers(@name)
|
17
|
+
enum = opts[:create] || []
|
18
|
+
@redis.sadd(@name, enum) unless enum.empty?
|
19
|
+
super(enum | preset)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.find(name, opts)
|
23
|
+
self.new(:name => name,
|
24
|
+
:redis => opts[:redis])
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.create(name, enum = [], opts)
|
28
|
+
self.new(:name => name,
|
29
|
+
:create => enum,
|
30
|
+
:redis => opts[:redis])
|
31
|
+
end
|
32
|
+
|
33
|
+
def add(o)
|
34
|
+
@redis.sadd(@name, o) unless o.empty?
|
35
|
+
super(o)
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete(o)
|
39
|
+
@redis.srem(@name, o)
|
40
|
+
super(o)
|
41
|
+
end
|
42
|
+
|
43
|
+
def merge(o)
|
44
|
+
@redis.sadd(@name, o) unless o.empty?
|
45
|
+
super(o)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
data/lib/flapjack/executive.rb
CHANGED
@@ -18,7 +18,7 @@ require 'flapjack/pikelet'
|
|
18
18
|
require 'flapjack/redis_pool'
|
19
19
|
|
20
20
|
require 'flapjack/gateways/email'
|
21
|
-
require 'flapjack/gateways/
|
21
|
+
require 'flapjack/gateways/sms_messagenet'
|
22
22
|
|
23
23
|
module Flapjack
|
24
24
|
|
@@ -256,7 +256,7 @@ module Flapjack
|
|
256
256
|
# TODO consider changing Resque jobs to use raw blpop like the others
|
257
257
|
case media_type
|
258
258
|
when :sms
|
259
|
-
Resque.enqueue_to(@queues[:sms], Flapjack::Gateways::
|
259
|
+
Resque.enqueue_to(@queues[:sms], Flapjack::Gateways::SmsMessagenet, contents)
|
260
260
|
when :email
|
261
261
|
Resque.enqueue_to(@queues[:email], Flapjack::Gateways::Email, contents)
|
262
262
|
when :jabber
|
@@ -5,8 +5,10 @@ require 'erb'
|
|
5
5
|
require 'haml'
|
6
6
|
require 'socket'
|
7
7
|
|
8
|
-
require '
|
8
|
+
require 'em-synchrony'
|
9
|
+
require 'em/protocols/smtpclient'
|
9
10
|
|
11
|
+
require 'flapjack/data/entity_check'
|
10
12
|
require 'flapjack/gateways/base'
|
11
13
|
|
12
14
|
module Flapjack
|
@@ -19,24 +21,10 @@ module Flapjack
|
|
19
21
|
|
20
22
|
alias_method :orig_bootstrap, :bootstrap
|
21
23
|
|
22
|
-
# See https://github.com/mikel/mail/blob/master/lib/mail/mail.rb#L53
|
23
|
-
# & https://github.com/mikel/mail/blob/master/spec/mail/configuration_spec.rb
|
24
|
-
# for details of configuring mail gem. defaults to SMTP, localhost, port 25
|
25
24
|
def bootstrap(opts = {})
|
26
25
|
return if @bootstrapped
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if sc
|
31
|
-
smtp_config = sc.keys.inject({}) do |ret,obj|
|
32
|
-
ret[obj.to_sym] = sc[obj]
|
33
|
-
ret
|
34
|
-
end
|
35
|
-
|
36
|
-
Mail.defaults {
|
37
|
-
delivery_method :smtp, {:enable_starttls_auto => false}.merge(smtp_config)
|
38
|
-
}
|
39
|
-
end
|
26
|
+
@smtp_config = opts[:config].delete('smtp_config')
|
27
|
+
@sent = 0
|
40
28
|
orig_bootstrap(opts)
|
41
29
|
end
|
42
30
|
|
@@ -49,7 +37,6 @@ module Flapjack
|
|
49
37
|
state = notification['state']
|
50
38
|
summary = notification['summary']
|
51
39
|
time = notification['time']
|
52
|
-
entity, check = notification['event_id'].split(':')
|
53
40
|
|
54
41
|
entity_check = Flapjack::Data::EntityCheck.for_event_id(notification['event_id'],
|
55
42
|
:redis => ::Resque.redis)
|
@@ -63,37 +50,58 @@ module Flapjack
|
|
63
50
|
|
64
51
|
headline = headline_map[notification_type] || ''
|
65
52
|
|
66
|
-
subject = "#{headline}'#{check}' on #{
|
53
|
+
subject = "#{headline}'#{entity_check.check}' on #{entity_check.entity_name}"
|
67
54
|
subject += " is #{state.upcase}" unless ['acknowledgement', 'test'].include?(notification_type)
|
68
55
|
|
69
56
|
notification['subject'] = subject
|
70
57
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
58
|
+
begin
|
59
|
+
host = @smtp_config ? @smtp_config['host'] : nil
|
60
|
+
port = @smtp_config ? @smtp_config['port'] : nil
|
61
|
+
|
62
|
+
fqdn = `/bin/hostname -f`.chomp
|
63
|
+
m_from = "flapjack@#{fqdn}"
|
64
|
+
logger.debug("flapjack_mailer: set from to #{m_from}")
|
65
|
+
m_reply_to = m_from
|
66
|
+
m_to = notification['address']
|
67
|
+
|
68
|
+
mail = prepare_email(notification,
|
69
|
+
:from => m_from, :to => m_to,
|
70
|
+
:in_scheduled_maintenance => entity_check.in_scheduled_maintenance?,
|
71
|
+
:in_unscheduled_maintenance => entity_check.in_unscheduled_maintenance?)
|
72
|
+
|
73
|
+
email = EM::P::SmtpClient.send(
|
74
|
+
:from => m_from,
|
75
|
+
:to => m_to,
|
76
|
+
:content => "#{mail.to_s}\r\n.\r\n",
|
77
|
+
:domain => fqdn,
|
78
|
+
:host => host || 'localhost',
|
79
|
+
:port => port || 25)
|
80
|
+
|
81
|
+
response = EM::Synchrony.sync(email)
|
82
|
+
|
83
|
+
# http://tools.ietf.org/html/rfc821#page-36 SMTP response codes
|
84
|
+
if response && response.respond_to?(:code) &&
|
85
|
+
((response.code == 250) || (response.code == 251))
|
86
|
+
@logger.info "Email sending succeeded"
|
87
|
+
@sent += 1
|
88
|
+
else
|
89
|
+
@logger.info "Email sending failed"
|
90
|
+
end
|
91
|
+
|
92
|
+
@logger.info "Email response: #{response.inspect}"
|
93
|
+
|
94
|
+
rescue Exception => e
|
95
|
+
@logger.error "Error delivering email to #{mail.to}: #{e.message}"
|
96
|
+
@logger.error e.backtrace.join("\n")
|
97
|
+
end
|
75
98
|
end
|
76
99
|
|
77
100
|
end
|
78
101
|
|
79
102
|
private
|
80
103
|
|
81
|
-
def self.prepare_email(notification, opts)
|
82
|
-
|
83
|
-
logger = opts[:logger]
|
84
|
-
|
85
|
-
# not using socket and gethostname as that doesn't give you a fqdn.
|
86
|
-
# see the facter issue: https://projects.puppetlabs.com/issues/3898
|
87
|
-
fqdn = `/bin/hostname -f`.chomp
|
88
|
-
m_from = "flapjack@#{fqdn}"
|
89
|
-
logger.debug("flapjack_mailer: set from to #{m_from}")
|
90
|
-
m_reply_to = m_from
|
91
|
-
|
92
|
-
m_to = notification['address']
|
93
|
-
m_subject = notification['subject']
|
94
|
-
|
95
|
-
logger.debug("sending Flapjack::Notification::Email " +
|
96
|
-
"#{notification['id']} to: #{m_to} subject: #{m_subject}")
|
104
|
+
def self.prepare_email(notification, opts = {})
|
97
105
|
|
98
106
|
@notification_type = notification['notification_type']
|
99
107
|
@contact_first_name = notification['contact_first_name']
|
@@ -105,6 +113,11 @@ module Flapjack
|
|
105
113
|
@in_unscheduled_maintenance = opts[:in_unscheduled_maintenance]
|
106
114
|
@in_scheduled_maintenance = opts[:in_scheduled_maintenance]
|
107
115
|
|
116
|
+
m_subject = notification['subject']
|
117
|
+
|
118
|
+
@logger.debug("sending Flapjack::Notification::Email " +
|
119
|
+
"#{notification['id']} to: #{opts[:to]} subject: #{m_subject}")
|
120
|
+
|
108
121
|
text_template = ERB.new(File.read(File.dirname(__FILE__) +
|
109
122
|
'/email/alert.text.erb'))
|
110
123
|
|
@@ -113,11 +126,13 @@ module Flapjack
|
|
113
126
|
|
114
127
|
mail_scope = self
|
115
128
|
|
129
|
+
# this part is the only use of the mail gem -- maybe this can be done
|
130
|
+
# using standard library calls instead?
|
116
131
|
mail = Mail.new do
|
117
|
-
from
|
118
|
-
to
|
132
|
+
from opts[:from]
|
133
|
+
to opts[:to]
|
119
134
|
subject m_subject
|
120
|
-
reply_to
|
135
|
+
reply_to opts[:from]
|
121
136
|
|
122
137
|
text_part do
|
123
138
|
body text_template.result(binding)
|
@@ -111,7 +111,7 @@ module Flapjack
|
|
111
111
|
|
112
112
|
stanza_body = stanza.body
|
113
113
|
|
114
|
-
logger.debug("groupchat stanza body: "
|
114
|
+
logger.debug("groupchat stanza body: #{stanza_body}")
|
115
115
|
logger.debug("groupchat message received: #{stanza.inspect}")
|
116
116
|
|
117
117
|
if (stanza_body =~ /^(?:problem|recovery|acknowledgement)/i) &&
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'em-synchrony'
|
4
|
+
require 'em-synchrony/em-http'
|
5
|
+
|
6
|
+
require 'flapjack/gateways/base'
|
7
|
+
|
8
|
+
module Flapjack
|
9
|
+
module Gateways
|
10
|
+
class SmsMessagenet
|
11
|
+
extend Flapjack::Gateways::Resque
|
12
|
+
|
13
|
+
MESSAGENET_URL = 'https://www.messagenet.com.au/dotnet/Lodge.asmx/LodgeSMSMessage'
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
alias_method :orig_bootstrap, :bootstrap
|
18
|
+
|
19
|
+
def bootstrap(opts = {})
|
20
|
+
return if @bootstrapped
|
21
|
+
@sent = 0
|
22
|
+
orig_bootstrap(opts)
|
23
|
+
end
|
24
|
+
|
25
|
+
def perform(notification)
|
26
|
+
logger.debug "Woo, got a notification to send out: #{notification.inspect}"
|
27
|
+
|
28
|
+
notification_type = notification['notification_type']
|
29
|
+
contact_first_name = notification['contact_first_name']
|
30
|
+
contact_last_name = notification['contact_last_name']
|
31
|
+
state = notification['state']
|
32
|
+
summary = notification['summary']
|
33
|
+
time = notification['time']
|
34
|
+
entity, check = notification['event_id'].split(':')
|
35
|
+
|
36
|
+
headline_map = {'problem' => 'PROBLEM: ',
|
37
|
+
'recovery' => 'RECOVERY: ',
|
38
|
+
'acknowledgement' => 'ACK: ',
|
39
|
+
'test' => 'TEST NOTIFICATION: ',
|
40
|
+
'unknown' => '',
|
41
|
+
'' => '',
|
42
|
+
}
|
43
|
+
|
44
|
+
headline = headline_map[notification_type] || ''
|
45
|
+
|
46
|
+
message = "#{headline}'#{check}' on #{entity}"
|
47
|
+
message += " is #{state.upcase}" unless ['acknowledgement', 'test'].include?(notification_type)
|
48
|
+
message += " at #{Time.at(time).strftime('%-d %b %H:%M')}, #{summary}"
|
49
|
+
|
50
|
+
notification['message'] = message
|
51
|
+
|
52
|
+
# TODO log error and skip instead of raising errors
|
53
|
+
if config.nil? || (config.respond_to?(:empty?) && config.empty?)
|
54
|
+
logger.error "Messagenet config is missing"
|
55
|
+
return
|
56
|
+
end
|
57
|
+
|
58
|
+
errors = []
|
59
|
+
|
60
|
+
username = config["username"]
|
61
|
+
password = config["password"]
|
62
|
+
address = notification['address']
|
63
|
+
message = notification['message']
|
64
|
+
notification_id = notification['id']
|
65
|
+
|
66
|
+
[[username, "Messagenet username is missing"],
|
67
|
+
[password, "Messagenet password is missing"],
|
68
|
+
[address, "SMS address is missing"],
|
69
|
+
[message, "SMS message is missing"],
|
70
|
+
[notification_id, "Notification id is missing"]].each do |val_err|
|
71
|
+
|
72
|
+
next unless val_err.first.nil? || (val_err.first.respond_to?(:empty?) && val_err.first.empty?)
|
73
|
+
errors << val_err.last
|
74
|
+
end
|
75
|
+
|
76
|
+
unless errors.empty?
|
77
|
+
errors.each {|err| logger.error err }
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
81
|
+
query = {'Username' => username,
|
82
|
+
'Pwd' => password,
|
83
|
+
'PhoneNumber' => address,
|
84
|
+
'PhoneMessage' => message}
|
85
|
+
|
86
|
+
http = EM::HttpRequest.new(MESSAGENET_URL).get(:query => query)
|
87
|
+
|
88
|
+
logger.debug "server response: #{http.response}"
|
89
|
+
|
90
|
+
status = (http.nil? || http.response_header.nil?) ? nil : http.response_header.status
|
91
|
+
if (status >= 200) && (status <= 206)
|
92
|
+
@sent += 1
|
93
|
+
logger.info "Sent SMS via Messagenet, response status is #{status}, " +
|
94
|
+
"notification_id: #{notification_id}"
|
95
|
+
else
|
96
|
+
logger.error "Failed to send SMS via Messagenet, response status is #{status}, " +
|
97
|
+
"notification_id: #{notification_id}"
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
data/lib/flapjack/version.rb
CHANGED
@@ -135,4 +135,57 @@ describe Flapjack::Data::Entity, :redis => true do
|
|
135
135
|
entities.first.should == 'abc-123'
|
136
136
|
end
|
137
137
|
|
138
|
-
|
138
|
+
it "adds tags to entities" do
|
139
|
+
entity = Flapjack::Data::Entity.add({'id' => '5000',
|
140
|
+
'name' => 'abc-123',
|
141
|
+
'contacts' => []},
|
142
|
+
:redis => @redis)
|
143
|
+
|
144
|
+
entity.add_tags('source:foobar', 'foo')
|
145
|
+
|
146
|
+
entity.should_not be_nil
|
147
|
+
entity.should be_an(Flapjack::Data::Entity)
|
148
|
+
entity.name.should == 'abc-123'
|
149
|
+
entity.tags.should include("source:foobar")
|
150
|
+
entity.tags.should include("foo")
|
151
|
+
|
152
|
+
# and test the tags as read back from redis
|
153
|
+
entity = Flapjack::Data::Entity.find_by_id('5000', :redis => @redis)
|
154
|
+
entity.tags.should include("source:foobar")
|
155
|
+
entity.tags.should include("foo")
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
it "deletes tags from entities" do
|
160
|
+
entity = Flapjack::Data::Entity.add({'id' => '5000',
|
161
|
+
'name' => 'abc-123',
|
162
|
+
'contacts' => []},
|
163
|
+
:redis => @redis)
|
164
|
+
|
165
|
+
entity.add_tags('source:foobar', 'foo')
|
166
|
+
|
167
|
+
entity.should_not be_nil
|
168
|
+
entity.tags.should include("source:foobar")
|
169
|
+
entity.tags.should include("foo")
|
170
|
+
|
171
|
+
entity.delete_tags('source:foobar')
|
172
|
+
|
173
|
+
entity.tags.should_not include("source:foobar")
|
174
|
+
entity.tags.should include("foo")
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
it "finds entities by tag" do
|
179
|
+
entity = Flapjack::Data::Entity.add({'id' => '5000',
|
180
|
+
'name' => 'abc-123',
|
181
|
+
'contacts' => []},
|
182
|
+
:redis => @redis)
|
183
|
+
|
184
|
+
entity.add_tags('source:foobar', 'foo')
|
185
|
+
|
186
|
+
entity.should_not be_nil
|
187
|
+
entity.should be_an(Flapjack::Data::Entity)
|
188
|
+
# TODO - the rest of it
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
data/tasks/events.rake
CHANGED
@@ -13,12 +13,17 @@ namespace :events do
|
|
13
13
|
|
14
14
|
require 'flapjack/configuration'
|
15
15
|
require 'flapjack/data/event'
|
16
|
+
require 'flapjack/data/entity_check'
|
16
17
|
|
17
18
|
FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'development'
|
18
19
|
config_file = File.join('etc', 'flapjack_config.yaml')
|
19
|
-
|
20
|
+
config = Flapjack::Configuration.new
|
21
|
+
config.load( config_file )
|
20
22
|
|
21
|
-
|
23
|
+
@config_env = config.all
|
24
|
+
@redis_config = config.for_redis
|
25
|
+
|
26
|
+
if @config_env.nil? || @config_env.empty?
|
22
27
|
puts "No config data for environment '#{FLAPJACK_ENV}' found in '#{config_file}'"
|
23
28
|
exit(false)
|
24
29
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flapjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.47
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-11-
|
14
|
+
date: 2012-11-21 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: daemons
|
@@ -390,6 +390,7 @@ files:
|
|
390
390
|
- lib/flapjack/data/global.rb
|
391
391
|
- lib/flapjack/data/message.rb
|
392
392
|
- lib/flapjack/data/notification.rb
|
393
|
+
- lib/flapjack/data/tag.rb
|
393
394
|
- lib/flapjack/executive.rb
|
394
395
|
- lib/flapjack/filters/acknowledgement.rb
|
395
396
|
- lib/flapjack/filters/base.rb
|
@@ -408,8 +409,7 @@ files:
|
|
408
409
|
- lib/flapjack/gateways/jabber.rb
|
409
410
|
- lib/flapjack/gateways/oobetet.rb
|
410
411
|
- lib/flapjack/gateways/pagerduty.rb
|
411
|
-
- lib/flapjack/gateways/
|
412
|
-
- lib/flapjack/gateways/sms/messagenet.rb
|
412
|
+
- lib/flapjack/gateways/sms_messagenet.rb
|
413
413
|
- lib/flapjack/gateways/web.rb
|
414
414
|
- lib/flapjack/gateways/web/views/_css.haml
|
415
415
|
- lib/flapjack/gateways/web/views/_nav.haml
|
@@ -432,6 +432,7 @@ files:
|
|
432
432
|
- spec/lib/flapjack/data/global_spec.rb
|
433
433
|
- spec/lib/flapjack/data/message_spec.rb
|
434
434
|
- spec/lib/flapjack/data/notification_spec.rb
|
435
|
+
- spec/lib/flapjack/data/tag_spec.rb
|
435
436
|
- spec/lib/flapjack/executive_spec.rb
|
436
437
|
- spec/lib/flapjack/filters/acknowledgement_spec.rb
|
437
438
|
- spec/lib/flapjack/filters/delays_spec.rb
|
@@ -446,7 +447,7 @@ files:
|
|
446
447
|
- spec/lib/flapjack/gateways/jabber_spec.rb
|
447
448
|
- spec/lib/flapjack/gateways/oobetet_spec.rb
|
448
449
|
- spec/lib/flapjack/gateways/pagerduty_spec.rb
|
449
|
-
- spec/lib/flapjack/gateways/
|
450
|
+
- spec/lib/flapjack/gateways/sms_messagenet.spec.rb
|
450
451
|
- spec/lib/flapjack/gateways/web_spec.rb
|
451
452
|
- spec/lib/flapjack/pikelet_spec.rb
|
452
453
|
- spec/lib/flapjack/redis_pool_spec.rb
|
@@ -511,6 +512,7 @@ test_files:
|
|
511
512
|
- spec/lib/flapjack/data/global_spec.rb
|
512
513
|
- spec/lib/flapjack/data/message_spec.rb
|
513
514
|
- spec/lib/flapjack/data/notification_spec.rb
|
515
|
+
- spec/lib/flapjack/data/tag_spec.rb
|
514
516
|
- spec/lib/flapjack/executive_spec.rb
|
515
517
|
- spec/lib/flapjack/filters/acknowledgement_spec.rb
|
516
518
|
- spec/lib/flapjack/filters/delays_spec.rb
|
@@ -525,7 +527,7 @@ test_files:
|
|
525
527
|
- spec/lib/flapjack/gateways/jabber_spec.rb
|
526
528
|
- spec/lib/flapjack/gateways/oobetet_spec.rb
|
527
529
|
- spec/lib/flapjack/gateways/pagerduty_spec.rb
|
528
|
-
- spec/lib/flapjack/gateways/
|
530
|
+
- spec/lib/flapjack/gateways/sms_messagenet.spec.rb
|
529
531
|
- spec/lib/flapjack/gateways/web_spec.rb
|
530
532
|
- spec/lib/flapjack/pikelet_spec.rb
|
531
533
|
- spec/lib/flapjack/redis_pool_spec.rb
|
@@ -1,53 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'flapjack/pikelet'
|
4
|
-
require 'flapjack/gateways/sms/messagenet'
|
5
|
-
|
6
|
-
module Flapjack
|
7
|
-
module Gateways
|
8
|
-
|
9
|
-
class Sms
|
10
|
-
extend Flapjack::Gateways::Resque
|
11
|
-
|
12
|
-
class << self
|
13
|
-
|
14
|
-
def perform(notification)
|
15
|
-
@logger.debug "Woo, got a notification to send out: #{notification.inspect}"
|
16
|
-
dispatch(notification, :logger => @logger, :redis => ::Resque.redis)
|
17
|
-
end
|
18
|
-
|
19
|
-
def dispatch(notification, opts = {})
|
20
|
-
notification_type = notification['notification_type']
|
21
|
-
contact_first_name = notification['contact_first_name']
|
22
|
-
contact_last_name = notification['contact_last_name']
|
23
|
-
state = notification['state']
|
24
|
-
summary = notification['summary']
|
25
|
-
time = notification['time']
|
26
|
-
entity, check = notification['event_id'].split(':')
|
27
|
-
|
28
|
-
headline_map = {'problem' => 'PROBLEM: ',
|
29
|
-
'recovery' => 'RECOVERY: ',
|
30
|
-
'acknowledgement' => 'ACK: ',
|
31
|
-
'test' => 'TEST NOTIFICATION: ',
|
32
|
-
'unknown' => '',
|
33
|
-
'' => '',
|
34
|
-
}
|
35
|
-
|
36
|
-
headline = headline_map[notification_type] || ''
|
37
|
-
|
38
|
-
message = "#{headline}'#{check}' on #{entity}"
|
39
|
-
message += " is #{state.upcase}" unless ['acknowledgement', 'test'].include?(notification_type)
|
40
|
-
message += " at #{Time.at(time).strftime('%-d %b %H:%M')}, #{summary}"
|
41
|
-
|
42
|
-
notification['message'] = message
|
43
|
-
Flapjack::Gateways::Sms::Messagenet.sender(notification,
|
44
|
-
:logger => opts[:logger],
|
45
|
-
:config => Flapjack::Gateways::Sms.instance_variable_get('@config'))
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
@@ -1,49 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'net/http'
|
4
|
-
require 'uri'
|
5
|
-
|
6
|
-
module Flapjack
|
7
|
-
module Gateways
|
8
|
-
class Sms
|
9
|
-
class Messagenet
|
10
|
-
|
11
|
-
def self.sender(notification, options = {})
|
12
|
-
logger = options[:logger]
|
13
|
-
config = options[:config]
|
14
|
-
|
15
|
-
unless config && (username = config["username"])
|
16
|
-
raise RuntimeError.new('sms_messagenet: username is missing')
|
17
|
-
end
|
18
|
-
unless config && (password = config["password"])
|
19
|
-
raise RuntimeError.new('sms_messagenet: password is missing')
|
20
|
-
end
|
21
|
-
|
22
|
-
raise RuntimeError.new('address is missing') unless address = notification['address']
|
23
|
-
raise RuntimeError.new('message is missing') unless message = notification['message']
|
24
|
-
raise RuntimeError.new('id is missing') unless notification_id = notification['id']
|
25
|
-
|
26
|
-
params = { 'Username' => username,
|
27
|
-
'Pwd' => password,
|
28
|
-
'PhoneNumber' => address,
|
29
|
-
'PhoneMessage' => message }
|
30
|
-
|
31
|
-
uri = URI('https://www.messagenet.com.au/dotnet/Lodge.asmx/LodgeSMSMessage')
|
32
|
-
uri.query = URI.encode_www_form(params)
|
33
|
-
logger.debug("request_uri: #{uri.request_uri.inspect}")
|
34
|
-
|
35
|
-
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
36
|
-
request = Net::HTTP::Get.new uri.request_uri
|
37
|
-
response = http.request request
|
38
|
-
http_success = ( response.is_a?(Net::HTTPSuccess) == true )
|
39
|
-
logger.debug("Flapjack::Notification::SMSMessagenet: response from server: #{response.body}")
|
40
|
-
raise RuntimeError.new "Failed to send SMS via messagenet, http response is a #{response.class}, notification_id: #{notification_id}" unless http_success
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
|