flapjack 0.6.61 → 0.7.0

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