flapjack 0.7.28 → 0.7.29

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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +10 -0
  3. data/features/notification_rules.feature +25 -25
  4. data/features/rollup.feature +38 -18
  5. data/features/steps/events_steps.rb +10 -5
  6. data/features/steps/notifications_steps.rb +8 -4
  7. data/lib/flapjack/data/alert.rb +207 -0
  8. data/lib/flapjack/data/contact.rb +14 -7
  9. data/lib/flapjack/data/entity_check.rb +4 -3
  10. data/lib/flapjack/data/notification.rb +28 -27
  11. data/lib/flapjack/gateways/api/contact_methods.rb +32 -12
  12. data/lib/flapjack/gateways/email.rb +49 -53
  13. data/lib/flapjack/gateways/email/alert.html.erb +15 -15
  14. data/lib/flapjack/gateways/email/alert.text.erb +15 -15
  15. data/lib/flapjack/gateways/email/alert_subject.text.erb +3 -13
  16. data/lib/flapjack/gateways/email/rollup.html.erb +6 -6
  17. data/lib/flapjack/gateways/email/rollup.text.erb +7 -7
  18. data/lib/flapjack/gateways/email/rollup_subject.text.erb +1 -19
  19. data/lib/flapjack/gateways/jabber.rb +57 -47
  20. data/lib/flapjack/gateways/jabber/alert.text.erb +12 -0
  21. data/lib/flapjack/gateways/jabber/rollup.text.erb +2 -0
  22. data/lib/flapjack/gateways/pagerduty.rb +60 -30
  23. data/lib/flapjack/gateways/pagerduty/alert.text.erb +10 -0
  24. data/lib/flapjack/gateways/sms_messagenet.rb +29 -36
  25. data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +4 -14
  26. data/lib/flapjack/gateways/sms_messagenet/rollup.text.erb +2 -34
  27. data/lib/flapjack/gateways/web.rb +23 -14
  28. data/lib/flapjack/gateways/web/views/check.html.erb +16 -11
  29. data/lib/flapjack/gateways/web/views/contact.html.erb +58 -16
  30. data/lib/flapjack/gateways/web/views/self_stats.html.erb +80 -71
  31. data/lib/flapjack/notifier.rb +8 -2
  32. data/lib/flapjack/pikelet.rb +17 -3
  33. data/lib/flapjack/processor.rb +0 -1
  34. data/lib/flapjack/redis_pool.rb +1 -1
  35. data/lib/flapjack/utility.rb +13 -0
  36. data/lib/flapjack/version.rb +1 -1
  37. data/spec/lib/flapjack/data/contact_spec.rb +44 -29
  38. data/spec/lib/flapjack/gateways/api/contact_methods_spec.rb +24 -4
  39. data/spec/lib/flapjack/gateways/email_spec.rb +0 -5
  40. data/spec/lib/flapjack/gateways/jabber_spec.rb +5 -1
  41. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +5 -2
  42. data/spec/lib/flapjack/gateways/{sms_messagenet.spec.rb → sms_messagenet_spec.rb} +16 -12
  43. data/spec/lib/flapjack/gateways/web_spec.rb +1 -1
  44. data/spec/spec_helper.rb +28 -6
  45. metadata +43 -89
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a8a6bbb199b138fb0da3af9765f5f0fe7b2ad552
4
+ data.tar.gz: 3dbd00e9e7e63978726cb0f1e78fc96639f1762b
5
+ SHA512:
6
+ metadata.gz: 981b9061652d0a75e5e32cb82590c20eeca4a7b2d624aad076097c8a39c799a0850110e67fe080afa6ffac5dbe16d39184d06014db3d3cdbf1c469353425019f
7
+ data.tar.gz: cad93481bc1dfd36c636ea84a0e7d59a9e5b1c926e046cf15b35a58cf4d4d06545bdd600b0cfe4d3e343ab6298944b40efc6ea89747355da04c456db56f46058
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## Flapjack Changelog
2
2
 
3
+ # 0.7.29 - 2013-11-01
4
+ - Feature: Per contact media rollup complete gh-291 (@jessereynolds)
5
+ - Feature: Rollup - show alerting checks and rollup status for each media on contact page gh-326 (@jessereynolds)
6
+ - Feature: Make message templating more flexible and consistent gh-329 (@jessereynolds)
7
+ - Feature: Remove misleading internal metrics gh-344 (@jessereynolds)
8
+ - Bug: clear up pagerduty details API code gh-338 (@ali-graham)
9
+ - Bug: non-numeric contact ID not properly supported - thanks @avishai-ish-shalom gh-338 (@jessereynolds)
10
+ - Bug: GET /contacts gives you more than you bargained for gh-339 (@jessereynolds)
11
+ - Bug: SMS alerts being sent from separate environment gh-135 (@jessereynolds)
12
+
3
13
  # 0.7.28 - 2013-10-21
4
14
  - Feature: Per contact media rollup (summary) notifications - foundation (data, api, web UI etc) gh-291 (@jessereynolds)
5
15
  - Feature: flapper takes an IP to bind to gh-98 (@ali-graham)
@@ -4,51 +4,51 @@ Feature: Notification rules on a per contact basis
4
4
  Background:
5
5
  Given the following users exist:
6
6
  | id | first_name | last_name | email | sms | timezone |
7
- | 1 | Malak | Al-Musawi | malak@example.com | +61400000001 | Asia/Baghdad |
8
- | 2 | Imani | Farooq | imani@example.com | +61400000002 | Europe/Moscow |
9
- | 3 | Vera | Дурейко | vera@example.com | +61400000003 | Europe/Paris |
10
- | 4 | Lucia | Moretti | lucia@example.com | +61400000004 | Europe/Rome |
11
- | 5 | Wang Fang | Wong | fang@example.com | +61400000005 | Asia/Shanghai |
7
+ | c1 | Malak | Al-Musawi | malak@example.com | +61400000001 | Asia/Baghdad |
8
+ | c2 | Imani | Farooq | imani@example.com | +61400000002 | Europe/Moscow |
9
+ | c3 | Vera | Дурейко | vera@example.com | +61400000003 | Europe/Paris |
10
+ | c4 | Lucia | Moretti | lucia@example.com | +61400000004 | Europe/Rome |
11
+ | c5 | Wang Fang | Wong | fang@example.com | +61400000005 | Asia/Shanghai |
12
12
 
13
13
  And the following entities exist:
14
14
  | id | name | contacts |
15
- | 1 | foo | 1 |
16
- | 2 | bar | 1,2,3 |
17
- | 3 | baz | 1,3 |
18
- | 4 | buf | 1,2,3 |
19
- | 5 | foo-app-01.xyz | 4 |
15
+ | 1 | foo | c1 |
16
+ | 2 | bar | c1,c2,c3 |
17
+ | 3 | baz | c1,c3 |
18
+ | 4 | buf | c1,c2,c3 |
19
+ | 5 | foo-app-01.xyz | c4 |
20
20
 
21
- And user 1 has the following notification intervals:
21
+ And user c1 has the following notification intervals:
22
22
  | email | sms |
23
23
  | 15 | 60 |
24
24
 
25
- And user 2 has the following notification intervals:
25
+ And user c2 has the following notification intervals:
26
26
  | email | sms |
27
27
  | 15 | 60 |
28
28
 
29
- And user 3 has the following notification intervals:
29
+ And user c3 has the following notification intervals:
30
30
  | email | sms |
31
31
  | 15 | 60 |
32
32
 
33
- And user 4 has the following notification intervals:
33
+ And user c4 has the following notification intervals:
34
34
  | email | sms |
35
35
  | 15 | 60 |
36
36
 
37
- And user 1 has the following notification rules:
37
+ And user c1 has the following notification rules:
38
38
  | entities | unknown_media | warning_media | critical_media | warning_blackhole | critical_blackhole | time_restrictions |
39
39
  | | | email | sms,email | true | true | |
40
40
  | foo | | email | sms,email | | | 8-18 weekdays |
41
41
  | bar | email | | sms,email | true | | |
42
42
  | baz | | email | sms,email | | | |
43
43
 
44
- And user 2 has the following notification rules:
44
+ And user c2 has the following notification rules:
45
45
  | entities | tags | warning_media | critical_media | warning_blackhole | critical_blackhole |
46
46
  | | | email | email | | |
47
47
  | | | sms | sms | | |
48
48
  | bar | | email | email,sms | | |
49
49
  | bar | wags | | | true | true |
50
50
 
51
- And user 3 has the following notification rules:
51
+ And user c3 has the following notification rules:
52
52
  | entities | warning_media | critical_media | warning_blackhole | critical_blackhole |
53
53
  | | email | email | | |
54
54
  | baz | sms | sms | | |
@@ -56,13 +56,13 @@ Feature: Notification rules on a per contact basis
56
56
  | buf | sms | sms | | |
57
57
  | bar | email | email | true | true |
58
58
 
59
- And user 4 has the following notification rules:
59
+ And user c4 has the following notification rules:
60
60
  | tags | warning_media | critical_media | time_restrictions |
61
61
  | | | | |
62
62
  | xyz, disk, util | sms | sms | |
63
63
  | xyz, ping | sms,email | sms,email | 8-18 weekdays |
64
64
 
65
- And user 5 has the following notification rules:
65
+ And user c5 has the following notification rules:
66
66
  | unknown_media | critical_media |
67
67
  | email | email, sms |
68
68
 
@@ -81,15 +81,15 @@ Feature: Notification rules on a per contact basis
81
81
  And a critical event is received
82
82
  Then 1 email alert should be queued for malak@example.com
83
83
  When the time is February 1 2013 12:00
84
- Then all alert dropping keys for user 1 should have expired
84
+ Then all alert dropping keys for user c1 should have expired
85
85
  When a critical event is received
86
86
  Then 2 email alerts should be queued for malak@example.com
87
87
  When the time is February 1 2013 17:59
88
- Then all alert dropping keys for user 1 should have expired
88
+ Then all alert dropping keys for user c1 should have expired
89
89
  When a critical event is received
90
90
  Then 3 email alerts should be queued for malak@example.com
91
91
  When the time is February 1 2013 18:01
92
- Then all alert dropping keys for user 1 should have expired
92
+ Then all alert dropping keys for user c1 should have expired
93
93
  When a critical event is received
94
94
  Then 3 email alerts should be queued for malak@example.com
95
95
 
@@ -395,15 +395,15 @@ Feature: Notification rules on a per contact basis
395
395
  And a critical event is received
396
396
  Then 1 sms alert should be queued for +61400000004
397
397
  When the time is February 1 2013 12:00
398
- Then all alert dropping keys for user 1 should have expired
398
+ Then all alert dropping keys for user c1 should have expired
399
399
  When a critical event is received
400
400
  Then 2 sms alerts should be queued for +61400000004
401
401
  When the time is February 1 2013 17:59
402
- Then all alert dropping keys for user 1 should have expired
402
+ Then all alert dropping keys for user c1 should have expired
403
403
  When a critical event is received
404
404
  Then 3 sms alerts should be queued for +61400000004
405
405
  When the time is February 1 2013 18:01
406
- Then all alert dropping keys for user 1 should have expired
406
+ Then all alert dropping keys for user c1 should have expired
407
407
  When a critical event is received
408
408
  Then 3 sms alerts should be queued for +61400000004
409
409
 
@@ -177,22 +177,42 @@ Feature: Rollup on a per contact, per media basis
177
177
  Then 1 sms alert of type problem and rollup problem should be queued for +61400000001
178
178
  And 2 sms alerts should be queued for +61400000001
179
179
 
180
- # @time
181
- # Scenario: Contact ceases to be a contact on an entity that they were being alerted for
182
- # Given check 'ping' for entity 'foo' is in an ok state
183
- # And check 'ping' for entity 'baz' is in an ok state
184
- # When a critical event is received for check 'ping' on entity 'foo'
185
- # And 1 minute passes
186
- # And a critical event is received for check 'ping' on entity 'foo'
187
- # Then 1 sms alerts of type problem and rollup none should be queued for +61400000001
188
- # When 5 minutes passes
189
- # And a critical event is received for check 'ping' on entity 'baz'
190
- # And 1 minute passes
191
- # And a critical event is received for check 'ping' on entity 'baz'
192
- # Then 1 sms alert of type problem and rollup problem should be queued for +61400000001
193
- # And 2 sms alerts should be queued for +61400000001
194
- # When 1 minute passes
195
- # And user 1 ceases to be a contact of entity 'foo'
196
- # And a critical event is received for check 'ping' on entity 'baz'
197
- # Then 1 sms alert of rollup recovery should be queued for +61400000001
180
+ @time
181
+ Scenario: Contact ceases to be a contact on an entity that they were being alerted for
182
+ Given check 'ping' for entity 'foo' is in an ok state
183
+ And check 'ping' for entity 'baz' is in an ok state
184
+ When a critical event is received for check 'ping' on entity 'foo'
185
+ And 1 minute passes
186
+ And a critical event is received for check 'ping' on entity 'foo'
187
+ Then 1 sms alerts of type problem and rollup none should be queued for +61400000001
188
+ When 5 minutes passes
189
+ And a critical event is received for check 'ping' on entity 'baz'
190
+ And 1 minute passes
191
+ And a critical event is received for check 'ping' on entity 'baz'
192
+ Then 1 sms alert of type problem and rollup problem should be queued for +61400000001
193
+ And 1 sms alerts of type problem and rollup none should be queued for +61400000001
194
+ And 2 sms alerts should be queued for +61400000001
195
+ When 20 minute passes
196
+ And user 1 ceases to be a contact of entity 'foo'
197
+ And a critical event is received for check 'ping' on entity 'baz'
198
+ Then 1 sms alert of rollup recovery should be queued for +61400000001
199
+
200
+ @time
201
+ Scenario: Test notification to not contribute to rollup
202
+ Given check 'ping' for entity 'foo' is in an ok state
203
+ And check 'ping' for entity 'baz' is in an ok state
204
+ When a critical event is received for check 'ping' on entity 'foo'
205
+ And 1 minute passes
206
+ And a critical event is received for check 'ping' on entity 'foo'
207
+ Then 1 sms alert of type problem and rollup none should be queued for +61400000001
208
+ And 1 sms alert should be queued for +61400000001
209
+ When 1 minute passes
210
+ And a test event is received for check 'sausage' on entity 'foo'
211
+ Then 1 sms alert of type problem and rollup none should be queued for +61400000001
212
+ And 1 sms alert of type test and rollup none should be queued for +61400000001
213
+ And 2 sms alerts should be queued for +61400000001
214
+ When 20 minutes passes
215
+ And a critical event is received for check 'ping' on entity 'foo'
216
+ Then 2 sms alerts of type problem and rollup none should be queued for +61400000001
217
+ And 3 sms alerts should be queued for +61400000001
198
218
 
@@ -301,7 +301,7 @@ Then /^show me the (\w+ )*log$/ do |adjective|
301
301
  puts @logger.messages.join("\n")
302
302
  end
303
303
 
304
- Then /^dump notification rules for user (\d+)$/ do |contact|
304
+ Then /^dump notification rules for user (\S+)$/ do |contact|
305
305
  rule_ids = @redis.smembers("contact_notification_rules:#{contact}")
306
306
  puts "There #{(rule_ids.length == 1) ? 'is' : 'are'} #{rule_ids.length} notification rule#{(rule_ids.length == 1) ? '' : 's'} for user #{contact}:"
307
307
  rule_ids.each {|rule_id|
@@ -338,7 +338,7 @@ Given /^the following users exist:$/ do |contacts|
338
338
  end
339
339
  end
340
340
 
341
- Given /^user (\d+) has the following notification intervals:$/ do |contact_id, intervals|
341
+ Given /^user (\S+) has the following notification intervals:$/ do |contact_id, intervals|
342
342
  contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
343
343
  intervals.hashes.each do |interval|
344
344
  contact.set_interval_for_media('email', interval['email'].to_i * 60)
@@ -346,7 +346,7 @@ Given /^user (\d+) has the following notification intervals:$/ do |contact_id, i
346
346
  end
347
347
  end
348
348
 
349
- Given /^user (\d+) has the following notification rollup thresholds:$/ do |contact_id, rollup_thresholds|
349
+ Given /^user (\S+) has the following notification rollup thresholds:$/ do |contact_id, rollup_thresholds|
350
350
  contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
351
351
  rollup_thresholds.hashes.each do |rollup_threshold|
352
352
  contact.set_rollup_threshold_for_media('email', rollup_threshold['email'].to_i)
@@ -354,7 +354,7 @@ Given /^user (\d+) has the following notification rollup thresholds:$/ do |conta
354
354
  end
355
355
  end
356
356
 
357
- Given /^user (\d+) has the following notification rules:$/ do |contact_id, rules|
357
+ Given /^user (\S+) has the following notification rules:$/ do |contact_id, rules|
358
358
  contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
359
359
  timezone = contact.timezone
360
360
 
@@ -400,7 +400,7 @@ Given /^user (\d+) has the following notification rules:$/ do |contact_id, rules
400
400
  end
401
401
  end
402
402
 
403
- Then /^all alert dropping keys for user (\d+) should have expired$/ do |contact_id|
403
+ Then /^all alert dropping keys for user (\S+) should have expired$/ do |contact_id|
404
404
  @redis.keys("drop_alerts_for_contact:#{contact_id}*").should be_empty
405
405
  end
406
406
 
@@ -426,3 +426,8 @@ Then /^(\w+) (\w+) alert(?:s)?(?: of)?(?: type (\w+))?(?: and)?(?: rollup (\w+))
426
426
  }.length.should == num_queued.to_i
427
427
  end
428
428
 
429
+ When(/^user (\S+) ceases to be a contact of entity '(.*)'$/) do |contact_id, entity|
430
+ entity = Flapjack::Data::Entity.find_by_name(entity, :redis => @redis)
431
+ @redis.srem("contacts_for:#{entity.id}", contact_id)
432
+ end
433
+
@@ -109,12 +109,14 @@ Given /^a user SMS notification has been queued for entity '([\w\.\-]+)'$/ do |e
109
109
  @sms_notification = {'notification_type' => 'problem',
110
110
  'contact_first_name' => 'John',
111
111
  'contact_last_name' => 'Smith',
112
- 'state' => 'CRITICAL',
112
+ 'state' => 'critical',
113
113
  'summary' => 'Socket timeout after 10 seconds',
114
114
  'time' => Time.now.to_i,
115
115
  'event_id' => "#{entity}:ping",
116
116
  'address' => '+61412345678',
117
- 'id' => 1}
117
+ 'id' => 1,
118
+ 'state_duration' => 30,
119
+ 'duration' => 45}
118
120
  end
119
121
 
120
122
  Given /^a user email notification has been queued for entity '([\w\.\-]+)'$/ do |entity|
@@ -124,12 +126,14 @@ Given /^a user email notification has been queued for entity '([\w\.\-]+)'$/ do
124
126
  @email_notification = {'notification_type' => 'problem',
125
127
  'contact_first_name' => 'John',
126
128
  'contact_last_name' => 'Smith',
127
- 'state' => 'CRITICAL',
129
+ 'state' => 'critical',
128
130
  'summary' => 'Socket timeout after 10 seconds',
129
131
  'time' => Time.now.to_i,
130
132
  'event_id' => "#{entity}:ping",
131
133
  'address' => 'johns@example.dom',
132
- 'id' => 2}
134
+ 'id' => 2,
135
+ 'state_duration' => 30,
136
+ 'duration' => 3600}
133
137
  end
134
138
 
135
139
  # NB using perform, the notifiers were accessing the wrong Redis DB number
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'active_support/inflector'
4
+ require 'flapjack/utility'
5
+
6
+ # Alert is the object ready to send to someone, complete with an address and all
7
+ # the data with which to render the text of the alert in the appropriate gateway
8
+ #
9
+ # It should possibly be renamed AlertPresenter
10
+
11
+ module Flapjack
12
+ module Data
13
+ class Alert
14
+
15
+ # from Flapjack::Data::Notification
16
+ attr_reader :event_id,
17
+ :state,
18
+ :summary,
19
+ :acknowledgement_duration,
20
+ :last_state,
21
+ :last_summary,
22
+ :state_duration,
23
+ :details,
24
+ :time,
25
+ :notification_type,
26
+ :event_count,
27
+ :tags
28
+
29
+ # from Flapjack::Data::Message
30
+ # :id,
31
+ attr_reader :media,
32
+ :address,
33
+ :rollup,
34
+ :contact_id,
35
+ :contact_first_name,
36
+ :contact_last_name
37
+
38
+ # from Flapjack::Notifier
39
+ attr_reader :rollup_threshold,
40
+ :rollup_alerts,
41
+ :in_scheduled_maintenance,
42
+ :in_unscheduled_maintenance
43
+
44
+ # from self
45
+ attr_reader :entity,
46
+ :check,
47
+ :notification_id
48
+
49
+ include Flapjack::Utility
50
+
51
+ def initialize(contents, opts)
52
+ raise "no logger supplied" unless @logger = opts[:logger]
53
+
54
+ @event_id = contents['event_id']
55
+ @state = contents['state']
56
+ @summary = contents['summary']
57
+ @acknowledgement_duration = contents['duration'] # SMELLY
58
+ @last_state = contents['last_state']
59
+ @last_summary = contents['last_summary']
60
+ @state_duration = contents['state_duration']
61
+ @details = contents['details']
62
+ @time = contents['time']
63
+ @notification_type = contents['notification_type']
64
+ @event_count = contents['event_count']
65
+ @tags = contents['tags']
66
+
67
+ @media = contents['media']
68
+ @address = contents['address']
69
+ @rollup = contents['rollup']
70
+ @contact_id = contents['contact_id']
71
+ @contact_first_name = contents['contact_first_name']
72
+ @contact_last_name = contents['contact_last_name']
73
+
74
+ @rollup_threshold = contents['rollup_threshold']
75
+ @rollup_alerts = contents['rollup_alerts']
76
+ @in_scheduled_maintenance = contents['in_scheduled_maintenance']
77
+ @in_unscheduled_maintenance = contents['in_unscheduled_maintenance']
78
+
79
+ @entity, @check = @event_id.split(':', 2)
80
+ @notification_id = contents['id'] || SecureRandom.uuid
81
+
82
+ allowed_states = ['ok', 'critical', 'warning', 'unknown', 'test_notifications', 'acknowledgement']
83
+ allowed_rollup_states = ['critical', 'warning', 'unknown']
84
+ raise "state #{@state.inspect} is invalid" unless
85
+ allowed_states.include?(@state)
86
+
87
+ raise "state_duration #{@state_duration.inspect} is invalid" unless
88
+ @state_duration && @state_duration.is_a?(Integer) && @state_duration >= 0
89
+
90
+ if @rollup_alerts
91
+ raise "rollup_alerts should be nil or a hash" unless @rollup_alerts.is_a?(Hash)
92
+ @rollup_alerts.each_pair do |check, details|
93
+ raise "duration of rollup_alerts['#{check}'] must be an integer" unless
94
+ details['duration'] && details['duration'].is_a?(Integer)
95
+ raise "state of rollup_alerts['#{check}'] is invalid" unless
96
+ details['state'] && allowed_rollup_states.include?(details['state'])
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+ def type
103
+ case @rollup
104
+ when "problem"
105
+ "rollup_problem"
106
+ when "recovery"
107
+ "rollup_recovery"
108
+ else
109
+ @notification_type
110
+ end
111
+ end
112
+
113
+ def type_sentence_case
114
+ case type
115
+ when "rollup_problem"
116
+ "Problem summary"
117
+ when "rollup_recovery"
118
+ "Problem summaries finishing"
119
+ else
120
+ type.titleize
121
+ end
122
+ end
123
+
124
+ def state_title_case
125
+ ['ok'].include?(@state) ? @state.upcase : @state.titleize
126
+ end
127
+
128
+ def last_state_title_case
129
+ ['ok'].include?(@last_state) ? @last_state.upcase : @last_state.titleize
130
+ end
131
+
132
+ def rollup_alerts_by_state
133
+ ['critical', 'warning', 'unknown'].inject({}) do |memo, state|
134
+ alerts = rollup_alerts.find_all {|alert| alert[1]['state'] == state}
135
+ memo[state] = alerts
136
+ memo
137
+ end
138
+ end
139
+
140
+ def rollup_state_counts
141
+ rollup_alerts.inject({}) do |memo, alert|
142
+ memo[alert[1]['state']] = (memo[alert[1]['state']] || 0) + 1
143
+ memo
144
+ end
145
+ end
146
+
147
+ def rollup_states_summary
148
+ state_counts = rollup_state_counts
149
+ ['critical', 'warning', 'unknown'].inject([]) do |memo, state|
150
+ next memo unless rollup_state_counts[state]
151
+ memo << "#{state.titleize}: #{state_counts[state]}"
152
+ memo
153
+ end.join(', ')
154
+ end
155
+
156
+ # produces a textual list of checks that are failing broken down by state, eg:
157
+ # Critical: 'PING' on 'foo-app-01.example.com', 'SSH' on 'foo-app-01.example.com';
158
+ # Warning: 'Disk / Utilisation' on 'foo-app-02.example.com'
159
+ def rollup_states_detail_text(opts)
160
+ max_checks = opts[:max_checks_per_state]
161
+ rollup_alerts_by_state.inject([]) do |memo, state|
162
+ state_titleized = state[0].titleize
163
+ alerts = max_checks && max_checks > 0 ? state[1][0..(max_checks - 1)] : state[1]
164
+ next memo if alerts.empty?
165
+ checks = alerts.map {|alert| alert[0]}
166
+ checks << '...' if checks.length < rollup_state_counts[state[0]]
167
+ memo << "#{state[0].titleize}: #{checks.join(', ')}"
168
+ memo
169
+ end.join('; ')
170
+ end
171
+
172
+ def to_s
173
+ msg = "Alert via #{media}:#{address} to contact #{contact_id} (#{contact_first_name} #{contact_last_name}): "
174
+ msg += type_sentence_case
175
+ if rollup
176
+ msg += " - #{rollup_states_summary} (#{rollup_states_detail_text(:max_checks_per_state => 3)})"
177
+ else
178
+ msg += " - '#{check}' on #{entity}"
179
+ unless ['acknowledgement', 'test'].include?(type)
180
+ msg += " is #{state_title_case}"
181
+ end
182
+ if ['acknowledgement'].include?(type)
183
+ msg += " has been acknowledged, unscheduled maintenance created for "
184
+ msg += time_period_in_words(acknowledgement_duration)
185
+ end
186
+ if summary && summary.length > 0
187
+ msg += " - #{summary}"
188
+ end
189
+ end
190
+ end
191
+
192
+ def record_send_success!
193
+ @logger.info "Sent alert successfully: #{to_s}"
194
+ end
195
+
196
+ # TODO: perhaps move message send failure porting to this method
197
+ # to avoid duplication in the gateways, and to more easily allow
198
+ # better error reporting on message generation / send failure
199
+ #def record_send_failure!(opts)
200
+ # exception = opts[:exception]
201
+ # message = opts[:message]
202
+ # @logger.error "Error sending an alert! #{alert}"
203
+ #end
204
+
205
+ end
206
+ end
207
+ end