flapjack 0.6.61 → 0.7.0

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 (38) hide show
  1. data/Gemfile +2 -1
  2. data/README.md +8 -4
  3. data/features/events.feature +269 -146
  4. data/features/notification_rules.feature +93 -0
  5. data/features/steps/events_steps.rb +162 -21
  6. data/features/steps/notifications_steps.rb +1 -1
  7. data/features/steps/time_travel_steps.rb +30 -19
  8. data/features/support/env.rb +71 -1
  9. data/flapjack.gemspec +3 -0
  10. data/lib/flapjack/data/contact.rb +256 -57
  11. data/lib/flapjack/data/entity.rb +2 -1
  12. data/lib/flapjack/data/entity_check.rb +22 -7
  13. data/lib/flapjack/data/global.rb +1 -0
  14. data/lib/flapjack/data/message.rb +2 -0
  15. data/lib/flapjack/data/notification_rule.rb +172 -0
  16. data/lib/flapjack/data/tag.rb +7 -2
  17. data/lib/flapjack/data/tag_set.rb +16 -0
  18. data/lib/flapjack/executive.rb +147 -13
  19. data/lib/flapjack/filters/delays.rb +21 -9
  20. data/lib/flapjack/gateways/api.rb +407 -27
  21. data/lib/flapjack/gateways/pagerduty.rb +1 -1
  22. data/lib/flapjack/gateways/web.rb +50 -22
  23. data/lib/flapjack/gateways/web/views/self_stats.haml +2 -0
  24. data/lib/flapjack/utility.rb +10 -0
  25. data/lib/flapjack/version.rb +1 -1
  26. data/spec/lib/flapjack/data/contact_spec.rb +103 -6
  27. data/spec/lib/flapjack/data/global_spec.rb +2 -0
  28. data/spec/lib/flapjack/data/message_spec.rb +6 -0
  29. data/spec/lib/flapjack/data/notification_rule_spec.rb +22 -0
  30. data/spec/lib/flapjack/data/notification_spec.rb +6 -0
  31. data/spec/lib/flapjack/gateways/api_spec.rb +727 -4
  32. data/spec/lib/flapjack/gateways/jabber_spec.rb +1 -0
  33. data/spec/lib/flapjack/gateways/web_spec.rb +11 -1
  34. data/spec/spec_helper.rb +10 -0
  35. data/tmp/notification_rules.rb +73 -0
  36. data/tmp/test_json_post.rb +16 -0
  37. data/tmp/test_notification_rules_api.rb +170 -0
  38. metadata +59 -2
@@ -104,6 +104,7 @@ describe Flapjack::Gateways::Jabber, :logger => true do
104
104
 
105
105
  attempts = 0
106
106
 
107
+ EventMachine::Synchrony.should_receive(:sleep).with(5).exactly(1).times
107
108
  EventMachine::Synchrony.should_receive(:sleep).with(2).exactly(3).times
108
109
  fj.should_receive(:connect).exactly(4).times.and_return {
109
110
  attempts +=1
@@ -16,6 +16,15 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
16
16
 
17
17
  let(:redis) { mock('redis') }
18
18
 
19
+ before(:all) do
20
+ Flapjack::Gateways::Web.class_eval {
21
+ set :raise_errors, true
22
+ }
23
+ Flapjack::Gateways::Web.instance_variable_get('@middleware').delete_if {|m|
24
+ m[0] == Rack::FiberPool
25
+ }
26
+ end
27
+
19
28
  before(:each) do
20
29
  Flapjack::RedisPool.should_receive(:new).and_return(redis)
21
30
  Flapjack::Gateways::Web.instance_variable_set('@config', {})
@@ -174,6 +183,7 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
174
183
 
175
184
  post "/scheduled_maintenances/#{entity_name_esc}/ping?"+
176
185
  "start_time=1+day+ago&duration=30+minutes&summary=wow"
186
+
177
187
  last_response.status.should == 302
178
188
  end
179
189
 
@@ -227,7 +237,7 @@ describe Flapjack::Gateways::Web, :sinatra => true, :logger => true do
227
237
  contact = mock('contact')
228
238
  contact.should_receive(:name).twice.and_return("Smithson Smith")
229
239
  contact.should_receive(:media).exactly(3).times.and_return({})
230
- contact.should_receive(:entities_and_checks).and_return([])
240
+ contact.should_receive(:entities).with(:checks => true).and_return([])
231
241
 
232
242
  Flapjack::Data::Contact.should_receive(:find_by_id).
233
243
  with('0362', :redis => redis).and_return(contact)
data/spec/spec_helper.rb CHANGED
@@ -9,6 +9,8 @@ end
9
9
  $testing = true
10
10
 
11
11
  FLAPJACK_ENV = ENV["FLAPJACK_ENV"] || 'test'
12
+ ENV['RACK_ENV'] = ENV["FLAPJACK_ENV"]
13
+
12
14
  require 'bundler'
13
15
  Bundler.require(:default, :test)
14
16
 
@@ -37,6 +39,11 @@ class MockLogger
37
39
  end
38
40
  end
39
41
 
42
+ JsonSpec.configure do
43
+ # so we include id
44
+ exclude_keys "created_at", "updated_at"
45
+ end
46
+
40
47
  # This file was generated by the `rspec --init` command. Conventionally, all
41
48
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
42
49
  # Require this file using `require "spec_helper"` to ensure that it is only
@@ -76,6 +83,8 @@ RSpec.configure do |config|
76
83
  config.around(:each, :logger => true) do |example|
77
84
  @logger = MockLogger.new
78
85
  example.run
86
+ #messages = @logger.messages.compact
87
+ #p "logger: " + messages.join(", ") unless messages.empty?
79
88
  @logger.messages.clear
80
89
  end
81
90
 
@@ -85,4 +94,5 @@ RSpec.configure do |config|
85
94
 
86
95
  config.include HamlViewHelper, :haml_view => true
87
96
  config.include Rack::Test::Methods, :sinatra => true
97
+ config.include JsonSpec::Helpers, :json => true
88
98
  end
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+
5
+ #tuple = [
6
+ # [ alice, sms ],
7
+ # [ alice, email ],
8
+ # [ boby, email ],
9
+ # [ carol, sms ],
10
+ #]
11
+
12
+ event
13
+
14
+ # delete media based on entity name(s), tags, severity, time of day
15
+ # first get all rules matching entity and time
16
+ tuple.map! do |contact, media|
17
+ rules = contact.notification_rules
18
+ # filter based on tags, severity, time of day
19
+ matchers = contact.notification_rules do |rule|
20
+ rule.match_entity?(event) && rule.match_time?(event)
21
+ end
22
+ matchers.empty? ? nil : [ contact, media, matchers ]
23
+ end
24
+
25
+ # matchers are rules of the contact that have matched the current event
26
+ # for time and entity
27
+
28
+ tuple.compact!
29
+
30
+ # tuple = [
31
+ # [ alice, sms, matchers ],
32
+ # [ boby, email, matchers ],
33
+ # ]
34
+
35
+ # delete the matcher for all entities if there are more specific matchers
36
+ tuple = tuple.map do |contact, media, matchers|
37
+ if matchers.lengh > 1
38
+ have_specific = matchers.detect do |matcher|
39
+ matcher.entities or matcher.entity_tags
40
+ end
41
+ if have_specific
42
+ # delete the rule for all entities
43
+ matchers.map! do |matcher|
44
+ matcher.entities.nil? and matcher.entity_tags.nil? ? nil : matcher
45
+ end
46
+ end
47
+ end
48
+ [contact, media, matchers]
49
+ end
50
+
51
+ # delete media based on blackholes
52
+ tuple = tuple.find_all do |contact, media, matchers|
53
+ matchers.none? {|matcher| matcher.blackhole? }
54
+ end
55
+
56
+ # tuple = [
57
+ # [ alice, sms, matchers ],
58
+ # ]
59
+
60
+ # delete media based on notification interval
61
+ tuple.find_all do |contact, media, matchers|
62
+ #interval = matchers.sort_by {|matcher| matcher.interval }.first # => 5
63
+ interval = contact.interval_for_media(media) # => 5
64
+ # use an expiring key to block a notification for a given (contact, media) for the interval
65
+ not_notified_within(interval) # => true
66
+ end
67
+
68
+ # tuple = [
69
+ # [ alice, sms, matchers ],
70
+ # ]
71
+
72
+ tuple.each {|contact, media, matchers| dispatch_message(media, contact) }
73
+
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'HTTParty'
4
+ require 'json'
5
+
6
+ @payload ={
7
+ "email" => "phil@gmail.com",
8
+ "token" => "mytokenstuff",
9
+ "content" => "here is some content",
10
+ "notification_type" => "1",
11
+ "name" => "here is a name",
12
+ "auto_action" => "true"
13
+ }
14
+
15
+ HTTParty.post( 'http://localhost:4091/notification_rules', :body => JSON.dump(@payload), :options => { :headers => { 'ContentType' => 'application/json' } })
16
+
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "httparty"
4
+ require "json"
5
+
6
+ class Foo
7
+
8
+ include HTTParty
9
+ base_uri "http://localhost:4091"
10
+
11
+ @summary = ""
12
+
13
+ #test_entity = "foo-app-1.example.com"
14
+ test_entity = "localhost"
15
+ test_check = "PING"
16
+ test_contact = "21"
17
+ test_email = '{
18
+ "address": "dmitri@example.com",
19
+ "interval": 900
20
+ }'
21
+ test_timezone = '{
22
+ "timezone": "Australia/Broken_Hill"
23
+ }'
24
+ get_urls = [
25
+ "/entities",
26
+ "/checks/#{test_entity}",
27
+ "/status/#{test_entity}",
28
+ "/status/#{test_entity}/#{test_check}",
29
+ "/outages/#{test_entity}",
30
+ "/outages/#{test_entity}/#{test_check}",
31
+ "/unscheduled_maintenances/#{test_entity}",
32
+ "/unscheduled_maintenances/#{test_entity}/#{test_check}",
33
+ "/scheduled_maintenances/#{test_entity}",
34
+ "/scheduled_maintenances/#{test_entity}/#{test_check}",
35
+ "/downtime/#{test_entity}",
36
+ "/downtime/#{test_entity}/#{test_check}",
37
+ "/contacts",
38
+ "/contacts/#{test_contact}",
39
+ "/contacts/#{test_contact}/notification_rules",
40
+ "/contacts/#{test_contact}/media",
41
+ "/contacts/#{test_contact}/media/email",
42
+ "/contacts/#{test_contact}/timezone",
43
+ ]
44
+
45
+ test_rule = '{
46
+ "contact_id": "21",
47
+ "entity_tags": [
48
+ "database",
49
+ "physical"
50
+ ],
51
+ "entities": [
52
+ "localhost"
53
+ ],
54
+ "time_restrictions": [
55
+ {
56
+ "TODO": "TODO"
57
+ }
58
+ ],
59
+ "warning_media": [
60
+ "email"
61
+ ],
62
+ "critical_media": [
63
+ "sms",
64
+ "email"
65
+ ],
66
+ "warning_blackhole": false,
67
+ "critical_blackhole": false
68
+ }'
69
+ post_urls = {
70
+ "/scheduled_maintenances/#{test_entity}/#{test_check}" => '{
71
+ "start_time": 1361791228,
72
+ "duration": 3600,
73
+ "@summary": "SHUT IT ALL DOWN!"
74
+ }',
75
+ "/acknowledgements/#{test_entity}/#{test_check}" => '{
76
+ "duration": 3600,
77
+ "@summary": "AL - working on it"
78
+ }',
79
+ "/test_notifications/#{test_entity}/#{test_check}" => '',
80
+ "/entities" => '{
81
+ "entities": [
82
+ {
83
+ "id": "825",
84
+ "name": "foo.example.com",
85
+ "contacts": [
86
+ "21",
87
+ "22"
88
+ ],
89
+ "tags": [
90
+ "foo"
91
+ ]
92
+ }
93
+ ]
94
+ }',
95
+ "/contacts" => '{
96
+ "contacts": [
97
+ {
98
+ "id": "21",
99
+ "first_name": "Ada",
100
+ "last_name": "Lovelace",
101
+ "email": "ada@example.com",
102
+ "media": {
103
+ "sms": "+61412345678",
104
+ "email": "ada@example.com"
105
+ },
106
+ "tags": [
107
+ "legend",
108
+ "first computer programmer"
109
+ ]
110
+ }
111
+ ]
112
+ }',
113
+ "/notification_rules" => test_rule,
114
+ }
115
+
116
+ def self.do_get(url)
117
+ response = get(url)
118
+ response_body = response.body ? response.body[0..300] : nil
119
+ puts "GET #{url}", "#{response.code} - #{response.message}", response.headers.inspect, response_body
120
+ puts "---------------------------------------------------"
121
+ @summary += "#{response.code} GET #{url}\n"
122
+ end
123
+
124
+ def self.do_post(url, body)
125
+ response = post(url, :body => body, :headers => {'Content-Type' => 'application/json'})
126
+ response_body = response.body ? response.body[0..300] : nil
127
+ puts "POST #{url}", body, "#{response.code} - #{response.message}", response.headers.inspect, response_body
128
+ puts "---------------------------------------------------"
129
+ @summary += "#{response.code} POST #{url}\n"
130
+ end
131
+
132
+ def self.do_put(url, body)
133
+ response = put(url, :body => body, :headers => {'Content-Type' => 'application/json'})
134
+ response_body = response.body ? response.body[0..300] : nil
135
+ puts "PUT #{url}", body, "#{response.code} - #{response.message}", response.headers.inspect, response_body
136
+ puts "---------------------------------------------------"
137
+ @summary += "#{response.code} PUT #{url}\n"
138
+ end
139
+
140
+ def self.do_delete(url)
141
+ response = delete(url)
142
+ response_body = response.body ? response.body[0..300] : nil
143
+ puts "DELETE #{url}", "#{response.code} - #{response.message}", response.headers.inspect, response_body
144
+ puts "---------------------------------------------------"
145
+ @summary += "#{response.code} DELETE #{url}\n"
146
+ end
147
+
148
+ get_urls.each do |url|
149
+ do_get(url)
150
+ end
151
+
152
+ post_urls.each_pair do |url, data|
153
+ do_post(url, data)
154
+ end
155
+
156
+ rule = JSON.parse(get('/contacts/21/notification_rules').body).last
157
+ rule_id = rule['id']
158
+ raise RuntimeError unless rule_id
159
+ puts "****** NOTIFICATION RULE ID TO PICK ON (PUT, DELETE) IS: #{rule_id} ******"
160
+
161
+ do_get("/notification_rules/#{rule_id}")
162
+ do_put("/notification_rules/#{rule_id}", test_rule)
163
+ do_delete("/contacts/21/media/email")
164
+ do_put("/contacts/21/media/email", test_email)
165
+ do_delete("/contacts/21/timezone")
166
+ do_put("/contacts/21/timezone", test_timezone)
167
+
168
+ puts "\nSummary:\n"
169
+ puts @summary
170
+ 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.61
4
+ version: 0.7.0
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: 2013-01-11 00:00:00.000000000 Z
14
+ date: 2013-04-18 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: dante
@@ -301,6 +301,54 @@ dependencies:
301
301
  - - ! '>='
302
302
  - !ruby/object:Gem::Version
303
303
  version: '0'
304
+ - !ruby/object:Gem::Dependency
305
+ name: activesupport
306
+ requirement: !ruby/object:Gem::Requirement
307
+ none: false
308
+ requirements:
309
+ - - ! '>='
310
+ - !ruby/object:Gem::Version
311
+ version: '0'
312
+ type: :runtime
313
+ prerelease: false
314
+ version_requirements: !ruby/object:Gem::Requirement
315
+ none: false
316
+ requirements:
317
+ - - ! '>='
318
+ - !ruby/object:Gem::Version
319
+ version: '0'
320
+ - !ruby/object:Gem::Dependency
321
+ name: ice_cube
322
+ requirement: !ruby/object:Gem::Requirement
323
+ none: false
324
+ requirements:
325
+ - - ! '>='
326
+ - !ruby/object:Gem::Version
327
+ version: '0'
328
+ type: :runtime
329
+ prerelease: false
330
+ version_requirements: !ruby/object:Gem::Requirement
331
+ none: false
332
+ requirements:
333
+ - - ! '>='
334
+ - !ruby/object:Gem::Version
335
+ version: '0'
336
+ - !ruby/object:Gem::Dependency
337
+ name: tzinfo
338
+ requirement: !ruby/object:Gem::Requirement
339
+ none: false
340
+ requirements:
341
+ - - ! '>='
342
+ - !ruby/object:Gem::Version
343
+ version: '0'
344
+ type: :runtime
345
+ prerelease: false
346
+ version_requirements: !ruby/object:Gem::Requirement
347
+ none: false
348
+ requirements:
349
+ - - ! '>='
350
+ - !ruby/object:Gem::Version
351
+ version: '0'
304
352
  - !ruby/object:Gem::Dependency
305
353
  name: rake
306
354
  requirement: !ruby/object:Gem::Requirement
@@ -359,6 +407,7 @@ files:
359
407
  - dist/puppet/sqlite3/manifests/dev.pp
360
408
  - etc/flapjack_config.yaml.example
361
409
  - features/events.feature
410
+ - features/notification_rules.feature
362
411
  - features/notifications.feature
363
412
  - features/packaging-lintian.feature
364
413
  - features/steps/events_steps.rb
@@ -381,7 +430,9 @@ files:
381
430
  - lib/flapjack/data/global.rb
382
431
  - lib/flapjack/data/message.rb
383
432
  - lib/flapjack/data/notification.rb
433
+ - lib/flapjack/data/notification_rule.rb
384
434
  - lib/flapjack/data/tag.rb
435
+ - lib/flapjack/data/tag_set.rb
385
436
  - lib/flapjack/executive.rb
386
437
  - lib/flapjack/filters/acknowledgement.rb
387
438
  - lib/flapjack/filters/base.rb
@@ -422,6 +473,7 @@ files:
422
473
  - spec/lib/flapjack/data/event_spec.rb
423
474
  - spec/lib/flapjack/data/global_spec.rb
424
475
  - spec/lib/flapjack/data/message_spec.rb
476
+ - spec/lib/flapjack/data/notification_rule_spec.rb
425
477
  - spec/lib/flapjack/data/notification_spec.rb
426
478
  - spec/lib/flapjack/data/tag_spec.rb
427
479
  - spec/lib/flapjack/executive_spec.rb
@@ -464,9 +516,12 @@ files:
464
516
  - tmp/create_events_ok_failure_ack.rb
465
517
  - tmp/dummy_entities.json
466
518
  - tmp/generate_nagios_test_hosts.rb
519
+ - tmp/notification_rules.rb
467
520
  - tmp/parse_config_yaml.rb
468
521
  - tmp/redis_delete_all_keys.rb
469
522
  - tmp/test_entities.json
523
+ - tmp/test_json_post.rb
524
+ - tmp/test_notification_rules_api.rb
470
525
  homepage: http://flapjack-project.com/
471
526
  licenses: []
472
527
  post_install_message:
@@ -493,6 +548,7 @@ specification_version: 3
493
548
  summary: Intelligent, scalable, distributed monitoring notification system.
494
549
  test_files:
495
550
  - features/events.feature
551
+ - features/notification_rules.feature
496
552
  - features/notifications.feature
497
553
  - features/packaging-lintian.feature
498
554
  - features/steps/events_steps.rb
@@ -509,6 +565,7 @@ test_files:
509
565
  - spec/lib/flapjack/data/event_spec.rb
510
566
  - spec/lib/flapjack/data/global_spec.rb
511
567
  - spec/lib/flapjack/data/message_spec.rb
568
+ - spec/lib/flapjack/data/notification_rule_spec.rb
512
569
  - spec/lib/flapjack/data/notification_spec.rb
513
570
  - spec/lib/flapjack/data/tag_spec.rb
514
571
  - spec/lib/flapjack/executive_spec.rb