flapjack 0.5.5 → 0.6.23

Sign up to get free protection for your applications and to get access to all the features.
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/api/entity_check_presenter'
3
+
4
+ # require 'flapjack/data/entity'
5
+ # require 'flapjack/data/entity_check'
6
+
7
+ describe 'Flapjack::API::EntityCheck::Presenter' do
8
+
9
+ let(:entity_check) { mock(Flapjack::Data::EntityCheck) }
10
+
11
+ let(:time) { Time.now.to_i }
12
+
13
+ let(:states) {
14
+ [{:state => 'critical', :timestamp => time - (4 * 60 * 60)},
15
+ {:state => 'ok', :timestamp => time - (4 * 60 * 60) + (5 * 60)},
16
+ {:state => 'critical', :timestamp => time - (3 * 60 * 60)},
17
+ {:state => 'ok', :timestamp => time - (3 * 60 * 60) + (10 * 60)},
18
+ {:state => 'critical', :timestamp => time - (2 * 60 * 60)},
19
+ {:state => 'ok', :timestamp => time - (2 * 60 * 60) + (15 * 60)},
20
+ {:state => 'critical', :timestamp => time - (1 * 60 * 60)},
21
+ {:state => 'ok', :timestamp => time - (1 * 60 * 60) + (20 * 60)}
22
+ ]
23
+ }
24
+
25
+ # one overlap at start, one overlap at end, one wholly overlapping,
26
+ # one wholly contained
27
+ let(:maintenances) {
28
+ [{:start_time => time - ((4 * 60 * 60) + (1 * 60)), # 1 minute before outage starts
29
+ :end_time => time - (4 * 60 * 60) + (2 * 60), # 2 minutes after outage starts
30
+ :duration => (3 * 60)},
31
+ {:start_time => time - (3 * 60 * 60) + (8 * 60), # 2 minutes before outage ends
32
+ :end_time => time - (3 * 60 * 60) + (11 * 60), # 1 minute after outage ends
33
+ :duration => (3 * 60)},
34
+ {:start_time => time - ((2 * 60 * 60) + (1 * 60)), # 1 minute before outage starts
35
+ :end_time => time - (2 * 60 * 60) + (17 * 60), # 2 minutes after outage ends
36
+ :duration => (3 * 60)},
37
+ {:start_time => time - (1 * 60 * 60) + (1 * 60), # 1 minute after outage starts
38
+ :end_time => time - (1 * 60 * 60) + (10 * 60), # 10 minutes before outage ends
39
+ :duration => (9 * 60)}
40
+ ]
41
+ }
42
+
43
+ it "returns a list of outage hashes for an entity check" do
44
+ entity_check.should_receive(:historical_states).
45
+ with(time - (5 * 60 * 60), time - (2 * 60 * 60)).and_return(states)
46
+
47
+ entity_check.should_receive(:historical_state_before).
48
+ with(time - (4 * 60 * 60)).and_return(nil)
49
+
50
+ ecp = Flapjack::API::EntityCheckPresenter.new(entity_check)
51
+ outages = ecp.outages(time - (5 * 60 * 60), time - (2 * 60 * 60))
52
+ outages.should_not be_nil
53
+ outages.should be_an(Array)
54
+ outages.should have(4).time_ranges
55
+
56
+ # TODO check the data in those hashes
57
+ end
58
+
59
+ it "a list of unscheduled maintenances for an entity check" do
60
+ entity_check.should_receive(:maintenances).
61
+ with(time - (12 * 60 * 60), time, :scheduled => false).and_return(maintenances)
62
+
63
+ entity_check.should_receive(:maintenances).
64
+ with(nil, time - (12 * 60 * 60), :scheduled => false).and_return([])
65
+
66
+ ecp = Flapjack::API::EntityCheckPresenter.new(entity_check)
67
+ unsched_maint = ecp.unscheduled_maintenance(time - (12 * 60 * 60), time)
68
+
69
+ unsched_maint.should be_an(Array)
70
+ unsched_maint.should have(4).time_ranges
71
+
72
+ # TODO check the data in those hashes
73
+ end
74
+
75
+ it "a list of scheduled maintenances for an entity check" do
76
+ entity_check.should_receive(:maintenances).
77
+ with(time - (12 * 60 * 60), time, :scheduled => true).and_return(maintenances)
78
+
79
+ entity_check.should_receive(:maintenances).
80
+ with(nil, time - (12 * 60 * 60), :scheduled => true).and_return([])
81
+
82
+ ecp = Flapjack::API::EntityCheckPresenter.new(entity_check)
83
+ sched_maint = ecp.scheduled_maintenance(time - (12 * 60 * 60), time)
84
+
85
+ sched_maint.should be_an(Array)
86
+ sched_maint.should have(4).time_ranges
87
+
88
+ # TODO check the data in those hashes
89
+ end
90
+
91
+ it "returns downtime and percentage for an entity check" do
92
+ entity_check.should_receive(:historical_states).
93
+ with(time - (12 * 60 * 60), time).and_return(states)
94
+
95
+ entity_check.should_receive(:historical_state_before).
96
+ with(time - (4 * 60 * 60)).and_return(nil)
97
+
98
+ entity_check.should_receive(:maintenances).
99
+ with(time - (12 * 60 * 60), time, :scheduled => true).and_return(maintenances)
100
+
101
+ entity_check.should_receive(:maintenances).
102
+ with(nil, time - (12 * 60 * 60), :scheduled => true).and_return([])
103
+
104
+ ecp = Flapjack::API::EntityCheckPresenter.new(entity_check)
105
+ downtimes = ecp.downtime(time - (12 * 60 * 60), time)
106
+
107
+ # 22 minutes, 3 + 8 + 11
108
+ downtimes.should be_a(Hash)
109
+ downtimes[:total_seconds].should == (22 * 60)
110
+ downtimes[:percentage].should == (((22 * 60) * 100) / (12 * 60 * 60))
111
+ downtimes[:downtime].should be_an(Array)
112
+ # the last outage gets split by the intervening maintenance period,
113
+ # but the fully covered one gets removed.
114
+ downtimes[:downtime].should have(4).time_ranges
115
+ end
116
+
117
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/api/entity_presenter'
3
+
4
+ describe 'Flapjack::API::Entity::Presenter' do
5
+
6
+ let(:entity) { mock(Flapjack::Data::Entity) }
7
+
8
+ let(:check_a) { mock(Flapjack::Data::EntityCheck) }
9
+ let(:check_b) { mock(Flapjack::Data::EntityCheck) }
10
+
11
+ let(:checkpres_a) { mock(Flapjack::API::EntityCheckPresenter) }
12
+ let(:checkpres_b) { mock(Flapjack::API::EntityCheckPresenter) }
13
+
14
+ let(:time) { Time.now.to_i }
15
+
16
+ let(:start_time) { time - (6 * 60 * 60) }
17
+ let(:end_time) { time - (2 * 60 * 60) }
18
+
19
+ def expect_check_presenters
20
+ entity.should_receive(:check_list).and_return(['ssh', 'ping'])
21
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
22
+ with(entity, 'ssh', anything).and_return(check_a)
23
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
24
+ with(entity, 'ping', anything).and_return(check_b)
25
+
26
+ Flapjack::API::EntityCheckPresenter.should_receive(:new).
27
+ with(check_a).and_return(checkpres_a)
28
+ Flapjack::API::EntityCheckPresenter.should_receive(:new).
29
+ with(check_b).and_return(checkpres_b)
30
+ end
31
+
32
+ it "returns a list of outage hashes for each check on an entity" do
33
+ expect_check_presenters
34
+ outages_a = mock('outages_a')
35
+ outages_b = mock('outages_b')
36
+ checkpres_a.should_receive(:outages).with(start_time, end_time).
37
+ and_return(outages_a)
38
+ checkpres_b.should_receive(:outages).with(start_time, end_time).
39
+ and_return(outages_b)
40
+
41
+ ep = Flapjack::API::EntityPresenter.new(entity)
42
+ outages = ep.outages(start_time, end_time)
43
+ outages.should == [{:check => 'ssh', :outages => outages_a},
44
+ {:check => 'ping', :outages => outages_b}]
45
+ end
46
+
47
+ it "returns a list of unscheduled maintenance periods for each check on an entity" do
48
+ expect_check_presenters
49
+ unsched_maint_a = mock('unsched_maint_a')
50
+ unsched_maint_b = mock('unsched_maint_b')
51
+ checkpres_a.should_receive(:unscheduled_maintenance).with(start_time, end_time).
52
+ and_return(unsched_maint_a)
53
+ checkpres_b.should_receive(:unscheduled_maintenance).with(start_time, end_time).
54
+ and_return(unsched_maint_b)
55
+
56
+ ep = Flapjack::API::EntityPresenter.new(entity)
57
+ unsched_maint = ep.unscheduled_maintenance(start_time, end_time)
58
+ unsched_maint.should == [{:check => 'ssh', :unscheduled_maintenance => unsched_maint_a},
59
+ {:check => 'ping', :unscheduled_maintenance => unsched_maint_b}]
60
+ end
61
+
62
+ it "returns a list of scheduled maintenance periods for each check on an entity" do
63
+ expect_check_presenters
64
+ sched_maint_a = mock('sched_maint_a')
65
+ sched_maint_b = mock('sched_maint_b')
66
+ checkpres_a.should_receive(:scheduled_maintenance).with(start_time, end_time).
67
+ and_return(sched_maint_a)
68
+ checkpres_b.should_receive(:scheduled_maintenance).with(start_time, end_time).
69
+ and_return(sched_maint_b)
70
+
71
+ ep = Flapjack::API::EntityPresenter.new(entity)
72
+ sched_maint = ep.scheduled_maintenance(start_time, end_time)
73
+ sched_maint.should == [{:check => 'ssh', :scheduled_maintenance => sched_maint_a},
74
+ {:check => 'ping', :scheduled_maintenance => sched_maint_b}]
75
+ end
76
+
77
+ it "returns a list of downtime for each check on an entity" do
78
+ expect_check_presenters
79
+ downtime_a = mock('downtime_a')
80
+ downtime_b = mock('downtime_b')
81
+ checkpres_a.should_receive(:downtime).with(start_time, end_time).
82
+ and_return(downtime_a)
83
+ checkpres_b.should_receive(:downtime).with(start_time, end_time).
84
+ and_return(downtime_b)
85
+
86
+ ep = Flapjack::API::EntityPresenter.new(entity)
87
+ downtime = ep.downtime(start_time, end_time)
88
+ downtime.should == [{:check => 'ssh', :downtime => downtime_a},
89
+ {:check => 'ping', :downtime => downtime_b}]
90
+ end
91
+
92
+ end
@@ -0,0 +1,170 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/api'
3
+
4
+ describe 'Flapjack::API', :sinatra => true do
5
+
6
+ def app
7
+ Flapjack::API
8
+ end
9
+
10
+ let(:entity) { mock(Flapjack::Data::Entity) }
11
+ let(:entity_check) { mock(Flapjack::Data::EntityCheck) }
12
+
13
+ let(:entity_name) { 'example.com'}
14
+ let(:entity_name_esc) { URI.escape(entity_name) }
15
+ let(:check) { 'ping' }
16
+
17
+ let(:entity_presenter) { mock(Flapjack::API::EntityPresenter) }
18
+ let(:entity_check_presenter) { mock(Flapjack::API::EntityCheckPresenter) }
19
+
20
+ let(:redis) { mock(::Redis) }
21
+
22
+ before(:each) do
23
+ Flapjack::API.class_variable_set('@@redis', redis)
24
+ end
25
+
26
+ it "returns a list of checks for an entity" do
27
+ check_list = ['ping']
28
+ entity.should_receive(:check_list).and_return(check_list)
29
+ Flapjack::Data::Entity.should_receive(:find_by_name).
30
+ with(entity_name, :redis => redis).and_return(entity)
31
+
32
+ get "/checks/#{entity_name_esc}"
33
+ last_response.should be_ok
34
+ last_response.body.should == check_list.to_json
35
+ end
36
+
37
+ it "returns a list of scheduled maintenance periods for an entity" do
38
+ result = mock('result')
39
+ result_json = %q{"result"}
40
+ result.should_receive(:to_json).and_return(result_json)
41
+ entity_presenter.should_receive(:scheduled_maintenance).with(nil, nil).and_return(result)
42
+ Flapjack::API::EntityPresenter.should_receive(:new).
43
+ with(entity, :redis => redis).and_return(entity_presenter)
44
+ Flapjack::Data::Entity.should_receive(:find_by_name).
45
+ with(entity_name, :redis => redis).and_return(entity)
46
+
47
+ get "/scheduled_maintenances/#{entity_name_esc}"
48
+ last_response.should be_ok
49
+ last_response.body.should == result_json
50
+ end
51
+
52
+ it "returns a list of scheduled maintenance periods within a time window for an entity"
53
+
54
+ it "returns a list of scheduled maintenance periods for a check on an entity" do
55
+ result = mock('result')
56
+ result_json = %q{"result"}
57
+ result.should_receive(:to_json).and_return(result_json)
58
+ entity_check_presenter.should_receive(:scheduled_maintenance).with(nil, nil).and_return(result)
59
+ Flapjack::API::EntityCheckPresenter.should_receive(:new).
60
+ with(entity_check).and_return(entity_check_presenter)
61
+ Flapjack::Data::Entity.should_receive(:find_by_name).
62
+ with(entity_name, :redis => redis).and_return(entity)
63
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
64
+ with(entity, check, :redis => redis).and_return(entity_check)
65
+
66
+ get "/scheduled_maintenances/#{entity_name_esc}/#{check}"
67
+ last_response.should be_ok
68
+ last_response.body.should == result_json
69
+ end
70
+
71
+ it "returns a list of unscheduled maintenance periods for an entity" do
72
+ result = mock('result')
73
+ result_json = %q{"result"}
74
+ result.should_receive(:to_json).and_return(result_json)
75
+ entity_presenter.should_receive(:unscheduled_maintenance).with(nil, nil).and_return(result)
76
+ Flapjack::API::EntityPresenter.should_receive(:new).
77
+ with(entity, :redis => redis).and_return(entity_presenter)
78
+ Flapjack::Data::Entity.should_receive(:find_by_name).
79
+ with(entity_name, :redis => redis).and_return(entity)
80
+
81
+ get "/unscheduled_maintenances/#{entity_name_esc}"
82
+ last_response.should be_ok
83
+ last_response.body.should == result_json
84
+ end
85
+
86
+ it "returns a list of unscheduled maintenance periods for a check on an entity" do
87
+ result = mock('result')
88
+ result_json = %q{"result"}
89
+ result.should_receive(:to_json).and_return(result_json)
90
+ entity_check_presenter.should_receive(:unscheduled_maintenance).with(nil, nil).and_return(result)
91
+ Flapjack::API::EntityCheckPresenter.should_receive(:new).
92
+ with(entity_check).and_return(entity_check_presenter)
93
+ Flapjack::Data::Entity.should_receive(:find_by_name).
94
+ with(entity_name, :redis => redis).and_return(entity)
95
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
96
+ with(entity, check, :redis => redis).and_return(entity_check)
97
+
98
+ get "/unscheduled_maintenances/#{entity_name_esc}/#{check}"
99
+ last_response.should be_ok
100
+ last_response.body.should == result_json
101
+ end
102
+
103
+
104
+ it "returns a list of unscheduled maintenance periods within a time window for a check an entity"
105
+
106
+ it "returns a list of outages for an entity" do
107
+ result = mock('result')
108
+ result_json = %q{"result"}
109
+ result.should_receive(:to_json).and_return(result_json)
110
+ entity_presenter.should_receive(:outages).with(nil, nil).and_return(result)
111
+ Flapjack::API::EntityPresenter.should_receive(:new).
112
+ with(entity, :redis => redis).and_return(entity_presenter)
113
+ Flapjack::Data::Entity.should_receive(:find_by_name).
114
+ with(entity_name, :redis => redis).and_return(entity)
115
+
116
+ get "/outages/#{entity_name_esc}"
117
+ last_response.should be_ok
118
+ last_response.body.should == result_json
119
+ end
120
+
121
+ it "returns a list of outages for a check on an entity" do
122
+ result = mock('result')
123
+ result_json = %q{"result"}
124
+ result.should_receive(:to_json).and_return(result_json)
125
+ entity_check_presenter.should_receive(:outages).with(nil, nil).and_return(result)
126
+ Flapjack::API::EntityCheckPresenter.should_receive(:new).
127
+ with(entity_check).and_return(entity_check_presenter)
128
+ Flapjack::Data::Entity.should_receive(:find_by_name).
129
+ with(entity_name, :redis => redis).and_return(entity)
130
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
131
+ with(entity, check, :redis => redis).and_return(entity_check)
132
+
133
+ get "/outages/#{entity_name_esc}/#{check}"
134
+ last_response.should be_ok
135
+ last_response.body.should == result_json
136
+ end
137
+
138
+ it "returns a list of downtimes for an entity" do
139
+ result = mock('result')
140
+ result_json = %q{"result"}
141
+ result.should_receive(:to_json).and_return(result_json)
142
+ entity_presenter.should_receive(:downtime).with(nil, nil).and_return(result)
143
+ Flapjack::API::EntityPresenter.should_receive(:new).
144
+ with(entity, :redis => redis).and_return(entity_presenter)
145
+ Flapjack::Data::Entity.should_receive(:find_by_name).
146
+ with(entity_name, :redis => redis).and_return(entity)
147
+
148
+ get "/downtime/#{entity_name_esc}"
149
+ last_response.should be_ok
150
+ last_response.body.should == result_json
151
+ end
152
+
153
+ it "returns a list of downtimes for a check on an entity" do
154
+ result = mock('result')
155
+ result_json = %q{"result"}
156
+ result.should_receive(:to_json).and_return(result_json)
157
+ entity_check_presenter.should_receive(:downtime).with(nil, nil).and_return(result)
158
+ Flapjack::API::EntityCheckPresenter.should_receive(:new).
159
+ with(entity_check).and_return(entity_check_presenter)
160
+ Flapjack::Data::Entity.should_receive(:find_by_name).
161
+ with(entity_name, :redis => redis).and_return(entity)
162
+ Flapjack::Data::EntityCheck.should_receive(:for_entity).
163
+ with(entity, check, :redis => redis).and_return(entity_check)
164
+
165
+ get "/downtime/#{entity_name_esc}/#{check}"
166
+ last_response.should be_ok
167
+ last_response.body.should == result_json
168
+ end
169
+
170
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/coordinator'
3
+
4
+ describe Flapjack::Coordinator do
5
+
6
+ it "is initialized"
7
+
8
+ it "starts a suite of services based on config settings"
9
+
10
+ it "runs daemonized"
11
+
12
+ it "runs undaemonized"
13
+
14
+ it "stops its services when closing"
15
+
16
+ end
@@ -0,0 +1,398 @@
1
+ require 'spec_helper'
2
+
3
+ require 'yajl/json_gem'
4
+
5
+ require 'flapjack/data/entity'
6
+ require 'flapjack/data/entity_check'
7
+
8
+ describe Flapjack::Data::EntityCheck, :redis => true do
9
+
10
+ let(:name) { 'abc-123' }
11
+ let(:check) { 'ping' }
12
+
13
+ let(:half_an_hour) { 30 * 60 }
14
+
15
+ before(:each) do
16
+ Flapjack::Data::Entity.add({'id' => '5000',
17
+ 'name' => name},
18
+ :redis => @redis)
19
+ end
20
+
21
+ it "is created for an event id" do
22
+ ec = Flapjack::Data::EntityCheck.for_event_id("#{name}:ping", :redis => @redis)
23
+ ec.should_not be_nil
24
+ ec.entity.should_not be_nil
25
+ ec.entity.name.should_not be_nil
26
+ ec.entity.name.should == name
27
+ ec.check.should_not be_nil
28
+ ec.check.should == 'ping'
29
+ end
30
+
31
+ it "is created for an entity name" do
32
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, 'ping', :redis => @redis)
33
+ ec.should_not be_nil
34
+ ec.entity.should_not be_nil
35
+ ec.entity.name.should_not be_nil
36
+ ec.entity.name.should == name
37
+ ec.check.should_not be_nil
38
+ ec.check.should == 'ping'
39
+ end
40
+
41
+ it "is created for an entity id" do
42
+ ec = Flapjack::Data::EntityCheck.for_entity_id(5000, 'ping', :redis => @redis)
43
+ ec.should_not be_nil
44
+ ec.entity.should_not be_nil
45
+ ec.entity.name.should_not be_nil
46
+ ec.entity.name.should == name
47
+ ec.check.should_not be_nil
48
+ ec.check.should == 'ping'
49
+ end
50
+
51
+ it "is created for an entity object" do
52
+ e = Flapjack::Data::Entity.find_by_name(name, :redis => @redis)
53
+ ec = Flapjack::Data::EntityCheck.for_entity(e, 'ping', :redis => @redis)
54
+ ec.should_not be_nil
55
+ ec.entity.should_not be_nil
56
+ ec.entity.name.should_not be_nil
57
+ ec.entity.name.should == name
58
+ ec.check.should_not be_nil
59
+ ec.check.should == 'ping'
60
+ end
61
+
62
+ it "is not created for a missing entity" do
63
+ expect {
64
+ Flapjack::Data::EntityCheck.for_entity(nil, 'ping', :redis => @redis)
65
+ }.to raise_error
66
+ end
67
+
68
+ it "raises an error if not created with a redis connection handle" do
69
+ expect {
70
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, 'ping')
71
+ }.to raise_error
72
+ end
73
+
74
+ context "maintenance" do
75
+
76
+ it "returns that it is in unscheduled maintenance" do
77
+ @redis.set("#{name}:#{check}:unscheduled_maintenance", Time.now.to_i.to_s)
78
+
79
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
80
+ ec.should be_in_unscheduled_maintenance
81
+ end
82
+
83
+ it "returns that it is not in unscheduled maintenance" do
84
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
85
+ ec.should_not be_in_unscheduled_maintenance
86
+ end
87
+
88
+ it "returns that it is in scheduled maintenance" do
89
+ @redis.set("#{name}:#{check}:scheduled_maintenance", Time.now.to_i.to_s)
90
+
91
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
92
+ ec.should be_in_scheduled_maintenance
93
+ end
94
+
95
+ it "returns that it is not in scheduled maintenance" do
96
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
97
+ ec.should_not be_in_scheduled_maintenance
98
+ end
99
+
100
+ it "creates an unscheduled maintenance period" do
101
+ t = Time.now.to_i
102
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
103
+ ec.create_unscheduled_maintenance(:start_time => t, :duration => half_an_hour, :summary => 'oops')
104
+
105
+ timestamp = @redis.get("#{name}:#{check}:unscheduled_maintenance")
106
+ timestamp.should_not be_nil
107
+ timestamp.should == t.to_s
108
+
109
+ umps = @redis.zrange("#{name}:#{check}:unscheduled_maintenances", 0, -1, :with_scores => true)
110
+ umps.should_not be_nil
111
+ umps.should be_an(Array)
112
+ umps.should have(1).unscheduled_maintenance_period
113
+ umps[0].should be_an(Array)
114
+
115
+ start_time = umps[0][0]
116
+ start_time.should_not be_nil
117
+ start_time.should be_a(String)
118
+ start_time.should == t.to_s
119
+
120
+ score = umps[0][1]
121
+ score.should_not be_nil
122
+ score.should be_a(Float)
123
+ score.should == half_an_hour
124
+
125
+ summary = @redis.get("#{name}:#{check}:#{t}:unscheduled_maintenance:summary")
126
+ summary.should_not be_nil
127
+ summary.should == 'oops'
128
+ end
129
+
130
+ it "creates a scheduled maintenance period for a future time" do
131
+ t = Time.now.to_i
132
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
133
+ ec.create_scheduled_maintenance(:start_time => t + (60 * 60),
134
+ :duration => half_an_hour, :summary => "30 minutes")
135
+
136
+ smps = @redis.zrange("#{name}:#{check}:scheduled_maintenances", 0, -1, :with_scores => true)
137
+ smps.should_not be_nil
138
+ smps.should be_an(Array)
139
+ smps.should have(1).scheduled_maintenance_period
140
+ smps[0].should be_an(Array)
141
+
142
+ start_time = smps[0][0]
143
+ start_time.should_not be_nil
144
+ start_time.should be_a(String)
145
+ start_time.should == (t + (60 * 60)).to_s
146
+
147
+ score = smps[0][1]
148
+ score.should_not be_nil
149
+ score.should be_a(Float)
150
+ score.should == half_an_hour
151
+ end
152
+
153
+ it "creates a scheduled maintenance period covering the current time"
154
+
155
+ it "removes a scheduled maintenance period for a future time"
156
+
157
+ it "removes a scheduled maintenance period covering a current time"
158
+
159
+ it "returns a list of scheduled maintenance periods" do
160
+ t = Time.now.to_i
161
+ five_hours_ago = t - (60 * 60 * 5)
162
+ three_hours_ago = t - (60 * 60 * 3)
163
+
164
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
165
+ ec.create_scheduled_maintenance(:start_time => five_hours_ago,
166
+ :duration => half_an_hour, :summary => "first")
167
+ ec.create_scheduled_maintenance(:start_time => three_hours_ago,
168
+ :duration => half_an_hour, :summary => "second")
169
+
170
+ smp = ec.maintenances(nil, nil, :scheduled => true)
171
+ smp.should_not be_nil
172
+ smp.should be_an(Array)
173
+ smp.should have(2).scheduled_maintenance_periods
174
+ smp[0].should == {:start_time => five_hours_ago,
175
+ :end_time => five_hours_ago + half_an_hour,
176
+ :duration => half_an_hour,
177
+ :summary => "first"}
178
+ smp[1].should == {:start_time => three_hours_ago,
179
+ :end_time => three_hours_ago + half_an_hour,
180
+ :duration => half_an_hour,
181
+ :summary => "second"}
182
+ end
183
+
184
+ it "returns a list of unscheduled maintenance periods" do
185
+ t = Time.now.to_i
186
+ five_hours_ago = t - (60 * 60 * 5)
187
+ three_hours_ago = t - (60 * 60 * 3)
188
+
189
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
190
+ ec.create_unscheduled_maintenance(:start_time => five_hours_ago,
191
+ :duration => half_an_hour, :summary => "first")
192
+ ec.create_unscheduled_maintenance(:start_time => three_hours_ago,
193
+ :duration => half_an_hour, :summary => "second")
194
+
195
+ ump = ec.maintenances(nil, nil, :scheduled => false)
196
+ ump.should_not be_nil
197
+ ump.should be_an(Array)
198
+ ump.should have(2).unscheduled_maintenance_periods
199
+ ump[0].should == {:start_time => five_hours_ago,
200
+ :end_time => five_hours_ago + half_an_hour,
201
+ :duration => half_an_hour,
202
+ :summary => "first"}
203
+ ump[1].should == {:start_time => three_hours_ago,
204
+ :end_time => three_hours_ago + half_an_hour,
205
+ :duration => half_an_hour,
206
+ :summary => "second"}
207
+ end
208
+
209
+ it "updates scheduled maintenance periods"
210
+
211
+ end
212
+
213
+ it "creates an event" do
214
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
215
+ t = Time.now.to_i
216
+ ec.create_event('type' => 'service',
217
+ 'state' => 'ok',
218
+ 'summary' => 'everything checked out',
219
+ 'time' => t)
220
+ event_json = @redis.rpop('events')
221
+ event_json.should_not be_nil
222
+ event = nil
223
+ expect {
224
+ event = JSON.parse(event_json)
225
+ }.not_to raise_error
226
+ event.should_not be_nil
227
+ event.should be_a(Hash)
228
+ event.should == {
229
+ 'entity' => name,
230
+ 'check' => check,
231
+ 'type' => 'service',
232
+ 'state' => 'ok',
233
+ 'summary' => 'everything checked out',
234
+ 'time' => t
235
+ }
236
+ end
237
+
238
+ it "creates an acknowledgement" do
239
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
240
+ t = Time.now.to_i
241
+ ec.create_acknowledgement('summary' => 'looking now',
242
+ 'time' => t,
243
+ 'acknowledgement_id' => '75',
244
+ 'duration' => 40 * 60)
245
+ event_json = @redis.rpop('events')
246
+ event_json.should_not be_nil
247
+ event = nil
248
+ expect {
249
+ event = JSON.parse(event_json)
250
+ }.not_to raise_error
251
+ event.should_not be_nil
252
+ event.should be_a(Hash)
253
+ event.should == {
254
+ 'entity' => name,
255
+ 'check' => check,
256
+ 'type' => 'action',
257
+ 'state' => 'acknowledgement',
258
+ 'summary' => 'looking now',
259
+ 'time' => t,
260
+ 'acknowledgement_id' => '75',
261
+ 'duration' => 2400
262
+ }
263
+ end
264
+
265
+ it "returns its state" do
266
+ @redis.hset("check:#{name}:#{check}", 'state', 'ok')
267
+
268
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
269
+ state = ec.state
270
+ state.should_not be_nil
271
+ state.should == 'ok'
272
+ end
273
+
274
+ it "updates state" do
275
+ @redis.hset("check:#{name}:#{check}", 'state', 'ok')
276
+
277
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
278
+ ec.update_state('critical')
279
+
280
+ state = @redis.hget("check:#{name}:#{check}", 'state')
281
+ state.should_not be_nil
282
+ state.should == 'critical'
283
+ end
284
+
285
+ it "does not update state with invalid value" do
286
+ @redis.hset("check:#{name}:#{check}", 'state', 'ok')
287
+
288
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
289
+ ec.update_state('silly')
290
+
291
+ state = @redis.hget("check:#{name}:#{check}", 'state')
292
+ state.should_not be_nil
293
+ state.should == 'ok'
294
+ end
295
+
296
+ def time_before(t, min, sec = 0)
297
+ t - ((60 * min) + sec)
298
+ end
299
+
300
+ it "returns a list of historical states for a time range" do
301
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
302
+
303
+ t = Time.now.to_i
304
+ ec.update_state('ok', :timestamp => time_before(t, 5), :summary => 'a')
305
+ ec.update_state('critical', :timestamp => time_before(t, 4), :summary => 'b')
306
+ ec.update_state('ok', :timestamp => time_before(t, 3), :summary => 'c')
307
+ ec.update_state('critical', :timestamp => time_before(t, 2), :summary => 'd')
308
+ ec.update_state('ok', :timestamp => time_before(t, 1), :summary => 'e')
309
+
310
+ states = ec.historical_states(time_before(t, 4), t)
311
+ states.should_not be_nil
312
+ states.should be_an(Array)
313
+ states.should have(4).data_hashes
314
+ states[0][:summary].should == 'b'
315
+ states[1][:summary].should == 'c'
316
+ states[2][:summary].should == 'd'
317
+ states[3][:summary].should == 'e'
318
+ end
319
+
320
+ it "returns a list of historical unscheduled maintenances for a time range" do
321
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
322
+
323
+ t = Time.now.to_i
324
+ # ec.update_state('ok', :timestamp => time_before(t, 5), :summary => 'a')
325
+ # ec.update_state('critical', :timestamp => time_before(t, 4), :summary => 'b')
326
+ # ec.update_state('ok', :timestamp => time_before(t, 3), :summary => 'c')
327
+ # ec.update_state('critical', :timestamp => time_before(t, 2), :summary => 'd')
328
+ # ec.update_state('ok', :timestamp => time_before(t, 1), :summary => 'e')
329
+
330
+ # states = ec.historical_states(time_before(t, 4), t)
331
+ # states.should_not be_nil
332
+ # states.should be_an(Array)
333
+ # states.should have(4).data_hashes
334
+ # states[0][:summary].should == 'b'
335
+ # states[1][:summary].should == 'c'
336
+ # states[2][:summary].should == 'd'
337
+ # states[3][:summary].should == 'e'
338
+ end
339
+
340
+ it "returns a list of historical scheduled maintenances for a time range" do
341
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
342
+
343
+ t = Time.now.to_i
344
+
345
+ ec.create_scheduled_maintenance(:start_time => time_before(t, 180),
346
+ :duration => half_an_hour, :summary => "a")
347
+ ec.create_scheduled_maintenance(:start_time => time_before(t, 120),
348
+ :duration => half_an_hour, :summary => "b")
349
+ ec.create_scheduled_maintenance(:start_time => time_before(t, 60),
350
+ :duration => half_an_hour, :summary => "c")
351
+
352
+ sched_maint_periods = ec.maintenances(time_before(t, 150), t,
353
+ :scheduled => true)
354
+ sched_maint_periods.should_not be_nil
355
+ sched_maint_periods.should be_an(Array)
356
+ sched_maint_periods.should have(2).data_hashes
357
+ sched_maint_periods[0][:summary].should == 'b'
358
+ sched_maint_periods[1][:summary].should == 'c'
359
+ end
360
+
361
+ it "returns that it has failed" do
362
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
363
+
364
+ @redis.hset("check:#{name}:#{check}", 'state', 'warning')
365
+ ec.should be_failed
366
+
367
+ @redis.hset("check:#{name}:#{check}", 'state', 'critical')
368
+ ec.should be_failed
369
+ end
370
+
371
+ it "returns that it has not failed" do
372
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
373
+
374
+ @redis.hset("check:#{name}:#{check}", 'state', 'ok')
375
+ ec.should_not be_failed
376
+
377
+ @redis.hset("check:#{name}:#{check}", 'state', 'acknowledgement')
378
+ ec.should_not be_failed
379
+
380
+ @redis.hset("check:#{name}:#{check}", 'state', 'unknown')
381
+ ec.should_not be_failed
382
+ end
383
+
384
+ it "returns a status summary"
385
+
386
+ it "returns timestamps for its last notifications" do
387
+ t = Time.now.to_i
388
+ @redis.set("#{name}:#{check}:last_problem_notification", t - 30)
389
+ @redis.set("#{name}:#{check}:last_acknowledgement_notification", t - 15)
390
+ @redis.set("#{name}:#{check}:last_recovery_notification", t)
391
+
392
+ ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
393
+ ec.last_problem_notification.should == t - 30
394
+ ec.last_acknowledgement_notification.should == t - 15
395
+ ec.last_recovery_notification.should == t
396
+ end
397
+
398
+ end