flapjack 1.2.1 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +11 -12
- data/CHANGELOG.md +10 -0
- data/Gemfile +0 -7
- data/Rakefile +0 -1
- data/bin/flapjack +2 -0
- data/etc/flapjack_config.yaml.example +20 -0
- data/features/ack_after_sched_maint.feature +1 -1
- data/features/cli.feature +1 -1
- data/features/notification_rules.feature +1 -1
- data/features/notifications.feature +0 -9
- data/features/rollup.feature +1 -1
- data/features/steps/events_steps.rb +20 -8
- data/features/steps/notifications_steps.rb +62 -75
- data/features/support/env.rb +17 -8
- data/flapjack.gemspec +4 -4
- data/lib/flapjack.rb +3 -0
- data/lib/flapjack/cli/import.rb +1 -0
- data/lib/flapjack/cli/maintenance.rb +1 -0
- data/lib/flapjack/cli/purge.rb +2 -0
- data/lib/flapjack/cli/receiver.rb +1 -0
- data/lib/flapjack/cli/simulate.rb +1 -0
- data/lib/flapjack/data/alert.rb +28 -1
- data/lib/flapjack/data/contact.rb +1 -1
- data/lib/flapjack/data/entity.rb +18 -8
- data/lib/flapjack/data/entity_check.rb +17 -0
- data/lib/flapjack/data/event.rb +33 -15
- data/lib/flapjack/data/migration.rb +46 -23
- data/lib/flapjack/filters/delays.rb +13 -6
- data/lib/flapjack/gateways/aws_sns.rb +115 -88
- data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -1
- data/lib/flapjack/gateways/email.rb +145 -135
- data/lib/flapjack/gateways/email/alert.html.erb +6 -4
- data/lib/flapjack/gateways/email/alert.text.erb +2 -0
- data/lib/flapjack/gateways/jabber.rb +61 -1
- data/lib/flapjack/gateways/jabber/alert.text.erb +1 -1
- data/lib/flapjack/gateways/pagerduty/alert.text.erb +1 -1
- data/lib/flapjack/gateways/sms_gammu.rb +119 -0
- data/lib/flapjack/gateways/sms_messagenet.rb +95 -67
- data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +2 -1
- data/lib/flapjack/gateways/sms_twilio.rb +102 -74
- data/lib/flapjack/gateways/sms_twilio/alert.text.erb +2 -1
- data/lib/flapjack/logger.rb +1 -1
- data/lib/flapjack/notifier.rb +5 -14
- data/lib/flapjack/patches.rb +0 -58
- data/lib/flapjack/pikelet.rb +8 -78
- data/lib/flapjack/processor.rb +3 -1
- data/lib/flapjack/redis_pool.rb +2 -0
- data/lib/flapjack/version.rb +1 -1
- data/spec/lib/flapjack/data/contact_spec.rb +2 -2
- data/spec/lib/flapjack/data/entity_spec.rb +15 -0
- data/spec/lib/flapjack/data/event_spec.rb +2 -2
- data/spec/lib/flapjack/data/migration_spec.rb +11 -0
- data/spec/lib/flapjack/gateways/aws_sns_spec.rb +12 -8
- data/spec/lib/flapjack/gateways/email_spec.rb +56 -51
- data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +17 -12
- data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +17 -12
- data/spec/lib/flapjack/pikelet_spec.rb +9 -23
- data/spec/lib/flapjack/redis_pool_spec.rb +1 -0
- data/tasks/profile.rake +25 -109
- metadata +37 -39
- data/Gemfile-ruby1.9 +0 -30
- data/Gemfile-ruby1.9.lock +0 -250
- data/tasks/benchmarks.rake +0 -237
@@ -20,8 +20,15 @@ module Flapjack
|
|
20
20
|
include Base
|
21
21
|
|
22
22
|
def block?(event, entity_check, previous_state)
|
23
|
-
|
24
|
-
|
23
|
+
initial_failure_delay = entity_check.initial_failure_delay
|
24
|
+
if initial_failure_delay.nil? || (initial_failure_delay < 0)
|
25
|
+
initial_failure_delay = Flapjack::DEFAULT_INITIAL_FAILURE_DELAY
|
26
|
+
end
|
27
|
+
|
28
|
+
repeat_failure_delay = entity_check.repeat_failure_delay
|
29
|
+
if repeat_failure_delay.nil? || (repeat_failure_delay < 0)
|
30
|
+
repeat_failure_delay = Flapjack::DEFAULT_REPEAT_FAILURE_DELAY
|
31
|
+
end
|
25
32
|
|
26
33
|
label = 'Filter: Delays:'
|
27
34
|
|
@@ -51,18 +58,18 @@ module Flapjack
|
|
51
58
|
"event.state: [#{event.state.inspect}], " +
|
52
59
|
"last_alert_state == event.state ? #{last_alert_state.to_s == event.state}")
|
53
60
|
|
54
|
-
if current_state_duration <
|
61
|
+
if current_state_duration < initial_failure_delay
|
55
62
|
@logger.debug("#{label} block - duration of current failure " +
|
56
|
-
"(#{current_state_duration}) is less than
|
63
|
+
"(#{current_state_duration}) is less than initial_failure_delay (#{initial_failure_delay})")
|
57
64
|
return true
|
58
65
|
end
|
59
66
|
|
60
|
-
if !last_problem_alert.nil? && (time_since_last_alert <
|
67
|
+
if !last_problem_alert.nil? && (time_since_last_alert < repeat_failure_delay) &&
|
61
68
|
(last_alert_state.to_s == event.state)
|
62
69
|
|
63
70
|
@logger.debug("#{label} block - time since last alert for " +
|
64
71
|
"current problem (#{time_since_last_alert}) is less than " +
|
65
|
-
"
|
72
|
+
"repeat_failure_delay (#{repeat_failure_delay}) and last alert state (#{last_alert_state}) " +
|
66
73
|
"is equal to current event state (#{event.state})")
|
67
74
|
return true
|
68
75
|
end
|
@@ -4,6 +4,8 @@ require 'em-synchrony'
|
|
4
4
|
require 'em-synchrony/em-http'
|
5
5
|
require 'active_support/inflector'
|
6
6
|
|
7
|
+
require 'flapjack/redis_pool'
|
8
|
+
|
7
9
|
require 'flapjack/data/alert'
|
8
10
|
require 'flapjack/utility'
|
9
11
|
|
@@ -13,121 +15,146 @@ module Flapjack
|
|
13
15
|
|
14
16
|
SNS_DEFAULT_REGION_NAME = 'us-east-1'
|
15
17
|
|
16
|
-
|
18
|
+
include Flapjack::Utility
|
17
19
|
|
18
|
-
|
20
|
+
def initialize(opts = {})
|
21
|
+
@config = opts[:config]
|
22
|
+
@logger = opts[:logger]
|
23
|
+
@redis_config = opts[:redis_config] || {}
|
24
|
+
@redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1, :logger => @logger)
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
26
|
+
@logger.info("starting")
|
27
|
+
@logger.debug("new aws_sns gateway pikelet with the following options: #{@config.inspect}")
|
23
28
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
notification_id = alert.notification_id
|
37
|
-
message_type = alert.rollup ? 'rollup' : 'alert'
|
38
|
-
|
39
|
-
my_dir = File.dirname(__FILE__)
|
40
|
-
sms_template_path = case
|
41
|
-
when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
|
42
|
-
@config['templates']["#{message_type}.text"]
|
43
|
-
else
|
44
|
-
my_dir + "/aws_sns/#{message_type}.text.erb"
|
45
|
-
end
|
46
|
-
sms_template = ERB.new(File.read(sms_template_path), nil, '-')
|
29
|
+
@sent = 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop
|
33
|
+
@logger.info("stopping")
|
34
|
+
@should_quit = true
|
35
|
+
|
36
|
+
redis_uri = @redis_config[:path] ||
|
37
|
+
"redis://#{@redis_config[:host] || '127.0.0.1'}:#{@redis_config[:port] || '6379'}/#{@redis_config[:db] || '0'}"
|
38
|
+
shutdown_redis = EM::Hiredis.connect(redis_uri)
|
39
|
+
shutdown_redis.rpush(@config['queue'], Flapjack.dump_json('notification_type' => 'shutdown'))
|
40
|
+
end
|
47
41
|
|
48
|
-
|
49
|
-
|
42
|
+
def start
|
43
|
+
queue = @config['queue']
|
50
44
|
|
45
|
+
until @should_quit
|
51
46
|
begin
|
52
|
-
|
47
|
+
@logger.debug("aws_sns gateway is going into blpop mode on #{queue}")
|
48
|
+
deliver( Flapjack::Data::Alert.next(queue, :redis => @redis, :logger => @logger) )
|
53
49
|
rescue => e
|
54
|
-
@logger.error "Error
|
55
|
-
"
|
56
|
-
raise
|
50
|
+
@logger.error "Error generating or dispatching AWS SNS message: #{e.class}: #{e.message}\n" +
|
51
|
+
e.backtrace.join("\n")
|
57
52
|
end
|
53
|
+
end
|
54
|
+
end
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
def deliver(alert)
|
57
|
+
region_name = @config["region_name"] || SNS_DEFAULT_REGION_NAME
|
58
|
+
hostname = "sns.#{region_name}.amazonaws.com"
|
59
|
+
endpoint = "http://#{hostname}/"
|
60
|
+
access_key = @config["access_key"]
|
61
|
+
secret_key = @config["secret_key"]
|
62
|
+
timestamp = @config["timestamp"] || DateTime.now.iso8601
|
63
|
+
|
64
|
+
address = alert.address
|
65
|
+
notification_id = alert.notification_id
|
66
|
+
message_type = alert.rollup ? 'rollup' : 'alert'
|
67
|
+
|
68
|
+
my_dir = File.dirname(__FILE__)
|
69
|
+
sms_template_path = case
|
70
|
+
when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
|
71
|
+
@config['templates']["#{message_type}.text"]
|
72
|
+
else
|
73
|
+
my_dir + "/aws_sns/#{message_type}.text.erb"
|
74
|
+
end
|
75
|
+
sms_template = ERB.new(File.read(sms_template_path), nil, '-')
|
63
76
|
|
64
|
-
|
77
|
+
@alert = alert
|
78
|
+
bnd = binding
|
65
79
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
80
|
+
begin
|
81
|
+
message = sms_template.result(bnd).chomp
|
82
|
+
rescue => e
|
83
|
+
@logger.error "Error while excuting the ERB for an sms: " +
|
84
|
+
"ERB being executed: #{sms_template_path}"
|
85
|
+
raise
|
86
|
+
end
|
70
87
|
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
if @config.nil? || (@config.respond_to?(:empty?) && @config.empty?)
|
89
|
+
@logger.error "AWS SNS config is missing"
|
90
|
+
return
|
91
|
+
end
|
74
92
|
|
75
|
-
|
76
|
-
errors.each {|err| @logger.error err }
|
77
|
-
return
|
78
|
-
end
|
93
|
+
errors = []
|
79
94
|
|
95
|
+
[[address, "AWS SNS topic ARN is missing"],
|
96
|
+
[access_key, "AWS SNS access key is missing"],
|
97
|
+
[secret_key, "AWS SNS secret key is missing"],
|
98
|
+
[notification_id, "Notification id is missing"]].each do |val_err|
|
80
99
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
'Action' => 'Publish',
|
85
|
-
'SignatureVersion' => 2,
|
86
|
-
'SignatureMethod' => 'HmacSHA256',
|
87
|
-
'Timestamp' => timestamp,
|
88
|
-
'AWSAccessKeyId' => access_key}
|
100
|
+
next unless val_err.first.nil? || (val_err.first.respond_to?(:empty?) && val_err.first.empty?)
|
101
|
+
errors << val_err.last
|
102
|
+
end
|
89
103
|
|
90
|
-
|
104
|
+
unless errors.empty?
|
105
|
+
errors.each {|err| @logger.error err }
|
106
|
+
return
|
107
|
+
end
|
91
108
|
|
92
|
-
|
109
|
+
query = {'Subject' => message,
|
110
|
+
'TopicArn' => address,
|
111
|
+
'Message' => message,
|
112
|
+
'Action' => 'Publish',
|
113
|
+
'SignatureVersion' => 2,
|
114
|
+
'SignatureMethod' => 'HmacSHA256',
|
115
|
+
'Timestamp' => timestamp,
|
116
|
+
'AWSAccessKeyId' => access_key}
|
93
117
|
|
94
|
-
|
118
|
+
string_to_sign = self.class.string_to_sign('POST', hostname, "/", query)
|
95
119
|
|
96
|
-
|
120
|
+
query['Signature'] = self.class.get_signature(secret_key, string_to_sign)
|
97
121
|
|
98
|
-
|
99
|
-
if (status >= 200) && (status <= 206)
|
100
|
-
@sent += 1
|
101
|
-
alert.record_send_success!
|
102
|
-
@logger.debug "Sent notification via SNS, response status is #{status}, " +
|
103
|
-
"notification_id: #{notification_id}"
|
104
|
-
else
|
105
|
-
@logger.error "Failed to send notification via SNS, response status is #{status}, " +
|
106
|
-
"notification_id: #{notification_id}"
|
107
|
-
end
|
108
|
-
rescue => e
|
109
|
-
@logger.error "Error generating or delivering notification to #{address}: #{e.class}: #{e.message}"
|
110
|
-
@logger.error e.backtrace.join("\n")
|
111
|
-
raise
|
112
|
-
end
|
122
|
+
http = EM::HttpRequest.new(endpoint).post(:query => query)
|
113
123
|
|
114
|
-
|
115
|
-
signature = OpenSSL::HMAC.digest('sha256', secret_key, string_to_sign)
|
124
|
+
@logger.debug "server response: #{http.response}"
|
116
125
|
|
117
|
-
|
126
|
+
status = (http.nil? || http.response_header.nil?) ? nil : http.response_header.status
|
127
|
+
if (status >= 200) && (status <= 206)
|
128
|
+
@sent += 1
|
129
|
+
alert.record_send_success!
|
130
|
+
@logger.debug "Sent notification via SNS, response status is #{status}, " +
|
131
|
+
"notification_id: #{notification_id}"
|
132
|
+
else
|
133
|
+
@logger.error "Failed to send notification via SNS, response status is #{status}, " +
|
134
|
+
"notification_id: #{notification_id}"
|
118
135
|
end
|
136
|
+
rescue => e
|
137
|
+
@logger.error "Error generating or delivering notification to #{address}: #{e.class}: #{e.message}"
|
138
|
+
@logger.error e.backtrace.join("\n")
|
139
|
+
raise
|
140
|
+
end
|
119
141
|
|
120
|
-
|
121
|
-
|
142
|
+
def self.get_signature(secret_key, string_to_sign)
|
143
|
+
signature = OpenSSL::HMAC.digest('sha256', secret_key, string_to_sign)
|
122
144
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
145
|
+
Base64.encode64(signature).strip
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.string_to_sign(method, host, uri, query)
|
149
|
+
query = query.sort_by { |key, value| key }
|
129
150
|
|
151
|
+
[method.upcase,
|
152
|
+
host.downcase,
|
153
|
+
uri,
|
154
|
+
URI.encode_www_form(query)
|
155
|
+
].join("\n")
|
130
156
|
end
|
157
|
+
|
131
158
|
end
|
132
159
|
end
|
133
160
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
+
<% summary = @alert.summary %>
|
1
2
|
<%= @alert.type_sentence_case %>: '<%= @alert.check %>' on <%= @alert.entity -%>
|
2
3
|
<% unless ['acknowledgement', 'test'].include?(@alert.notification_type) -%>
|
3
4
|
is <%= @alert.state_title_case -%>
|
4
5
|
<% end -%>
|
5
|
-
at <%= Time.at(@alert.time).strftime('%-d %b %H:%M')
|
6
|
+
at <%= Time.at(@alert.time).strftime('%-d %b %H:%M') %><%= (summary.nil? || summary.empty?) ? '' : ", #{summary}" -%>
|
@@ -9,6 +9,7 @@ require 'active_support/inflector'
|
|
9
9
|
require 'em-synchrony'
|
10
10
|
require 'em/protocols/smtpclient'
|
11
11
|
|
12
|
+
require 'flapjack/redis_pool'
|
12
13
|
require 'flapjack/utility'
|
13
14
|
|
14
15
|
require 'flapjack/data/entity_check'
|
@@ -19,169 +20,178 @@ module Flapjack
|
|
19
20
|
|
20
21
|
class Email
|
21
22
|
|
22
|
-
|
23
|
+
include Flapjack::Utility
|
23
24
|
|
24
|
-
|
25
|
+
def initialize(opts = {})
|
26
|
+
@config = opts[:config]
|
27
|
+
@logger = opts[:logger]
|
28
|
+
@redis_config = opts[:redis_config] || {}
|
29
|
+
@redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1, :logger => @logger)
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
# TODO refactor to remove complexity
|
35
|
-
def perform(contents)
|
36
|
-
@logger.debug "Woo, got an alert to send out: #{contents.inspect}"
|
37
|
-
alert = prepare(contents)
|
38
|
-
deliver(alert)
|
39
|
-
end
|
40
|
-
|
41
|
-
# sets a bunch of class instance variables for each email
|
42
|
-
def prepare(contents)
|
43
|
-
Flapjack::Data::Alert.new(contents, :logger => @logger)
|
44
|
-
rescue => e
|
45
|
-
@logger.error "Error preparing email to #{contents['address']}: #{e.class}: #{e.message}"
|
46
|
-
@logger.error e.backtrace.join("\n")
|
47
|
-
raise
|
48
|
-
end
|
31
|
+
@logger.info("starting")
|
32
|
+
@logger.debug("new email gateway pikelet with the following options: #{@config.inspect}")
|
33
|
+
@smtp_config = @config.delete('smtp_config')
|
34
|
+
@sent = 0
|
35
|
+
@fqdn = `/bin/hostname -f`.chomp
|
36
|
+
end
|
49
37
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
starttls = @smtp_config ? !! @smtp_config['starttls'] : nil
|
54
|
-
m_from = @smtp_config ? @smtp_config['from'] : "flapjack@#{@fqdn}"
|
55
|
-
m_reply_to = @smtp_config ? ( @smtp_config['reply_to'] ||= m_from ) : "flapjack@#{@fqdn}"
|
56
|
-
if @smtp_config
|
57
|
-
if auth_config = @smtp_config['auth']
|
58
|
-
auth = {}
|
59
|
-
auth[:type] = auth_config['type'].to_sym || :plain
|
60
|
-
auth[:username] = auth_config['username']
|
61
|
-
auth[:password] = auth_config['password']
|
62
|
-
end
|
63
|
-
end
|
38
|
+
def stop
|
39
|
+
@logger.info("stopping")
|
40
|
+
@should_quit = true
|
64
41
|
|
65
|
-
|
42
|
+
redis_uri = @redis_config[:path] ||
|
43
|
+
"redis://#{@redis_config[:host] || '127.0.0.1'}:#{@redis_config[:port] || '6379'}/#{@redis_config[:db] || '0'}"
|
44
|
+
shutdown_redis = EM::Hiredis.connect(redis_uri)
|
45
|
+
shutdown_redis.rpush(@config['queue'], Flapjack.dump_json('notification_type' => 'shutdown'))
|
46
|
+
end
|
66
47
|
|
67
|
-
|
68
|
-
|
69
|
-
:to => alert.address,
|
70
|
-
:message_id => "<#{alert.notification_id}@#{@fqdn}>",
|
71
|
-
:alert => alert)
|
48
|
+
def start
|
49
|
+
queue = @config['queue']
|
72
50
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
51
|
+
until @should_quit
|
52
|
+
begin
|
53
|
+
@logger.debug("email gateway is going into blpop mode on #{queue}")
|
54
|
+
deliver( Flapjack::Data::Alert.next(queue, :redis => @redis, :logger => @logger) )
|
55
|
+
rescue => e
|
56
|
+
@logger.error "Error generating or dispatching email message: #{e.class}: #{e.message}\n" +
|
57
|
+
e.backtrace.join("\n")
|
77
58
|
end
|
59
|
+
end
|
60
|
+
end
|
78
61
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
# http://tools.ietf.org/html/rfc821#page-36 SMTP response codes
|
93
|
-
if response && response.respond_to?(:code) &&
|
94
|
-
((response.code == 250) || (response.code == 251))
|
95
|
-
alert.record_send_success!
|
96
|
-
@sent += 1
|
97
|
-
else
|
98
|
-
@logger.error "Email sending failed"
|
62
|
+
def deliver(alert)
|
63
|
+
host = @smtp_config ? @smtp_config['host'] : nil
|
64
|
+
port = @smtp_config ? @smtp_config['port'] : nil
|
65
|
+
starttls = @smtp_config ? !! @smtp_config['starttls'] : nil
|
66
|
+
m_from = @smtp_config ? @smtp_config['from'] : "flapjack@#{@fqdn}"
|
67
|
+
m_reply_to = @smtp_config ? ( @smtp_config['reply_to'] ||= m_from ) : "flapjack@#{@fqdn}"
|
68
|
+
if @smtp_config
|
69
|
+
if auth_config = @smtp_config['auth']
|
70
|
+
auth = {}
|
71
|
+
auth[:type] = auth_config['type'].to_sym || :plain
|
72
|
+
auth[:username] = auth_config['username']
|
73
|
+
auth[:password] = auth_config['password']
|
99
74
|
end
|
75
|
+
end
|
100
76
|
|
101
|
-
|
77
|
+
@logger.debug("flapjack_mailer: set from to #{m_from}")
|
102
78
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
79
|
+
mail = prepare_email(:from => m_from,
|
80
|
+
:reply_to => m_reply_to,
|
81
|
+
:to => alert.address,
|
82
|
+
:message_id => "<#{alert.notification_id}@#{@fqdn}>",
|
83
|
+
:alert => alert)
|
84
|
+
|
85
|
+
smtp_from = m_from.clone
|
86
|
+
while smtp_from =~ /(<|>)/
|
87
|
+
smtp_from.sub!(/^.*</, '')
|
88
|
+
smtp_from.sub!(/>.*$/, '')
|
107
89
|
end
|
108
90
|
|
109
|
-
|
91
|
+
smtp_args = {:from => smtp_from,
|
92
|
+
:to => alert.address,
|
93
|
+
:content => "#{mail.to_s}\r\n.\r\n",
|
94
|
+
:domain => @fqdn,
|
95
|
+
:host => host || 'localhost',
|
96
|
+
:port => port || 25,
|
97
|
+
:starttls => starttls}
|
98
|
+
smtp_args.merge!(:auth => auth) if auth
|
99
|
+
|
100
|
+
email = EM::P::SmtpClient.send(smtp_args)
|
101
|
+
|
102
|
+
response = EM::Synchrony.sync(email)
|
103
|
+
|
104
|
+
# http://tools.ietf.org/html/rfc821#page-36 SMTP response codes
|
105
|
+
if response && response.respond_to?(:code) &&
|
106
|
+
((response.code == 250) || (response.code == 251))
|
107
|
+
alert.record_send_success!
|
108
|
+
@sent += 1
|
109
|
+
else
|
110
|
+
@logger.error "Email sending failed"
|
111
|
+
end
|
110
112
|
|
111
|
-
|
112
|
-
def prepare_email(opts = {})
|
113
|
-
from = opts[:from]
|
114
|
-
reply_to = opts[:reply_to]
|
115
|
-
to = opts[:to]
|
116
|
-
message_id = opts[:message_id]
|
117
|
-
alert = opts[:alert]
|
113
|
+
@logger.debug "Email response: #{response.inspect}"
|
118
114
|
|
119
|
-
|
115
|
+
rescue => e
|
116
|
+
@logger.error "Error generating or delivering email to #{alert.address}: #{e.class}: #{e.message}"
|
117
|
+
@logger.error e.backtrace.join("\n")
|
118
|
+
raise
|
119
|
+
end
|
120
120
|
|
121
|
-
|
122
|
-
subject_template_path = case
|
123
|
-
when @config.has_key?('templates') && @config['templates']["#{message_type}_subject.text"]
|
124
|
-
@config['templates']["#{message_type}_subject.text"]
|
125
|
-
else
|
126
|
-
mydir + "/email/#{message_type}_subject.text.erb"
|
127
|
-
end
|
128
|
-
text_template_path = case
|
129
|
-
when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
|
130
|
-
@config['templates']["#{message_type}.text"]
|
131
|
-
else
|
132
|
-
mydir + "/email/#{message_type}.text.erb"
|
133
|
-
end
|
134
|
-
html_template_path = case
|
135
|
-
when @config.has_key?('templates') && @config['templates']["#{message_type}.html"]
|
136
|
-
@config['templates']["#{message_type}.html"]
|
137
|
-
else
|
138
|
-
mydir + "/email/#{message_type}.html.erb"
|
139
|
-
end
|
140
|
-
subject_template = ERB.new(File.read(subject_template_path), nil, '-')
|
141
|
-
text_template = ERB.new(File.read(text_template_path), nil, '-')
|
142
|
-
html_template = ERB.new(File.read(html_template_path), nil, '-')
|
121
|
+
private
|
143
122
|
|
144
|
-
|
145
|
-
|
123
|
+
# returns a Mail object
|
124
|
+
def prepare_email(opts = {})
|
125
|
+
from = opts[:from]
|
126
|
+
reply_to = opts[:reply_to]
|
127
|
+
to = opts[:to]
|
128
|
+
message_id = opts[:message_id]
|
129
|
+
alert = opts[:alert]
|
146
130
|
|
147
|
-
|
148
|
-
begin
|
149
|
-
erb_to_be_executed = subject_template_path
|
150
|
-
subject = subject_template.result(bnd).chomp
|
131
|
+
message_type = alert.rollup ? 'rollup' : 'alert'
|
151
132
|
|
152
|
-
|
153
|
-
|
133
|
+
mydir = File.dirname(__FILE__)
|
134
|
+
subject_template_path = case
|
135
|
+
when @config.has_key?('templates') && @config['templates']["#{message_type}_subject.text"]
|
136
|
+
@config['templates']["#{message_type}_subject.text"]
|
137
|
+
else
|
138
|
+
mydir + "/email/#{message_type}_subject.text.erb"
|
139
|
+
end
|
140
|
+
text_template_path = case
|
141
|
+
when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
|
142
|
+
@config['templates']["#{message_type}.text"]
|
143
|
+
else
|
144
|
+
mydir + "/email/#{message_type}.text.erb"
|
145
|
+
end
|
146
|
+
html_template_path = case
|
147
|
+
when @config.has_key?('templates') && @config['templates']["#{message_type}.html"]
|
148
|
+
@config['templates']["#{message_type}.html"]
|
149
|
+
else
|
150
|
+
mydir + "/email/#{message_type}.html.erb"
|
151
|
+
end
|
152
|
+
subject_template = ERB.new(File.read(subject_template_path), nil, '-')
|
153
|
+
text_template = ERB.new(File.read(text_template_path), nil, '-')
|
154
|
+
html_template = ERB.new(File.read(html_template_path), nil, '-')
|
154
155
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
156
|
+
@alert = alert
|
157
|
+
bnd = binding
|
158
|
+
|
159
|
+
# do some intelligence gathering in case an ERB execution blows up
|
160
|
+
begin
|
161
|
+
erb_to_be_executed = subject_template_path
|
162
|
+
subject = subject_template.result(bnd).chomp
|
162
163
|
|
163
|
-
|
164
|
+
erb_to_be_executed = text_template_path
|
165
|
+
body_text = text_template.result(bnd)
|
164
166
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
167
|
+
erb_to_be_executed = html_template_path
|
168
|
+
body_html = html_template.result(bnd)
|
169
|
+
rescue => e
|
170
|
+
@logger.error "Error while excuting ERBs for an email: " +
|
171
|
+
"ERB being executed: #{erb_to_be_executed}"
|
172
|
+
raise
|
173
|
+
end
|
171
174
|
|
172
|
-
|
173
|
-
body body_text
|
174
|
-
end
|
175
|
+
@logger.debug("preparing email to: #{to}, subject: #{subject}, message-id: #{message_id}")
|
175
176
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
177
|
+
mail = Mail.new do
|
178
|
+
from from
|
179
|
+
to to
|
180
|
+
subject subject
|
181
|
+
reply_to reply_to
|
182
|
+
message_id message_id
|
183
|
+
|
184
|
+
text_part do
|
185
|
+
body body_text
|
180
186
|
end
|
181
187
|
|
188
|
+
html_part do
|
189
|
+
content_type 'text/html; charset=UTF-8'
|
190
|
+
body body_html
|
191
|
+
end
|
182
192
|
end
|
183
|
-
end
|
184
193
|
|
194
|
+
end
|
185
195
|
end
|
186
196
|
end
|
187
197
|
end
|