flapjack 1.2.1 → 1.2.2
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.
- 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
|