flapjack 0.5.5 → 0.6.23

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 (167) hide show
  1. data/.gitignore +10 -0
  2. data/.rbenv-version +1 -0
  3. data/.rspec +10 -0
  4. data/Gemfile +18 -0
  5. data/Guardfile +14 -0
  6. data/README.md +152 -173
  7. data/Rakefile +53 -150
  8. data/bin/flapjack +72 -0
  9. data/bin/flapjack-nagios-receiver +111 -0
  10. data/bin/flapjack-nagios-receiver-control +15 -0
  11. data/bin/flapjack-netsaint-parser +0 -2
  12. data/bin/flapjack-populator +133 -16
  13. data/bin/install-flapjack-systemwide +2 -2
  14. data/config.ru +11 -0
  15. data/dist/etc/init.d/flapjack +46 -0
  16. data/dist/etc/init.d/flapjack-nagios-receiver +36 -0
  17. data/doc/GLOSSARY.md +19 -0
  18. data/etc/flapjack_config.yaml.example +90 -0
  19. data/features/events.feature +132 -0
  20. data/features/notifications.feature +57 -0
  21. data/features/packaging-lintian.feature +5 -3
  22. data/features/steps/events_steps.rb +164 -0
  23. data/features/steps/flapjack-importer_steps.rb +2 -5
  24. data/features/steps/flapjack-worker_steps.rb +13 -6
  25. data/features/steps/notifications_steps.rb +178 -0
  26. data/features/steps/packaging-lintian_steps.rb +14 -0
  27. data/features/steps/time_travel_steps.rb +34 -0
  28. data/features/support/env.rb +63 -36
  29. data/flapjack.gemspec +35 -186
  30. data/lib/flapjack.rb +2 -0
  31. data/lib/flapjack/api.rb +274 -0
  32. data/lib/flapjack/api/entity_check_presenter.rb +184 -0
  33. data/lib/flapjack/api/entity_presenter.rb +66 -0
  34. data/lib/flapjack/cli/worker_manager.rb +1 -2
  35. data/lib/flapjack/configuration.rb +11 -0
  36. data/lib/flapjack/coordinator.rb +288 -0
  37. data/lib/flapjack/daemonizing.rb +186 -0
  38. data/lib/flapjack/data/contact.rb +45 -0
  39. data/lib/flapjack/data/entity.rb +89 -0
  40. data/lib/flapjack/data/entity_check.rb +396 -0
  41. data/lib/flapjack/data/event.rb +144 -0
  42. data/lib/flapjack/data/notification.rb +13 -0
  43. data/lib/flapjack/executive.rb +289 -0
  44. data/lib/flapjack/filters/acknowledgement.rb +39 -0
  45. data/lib/flapjack/filters/{any_parents_failed.rb → base.rb} +6 -4
  46. data/lib/flapjack/filters/delays.rb +53 -0
  47. data/lib/flapjack/filters/detect_mass_client_failures.rb +44 -0
  48. data/lib/flapjack/filters/ok.rb +25 -5
  49. data/lib/flapjack/filters/scheduled_maintenance.rb +17 -0
  50. data/lib/flapjack/filters/unscheduled_maintenance.rb +17 -0
  51. data/lib/flapjack/jabber.rb +294 -0
  52. data/lib/flapjack/notification/common.rb +23 -0
  53. data/lib/flapjack/notification/email.rb +107 -0
  54. data/lib/flapjack/notification/email/alert.html.haml +48 -0
  55. data/lib/flapjack/notification/email/alert.text.erb +14 -0
  56. data/lib/flapjack/notification/sms.rb +42 -0
  57. data/lib/flapjack/notification/sms/messagenet.rb +49 -0
  58. data/lib/flapjack/notifier_engine.rb +4 -4
  59. data/lib/flapjack/notifiers/mailer/mailer.rb +6 -7
  60. data/lib/flapjack/notifiers/xmpp/xmpp.rb +12 -12
  61. data/lib/flapjack/pagerduty.rb +230 -0
  62. data/lib/flapjack/patches.rb +108 -19
  63. data/lib/flapjack/persistence/data_mapper/models/check.rb +5 -3
  64. data/lib/flapjack/persistence/data_mapper/models/check_template.rb +2 -0
  65. data/lib/flapjack/persistence/data_mapper/models/event.rb +2 -0
  66. data/lib/flapjack/persistence/data_mapper/models/node.rb +3 -1
  67. data/lib/flapjack/persistence/data_mapper/models/related_check.rb +3 -1
  68. data/lib/flapjack/pikelet.rb +56 -0
  69. data/lib/flapjack/transports/beanstalkd.rb +1 -1
  70. data/lib/flapjack/transports/result.rb +6 -6
  71. data/lib/flapjack/utility.rb +46 -0
  72. data/lib/flapjack/version.rb +5 -0
  73. data/lib/flapjack/web.rb +198 -0
  74. data/lib/flapjack/web/views/acknowledge.haml +55 -0
  75. data/lib/flapjack/web/views/check.haml +162 -0
  76. data/lib/flapjack/web/views/index.haml +92 -0
  77. data/lib/flapjack/web/views/self_stats.haml +56 -0
  78. data/lib/flapjack/{applications/worker.rb → worker/application.rb} +0 -0
  79. data/lib/flapjack/worker/cli.rb +49 -0
  80. data/{spec → spec.old}/check_sandbox/echo +0 -0
  81. data/{spec → spec.old}/check_sandbox/sandboxed_check +0 -0
  82. data/{spec → spec.old}/configs/flapjack-notifier-couchdb.ini +0 -0
  83. data/{spec → spec.old}/configs/flapjack-notifier.ini +0 -0
  84. data/{spec → spec.old}/configs/recipients.ini +0 -0
  85. data/{spec → spec.old}/helpers.rb +0 -0
  86. data/{spec → spec.old}/inifile_spec.rb +0 -0
  87. data/{spec → spec.old}/mock-notifiers/mock/init.rb +0 -0
  88. data/{spec → spec.old}/mock-notifiers/mock/mock.rb +0 -0
  89. data/{spec → spec.old}/notifier-directories/spoons/testmailer/init.rb +0 -0
  90. data/{spec → spec.old}/notifier_application_spec.rb +0 -0
  91. data/{spec → spec.old}/notifier_filters_spec.rb +0 -0
  92. data/{spec → spec.old}/notifier_options_multiplexer_spec.rb +0 -0
  93. data/{spec → spec.old}/notifier_options_spec.rb +0 -0
  94. data/{spec → spec.old}/notifier_spec.rb +0 -0
  95. data/{spec → spec.old}/notifiers/mailer_spec.rb +0 -0
  96. data/{spec → spec.old}/notifiers/xmpp_spec.rb +0 -0
  97. data/{spec → spec.old}/persistence/datamapper_spec.rb +0 -0
  98. data/{spec → spec.old}/persistence/mock_persistence_backend.rb +0 -0
  99. data/{spec → spec.old}/simple.ini +0 -0
  100. data/{spec → spec.old}/spec.opts +0 -0
  101. data/{spec → spec.old}/test-filters/blocker.rb +0 -0
  102. data/{spec → spec.old}/test-filters/mock.rb +0 -0
  103. data/{spec → spec.old}/transports/beanstalkd_spec.rb +0 -0
  104. data/{spec → spec.old}/transports/mock_transport.rb +0 -0
  105. data/{spec → spec.old}/worker_application_spec.rb +0 -0
  106. data/{spec → spec.old}/worker_options_spec.rb +0 -0
  107. data/spec/lib/flapjack/api/entity_check_presenter_spec.rb +117 -0
  108. data/spec/lib/flapjack/api/entity_presenter_spec.rb +92 -0
  109. data/spec/lib/flapjack/api_spec.rb +170 -0
  110. data/spec/lib/flapjack/coordinator_spec.rb +16 -0
  111. data/spec/lib/flapjack/data/entity_check_spec.rb +398 -0
  112. data/spec/lib/flapjack/data/entity_spec.rb +71 -0
  113. data/spec/lib/flapjack/data/event_spec.rb +6 -0
  114. data/spec/lib/flapjack/executive_spec.rb +59 -0
  115. data/spec/lib/flapjack/filters/acknowledgement_spec.rb +6 -0
  116. data/spec/lib/flapjack/filters/delays_spec.rb +6 -0
  117. data/spec/lib/flapjack/filters/detect_mass_client_failures_spec.rb +6 -0
  118. data/spec/lib/flapjack/filters/ok_spec.rb +6 -0
  119. data/spec/lib/flapjack/filters/scheduled_maintenance_spec.rb +6 -0
  120. data/spec/lib/flapjack/filters/unscheduled_maintenance_spec.rb +6 -0
  121. data/spec/lib/flapjack/jabber_spec.rb +150 -0
  122. data/spec/lib/flapjack/notification/email_spec.rb +6 -0
  123. data/spec/lib/flapjack/notification/sms_spec.rb +6 -0
  124. data/spec/lib/flapjack/pikelet_spec.rb +28 -0
  125. data/spec/lib/flapjack/web_spec.rb +188 -0
  126. data/spec/spec_helper.rb +44 -0
  127. data/spec/support/profile_all_formatter.rb +44 -0
  128. data/spec/support/uncolored_doc_formatter.rb +9 -0
  129. data/tasks/events.rake +85 -0
  130. data/tmp/acknowledge.rb +14 -0
  131. data/tmp/create_config_yaml.rb +16 -0
  132. data/tmp/create_events_failure.rb +33 -0
  133. data/tmp/create_events_ok.rb +33 -0
  134. data/tmp/create_events_ok_fail_ack_ok.rb +54 -0
  135. data/tmp/create_events_ok_failure.rb +40 -0
  136. data/tmp/create_events_ok_failure_ack.rb +54 -0
  137. data/tmp/dummy_entities.json +1 -0
  138. data/tmp/generate_nagios_test_hosts.rb +16 -0
  139. data/tmp/parse_config_yaml.rb +7 -0
  140. data/tmp/redis_delete_all_keys.rb +11 -0
  141. data/tmp/test_entities.json +1 -0
  142. metadata +482 -221
  143. data/TODO.md +0 -36
  144. data/VERSION +0 -1
  145. data/bin/flapjack-benchmark +0 -50
  146. data/bin/flapjack-notifier +0 -21
  147. data/bin/flapjack-notifier-manager +0 -43
  148. data/bin/flapjack-stats +0 -27
  149. data/bin/flapjack-worker +0 -13
  150. data/bin/flapjack-worker-manager +0 -35
  151. data/dist/etc/init.d/flapjack-notifier +0 -47
  152. data/dist/etc/init.d/flapjack-workers +0 -44
  153. data/features/flapjack-notifier-manager.feature +0 -19
  154. data/features/flapjack-worker-manager.feature +0 -27
  155. data/features/flapjack-worker.feature +0 -27
  156. data/features/netsaint-config-converter.feature +0 -126
  157. data/features/persistence/couch.feature +0 -105
  158. data/features/persistence/sqlite3.feature +0 -105
  159. data/features/persistence/steps/couch_steps.rb +0 -25
  160. data/features/persistence/steps/generic_steps.rb +0 -102
  161. data/features/persistence/steps/sqlite3_steps.rb +0 -13
  162. data/features/steps/flapjack-notifier-manager_steps.rb +0 -24
  163. data/features/steps/flapjack-worker-manager_steps.rb +0 -48
  164. data/lib/flapjack/applications/notifier.rb +0 -222
  165. data/lib/flapjack/cli/notifier.rb +0 -108
  166. data/lib/flapjack/cli/notifier_manager.rb +0 -86
  167. data/lib/flapjack/cli/worker.rb +0 -51
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/data/entity'
3
+
4
+ describe Flapjack::Data::Entity, :redis => true do
5
+
6
+ let(:name) { 'abc-123' }
7
+ let(:check) { 'ping' }
8
+
9
+ it "adds an entity, including contacts"
10
+
11
+ it "finds an entity by name"
12
+
13
+ it "creates an entity if allowed when it can't find it" do
14
+ entity = Flapjack::Data::Entity.find_by_name(name, :redis => @redis, :create => true)
15
+
16
+ entity.should_not be_nil
17
+ entity.name.should == name
18
+ @redis.get("entity_id:#{name}").should == ''
19
+ end
20
+
21
+ it "finds an entity by id"
22
+
23
+ it "returns a list of all entities" do
24
+ Flapjack::Data::Entity.add({'id' => '5000',
25
+ 'name' => name},
26
+ :redis => @redis)
27
+ Flapjack::Data::Entity.add({'id' => '5001',
28
+ 'name' => "z_" + name},
29
+ :redis => @redis)
30
+
31
+ entities = Flapjack::Data::Entity.all(:redis => @redis)
32
+ entities.should_not be_nil
33
+ entities.should be_an(Array)
34
+ entities.should have(2).entities
35
+ entities[0].id.should == 5000
36
+ entities[1].id.should == 5001
37
+ end
38
+
39
+ it "returns a list of checks for an entity" do
40
+ Flapjack::Data::Entity.add({'id' => '5000',
41
+ 'name' => name},
42
+ :redis => @redis)
43
+
44
+ @redis.hset("check:#{name}:ping", 'state', 'OK')
45
+ @redis.hset("check:#{name}:ssh", 'state', 'OK')
46
+
47
+ entity = Flapjack::Data::Entity.find_by_name(name, :redis => @redis)
48
+ check_list = entity.check_list
49
+ check_list.should_not be_nil
50
+ check_list.should have(2).checks
51
+ sorted_list = check_list.sort
52
+ sorted_list[0].should == 'ping'
53
+ sorted_list[1].should == 'ssh'
54
+ end
55
+
56
+ it "returns a count of checks for an entity" do
57
+ Flapjack::Data::Entity.add({'id' => '5000',
58
+ 'name' => name,
59
+ 'contacts' => []},
60
+ :redis => @redis)
61
+
62
+ @redis.hset("check:#{name}:ping", 'state', 'OK')
63
+ @redis.hset("check:#{name}:ssh", 'state', 'OK')
64
+
65
+ entity = Flapjack::Data::Entity.find_by_id(5000, :redis => @redis)
66
+ check_count = entity.check_count
67
+ check_count.should_not be_nil
68
+ check_count.should == 2
69
+ end
70
+
71
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/data/event'
3
+
4
+ describe Flapjack::Data::Event, :redis => true do
5
+
6
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/executive'
3
+
4
+ describe Flapjack::Executive, :redis => true do
5
+
6
+ # NB: this is only testing the public API of the Executive class, which is pretty limited.
7
+ # (initialize, main, stop). Most test coverage for this class comes from the cucumber features.
8
+
9
+ it "prompts the blocking redis connection to quit" do
10
+ redis = mock('redis')
11
+ redis.should_receive(:rpush).with('events', %q{{"type":"shutdown","host":"","service":"","state":""}})
12
+
13
+ executive = Flapjack::Executive.new
14
+ executive.bootstrap(:redis => @redis)
15
+ executive.add_shutdown_event(:redis => redis)
16
+ end
17
+
18
+ # TODO split out the setup stuff to a separate test
19
+ it "shuts down when provided with a shutdown event" do
20
+ t = Time.now.to_i
21
+
22
+ Flapjack::Filters::Ok.should_receive(:new)
23
+ Flapjack::Filters::ScheduledMaintenance.should_receive(:new)
24
+ Flapjack::Filters::UnscheduledMaintenance.should_receive(:new)
25
+ Flapjack::Filters::DetectMassClientFailures.should_receive(:new)
26
+ Flapjack::Filters::Delays.should_receive(:new)
27
+ Flapjack::Filters::Acknowledgement.should_receive(:new)
28
+
29
+ shutdown_evt = mock(Flapjack::Data::Event)
30
+ shutdown_evt.should_receive(:id).and_return('-:-')
31
+ shutdown_evt.should_receive(:type).exactly(3).times.and_return('shutdown')
32
+ shutdown_evt.should_receive(:state).and_return(nil)
33
+ shutdown_evt.should_receive(:summary).and_return(nil)
34
+ shutdown_evt.should_receive(:time).and_return(Time.now)
35
+ Flapjack::Data::Event.should_receive(:next).and_return(shutdown_evt)
36
+
37
+ EventMachine::Synchrony::ConnectionPool.should_receive(:new).and_return(@redis)
38
+
39
+ executive = Flapjack::Executive.new
40
+ executive.bootstrap(:config => {})
41
+
42
+ # hacky, but the behaviour it's mimicking (shutdown from another thread) isn't
43
+ # conducive to nice tests
44
+ executive.stub(:should_quit?).and_return(false, true)
45
+ executive.main
46
+
47
+ # TODO these will need to be made relative to the running instance,
48
+ # and a list of the running instances maintained somewhere
49
+ boot_time = @redis.get('boot_time')
50
+ boot_time.should_not be_nil
51
+ boot_time.to_i.should >= t
52
+
53
+ @redis.hget('event_counters', 'all').should == 1.to_s
54
+ @redis.hget('event_counters', 'ok').should == 0.to_s
55
+ @redis.hget('event_counters', 'failure').should == 0.to_s
56
+ @redis.hget('event_counters', 'action').should == 0.to_s
57
+ end
58
+
59
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/filters/acknowledgement'
3
+
4
+ describe Flapjack::Filters::Acknowledgement do
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/filters/delays'
3
+
4
+ describe Flapjack::Filters::Delays do
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/filters/detect_mass_client_failures'
3
+
4
+ describe Flapjack::Filters::DetectMassClientFailures do
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/filters/ok'
3
+
4
+ describe Flapjack::Filters::Ok do
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/filters/scheduled_maintenance'
3
+
4
+ describe Flapjack::Filters::ScheduledMaintenance do
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/filters/unscheduled_maintenance'
3
+
4
+ describe Flapjack::Filters::UnscheduledMaintenance do
5
+
6
+ end
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/jabber'
3
+
4
+ describe Flapjack::Jabber do
5
+
6
+ let(:config) { {'queue' => 'jabber_notifications',
7
+ 'server' => 'example.com',
8
+ 'port' => '5222',
9
+ 'jabberid' => 'flapjack@example.com',
10
+ 'password' => 'password',
11
+ 'alias' => 'flapjack',
12
+ 'rooms' => ['flapjacktest@conference.example.com']
13
+ }
14
+ }
15
+
16
+ let(:stanza) { mock('stanza') }
17
+
18
+ it "is initialized" do
19
+ fj = Flapjack::Jabber.new
20
+ fj.should_not be_nil
21
+ end
22
+
23
+ it "hooks up event handlers to the appropriate methods" do
24
+ Socket.should_receive(:gethostname).and_return('thismachine')
25
+
26
+ fj = Flapjack::Jabber.new
27
+ fj.bootstrap(:config => config)
28
+
29
+ EM.should_receive(:next_tick).exactly(4).times.and_yield
30
+ EM.should_receive(:synchrony).exactly(4).times.and_yield
31
+
32
+ fj.should_receive(:register_handler).with(:ready).and_yield(stanza)
33
+ fj.should_receive(:on_ready).with(stanza)
34
+
35
+ fj.should_receive(:register_handler).with(:message, :groupchat?, :body => /^flapjack:\s+/).and_yield(stanza)
36
+ fj.should_receive(:on_groupchat).with(stanza)
37
+
38
+ fj.should_receive(:register_handler).with(:message, :chat?).and_yield(stanza)
39
+ fj.should_receive(:on_chat).with(stanza)
40
+
41
+ fj.should_receive(:register_handler).with(:disconnected).and_yield(stanza)
42
+ fj.should_receive(:on_disconnect).with(stanza).and_return(true)
43
+
44
+ fj.setup
45
+ end
46
+
47
+ it "joins a chat room after connecting" do
48
+ fj = Flapjack::Jabber.new
49
+ fj.bootstrap(:config => config)
50
+
51
+ fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Presence))
52
+ fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
53
+
54
+ fj.on_ready(stanza)
55
+ end
56
+
57
+ it "receives an acknowledgement message" do
58
+ stanza.should_receive(:body).and_return('flapjack: ACKID 876 fixing now duration: 90m')
59
+ from = mock('from')
60
+ from.should_receive(:stripped).and_return('sender')
61
+ stanza.should_receive(:from).and_return(from)
62
+
63
+ redis = mock('redis')
64
+ redis.should_receive(:hget).with('unacknowledged_failures', '876').
65
+ and_return('main-example.com:ping')
66
+
67
+ entity_check = mock(Flapjack::Data::EntityCheck)
68
+ entity_check.should_receive(:create_acknowledgement).
69
+ with('summary' => 'fixing now', 'acknowledgement_id' => '876', 'duration' => (90 * 60))
70
+ entity_check.should_receive(:entity_name).and_return('main-example.com')
71
+ entity_check.should_receive(:check).and_return('ping')
72
+
73
+ Flapjack::Data::EntityCheck.should_receive(:for_event_id).
74
+ with('main-example.com:ping', :redis => redis).
75
+ and_return(entity_check)
76
+
77
+ fj = Flapjack::Jabber.new
78
+ fj.bootstrap(:config => config)
79
+ fj.instance_variable_set('@redis_handler', redis)
80
+
81
+ fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
82
+
83
+ fj.on_groupchat(stanza)
84
+ end
85
+
86
+ it "receives a message it doesn't understand" do
87
+ stanza.should_receive(:body).once.and_return('flapjack: hello!')
88
+ from = mock('from')
89
+ from.should_receive(:stripped).and_return('sender')
90
+ stanza.should_receive(:from).and_return(from)
91
+
92
+ fj = Flapjack::Jabber.new
93
+ fj.bootstrap(:config => config)
94
+
95
+ fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
96
+
97
+ fj.on_groupchat(stanza)
98
+ end
99
+
100
+ it "reconnects when disconnected (if not quitting)" do
101
+ fj = Flapjack::Jabber.new
102
+ fj.bootstrap(:config => config)
103
+
104
+ EventMachine::Timer.should_receive(:new).with(1).and_yield
105
+ fj.should_receive(:connect)
106
+
107
+ ret = fj.on_disconnect(stanza)
108
+ ret.should be_true
109
+ end
110
+
111
+ it "prompts the blocking redis connection to quit" do
112
+ redis = mock('redis')
113
+ redis.should_receive(:rpush).with('jabber_notifications', %q{{"notification_type":"shutdown"}})
114
+
115
+ fj = Flapjack::Jabber.new
116
+ fj.bootstrap(:config => config)
117
+
118
+ fj.add_shutdown_event(:redis => redis)
119
+ end
120
+
121
+ it "runs a blocking loop listening for notifications" do
122
+ timer_1 = mock('timer_1')
123
+ timer_2 = mock('timer_2')
124
+ timer_1.should_receive(:cancel)
125
+ timer_2.should_receive(:cancel)
126
+ EM::Synchrony.should_receive(:add_periodic_timer).with(30).and_return(timer_1)
127
+ EM::Synchrony.should_receive(:add_periodic_timer).with(60).and_return(timer_2)
128
+
129
+ redis = mock('redis')
130
+ EventMachine::Synchrony::ConnectionPool.should_receive(:new).and_return(redis)
131
+
132
+ fj = Flapjack::Jabber.new
133
+ fj.bootstrap(:config => config)
134
+
135
+ fj.should_receive(:connect)
136
+ fj.should_receive(:connected?).twice.and_return(true)
137
+ fj.should_receive(:should_quit?).exactly(3).times.and_return(false, false, true)
138
+ redis.should_receive(:blpop).twice.and_return(
139
+ ["jabber_notifications", %q{{"notification_type":"problem","event_id":"main-example.com:ping","state":"critical","summary":"!!!"}}],
140
+ ["jabber_notifications", %q{{"notification_type":"shutdown"}}]
141
+ )
142
+
143
+ EM.should_receive(:next_tick).twice.and_yield
144
+ fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
145
+ fj.should_receive(:close)
146
+
147
+ fj.main
148
+ end
149
+
150
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/notification/email'
3
+
4
+ describe Flapjack::Notification::Email do
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/notification/sms'
3
+
4
+ describe Flapjack::Notification::Sms do
5
+
6
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/pikelet'
3
+
4
+ describe Flapjack::Pikelet do
5
+
6
+ let(:stdout) { mock('StdoutOutputter') }
7
+ let(:syslogout) { mock('SyslogOutputter') }
8
+ let(:logger) { mock('Logger') }
9
+
10
+ class Breakfast
11
+ include Flapjack::Pikelet
12
+ end
13
+
14
+ it "should bootstrap an including class" do
15
+ Log4r::StdoutOutputter.should_receive(:new).and_return(stdout)
16
+ Log4r::SyslogOutputter.should_receive(:new).and_return(syslogout)
17
+ logger.should_receive(:add).with(stdout)
18
+ logger.should_receive(:add).with(syslogout)
19
+ Log4r::Logger.should_receive(:new).and_return(logger)
20
+
21
+ b = Breakfast.new
22
+ b.bootstrap
23
+
24
+ b.should respond_to(:logger)
25
+ b.logger.should equal(logger)
26
+ end
27
+
28
+ end
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/web'
3
+
4
+ # TODO move the rest of the redis operations down to data models, then this
5
+ # test won't need read/write redis data
6
+
7
+ describe Flapjack::Web, :sinatra => true, :redis => true do
8
+
9
+ def app
10
+ Flapjack::Web
11
+ end
12
+
13
+ let(:entity_name) { 'example.com'}
14
+ let(:entity_name_esc) { URI.escape(entity_name) }
15
+ let(:check) { 'ping' }
16
+
17
+ let(:entity) { mock(Flapjack::Data::Entity) }
18
+ let(:entity_check) { mock(Flapjack::Data::EntityCheck) }
19
+
20
+ before(:each) do
21
+ Flapjack::Web.class_variable_set('@@redis', @redis)
22
+ end
23
+
24
+ def expect_stats
25
+ @redis.should_receive(:keys).with('*').and_return([])
26
+ @redis.should_receive(:zcard).with('failed_checks')
27
+ @redis.should_receive(:keys).with('check:*:*').and_return([])
28
+ @redis.should_receive(:hget).with('event_counters', 'all')
29
+ @redis.should_receive(:hget).with('event_counters', 'ok')
30
+ @redis.should_receive(:hget).with('event_counters', 'failure')
31
+ @redis.should_receive(:hget).with('event_counters', 'action')
32
+ @redis.should_receive(:get).with('boot_time').and_return(0)
33
+ @redis.should_receive(:llen).with('events')
34
+ end
35
+
36
+ def expect_entity_check_status(ec)
37
+ time = Time.now.to_i
38
+
39
+ ec.should_receive(:state).and_return('ok')
40
+ ec.should_receive(:last_update).and_return(time - (3 * 60 * 60))
41
+ ec.should_receive(:last_change).and_return(time - (3 * 60 * 60))
42
+ ec.should_receive(:last_problem_notification).and_return(time - ((3 * 60 * 60) + (5 * 60)))
43
+ ec.should_receive(:last_recovery_notification).and_return(time - (3 * 60 * 60))
44
+ ec.should_receive(:last_acknowledgement_notification).and_return(nil)
45
+ ec.should_receive(:in_scheduled_maintenance?).and_return(false)
46
+ ec.should_receive(:in_unscheduled_maintenance?).and_return(false)
47
+ end
48
+
49
+ # TODO add data, test that pages contain representations of it
50
+ # (for the methods that access redis directly)
51
+
52
+ it "shows a page listing all checks" do
53
+ @redis.should_receive(:keys).with('*:*:states').and_return(["#{entity_name}:#{check}:states"])
54
+
55
+ expect_stats
56
+
57
+ expect_entity_check_status(entity_check)
58
+
59
+ Flapjack::Data::Entity.should_receive(:find_by_name).
60
+ with(entity_name, :redis => @redis).and_return(entity)
61
+
62
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
63
+ with(entity, 'ping', :redis => @redis).and_return(entity_check)
64
+
65
+ get '/'
66
+ last_response.should be_ok
67
+ end
68
+
69
+ it "shows a page listing failing checks" do
70
+ @redis.should_receive(:zrange).with('failed_checks', 0, -1).and_return(["#{entity_name}:#{check}:states"])
71
+
72
+ expect_stats
73
+
74
+ expect_entity_check_status(entity_check)
75
+
76
+ Flapjack::Data::Entity.should_receive(:find_by_name).
77
+ with(entity_name, :redis => @redis).and_return(entity)
78
+
79
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
80
+ with(entity, 'ping', :redis => @redis).and_return(entity_check)
81
+ get '/failing'
82
+ last_response.should be_ok
83
+ end
84
+
85
+ it "shows a page listing flapjack statistics" do
86
+ expect_stats
87
+
88
+ get '/self_stats'
89
+ last_response.should be_ok
90
+ end
91
+
92
+ it "shows the state of a check for an entity" do
93
+ time = Time.now.to_i
94
+
95
+ entity_check.should_receive(:state).and_return('ok')
96
+ entity_check.should_receive(:last_update).and_return(time - (3 * 60 * 60))
97
+ entity_check.should_receive(:last_change).and_return(time - (3 * 60 * 60))
98
+ entity_check.should_receive(:summary).and_return('all good')
99
+ entity_check.should_receive(:last_problem_notification).and_return(time - ((3 * 60 * 60) + (5 * 60)))
100
+ entity_check.should_receive(:last_recovery_notification).and_return(time - (3 * 60 * 60))
101
+ entity_check.should_receive(:last_acknowledgement_notification).and_return(nil)
102
+ entity_check.should_receive(:in_scheduled_maintenance?).and_return(false)
103
+ entity_check.should_receive(:in_unscheduled_maintenance?).and_return(false)
104
+ entity_check.should_receive(:maintenances).with(nil, nil, :scheduled => true).and_return([])
105
+ entity_check.should_receive(:failed?).and_return(false)
106
+
107
+ Flapjack::Data::Entity.should_receive(:find_by_name).
108
+ with(entity_name, :redis => @redis).and_return(entity)
109
+
110
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
111
+ with(entity, 'ping', :redis => @redis).and_return(entity_check)
112
+
113
+ get "/check?entity=#{entity_name_esc}&check=ping"
114
+ last_response.should be_ok
115
+ # TODO test instance variables set to appropriate values
116
+ end
117
+
118
+ it "returns 404 if an unknown entity is requested" do
119
+ get "/check?entity=#{entity_name_esc}&check=ping"
120
+ last_response.should be_not_found
121
+ end
122
+
123
+ # TODO shouldn't create actual entity record
124
+ it "returns 404 if no entity check is passed" do
125
+ Flapjack::Data::Entity.add({'id' => '5000',
126
+ 'name' => entity_name},
127
+ :redis => @redis)
128
+ get "/check?entity=#{entity_name_esc}"
129
+ last_response.should be_not_found
130
+ end
131
+
132
+ it "creates an acknowledgement for an entity check" do
133
+ Flapjack::Data::Entity.should_receive(:find_by_name).
134
+ with(entity_name, :redis => @redis).and_return(entity)
135
+
136
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
137
+ with(entity, 'ping', :redis => @redis).and_return(entity_check)
138
+
139
+ entity_check.should_receive(:create_acknowledgement).
140
+ with(an_instance_of(Hash))
141
+
142
+ post "/acknowledgements/#{entity_name_esc}/ping"
143
+ last_response.status.should == 201
144
+ end
145
+
146
+ it "creates a scheduled maintenance period for an entity check" do
147
+ t = Time.now.to_i
148
+
149
+ start_time = Time.at(t - (24 * 60 * 60))
150
+ duration = 30 * 60
151
+ summary = 'wow'
152
+
153
+ Chronic.should_receive(:parse).with('1 day ago').and_return(start_time)
154
+ ChronicDuration.should_receive(:parse).with('30 minutes').and_return(duration)
155
+
156
+ Flapjack::Data::Entity.should_receive(:find_by_name).
157
+ with(entity_name, :redis => @redis).and_return(entity)
158
+
159
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
160
+ with(entity, 'ping', :redis => @redis).and_return(entity_check)
161
+
162
+ entity_check.should_receive(:create_scheduled_maintenance).
163
+ with(:start_time => start_time.to_i, :duration => duration, :summary => summary)
164
+
165
+ post "/scheduled_maintenances/#{entity_name_esc}/ping?"+
166
+ "start_time=1+day+ago&duration=30+minutes&summary=wow"
167
+ last_response.status.should == 302
168
+ end
169
+
170
+ it "deletes a scheduled maintenance period for an entity check" do
171
+ t = Time.now.to_i
172
+
173
+ start_time = t - (24 * 60 * 60)
174
+
175
+ Flapjack::Data::Entity.should_receive(:find_by_name).
176
+ with(entity_name, :redis => @redis).and_return(entity)
177
+
178
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
179
+ with(entity, 'ping', :redis => @redis).and_return(entity_check)
180
+
181
+ entity_check.should_receive(:delete_scheduled_maintenance).
182
+ with(:start_time => start_time)
183
+
184
+ delete "/scheduled_maintenances/#{entity_name_esc}/ping?start_time=#{start_time}"
185
+ last_response.status.should == 302
186
+ end
187
+
188
+ end