flapjack 0.6.46 → 0.6.47
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|