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.
- data/.gitignore +10 -0
- data/.rbenv-version +1 -0
- data/.rspec +10 -0
- data/Gemfile +18 -0
- data/Guardfile +14 -0
- data/README.md +152 -173
- data/Rakefile +53 -150
- data/bin/flapjack +72 -0
- data/bin/flapjack-nagios-receiver +111 -0
- data/bin/flapjack-nagios-receiver-control +15 -0
- data/bin/flapjack-netsaint-parser +0 -2
- data/bin/flapjack-populator +133 -16
- data/bin/install-flapjack-systemwide +2 -2
- data/config.ru +11 -0
- data/dist/etc/init.d/flapjack +46 -0
- data/dist/etc/init.d/flapjack-nagios-receiver +36 -0
- data/doc/GLOSSARY.md +19 -0
- data/etc/flapjack_config.yaml.example +90 -0
- data/features/events.feature +132 -0
- data/features/notifications.feature +57 -0
- data/features/packaging-lintian.feature +5 -3
- data/features/steps/events_steps.rb +164 -0
- data/features/steps/flapjack-importer_steps.rb +2 -5
- data/features/steps/flapjack-worker_steps.rb +13 -6
- data/features/steps/notifications_steps.rb +178 -0
- data/features/steps/packaging-lintian_steps.rb +14 -0
- data/features/steps/time_travel_steps.rb +34 -0
- data/features/support/env.rb +63 -36
- data/flapjack.gemspec +35 -186
- data/lib/flapjack.rb +2 -0
- data/lib/flapjack/api.rb +274 -0
- data/lib/flapjack/api/entity_check_presenter.rb +184 -0
- data/lib/flapjack/api/entity_presenter.rb +66 -0
- data/lib/flapjack/cli/worker_manager.rb +1 -2
- data/lib/flapjack/configuration.rb +11 -0
- data/lib/flapjack/coordinator.rb +288 -0
- data/lib/flapjack/daemonizing.rb +186 -0
- data/lib/flapjack/data/contact.rb +45 -0
- data/lib/flapjack/data/entity.rb +89 -0
- data/lib/flapjack/data/entity_check.rb +396 -0
- data/lib/flapjack/data/event.rb +144 -0
- data/lib/flapjack/data/notification.rb +13 -0
- data/lib/flapjack/executive.rb +289 -0
- data/lib/flapjack/filters/acknowledgement.rb +39 -0
- data/lib/flapjack/filters/{any_parents_failed.rb → base.rb} +6 -4
- data/lib/flapjack/filters/delays.rb +53 -0
- data/lib/flapjack/filters/detect_mass_client_failures.rb +44 -0
- data/lib/flapjack/filters/ok.rb +25 -5
- data/lib/flapjack/filters/scheduled_maintenance.rb +17 -0
- data/lib/flapjack/filters/unscheduled_maintenance.rb +17 -0
- data/lib/flapjack/jabber.rb +294 -0
- data/lib/flapjack/notification/common.rb +23 -0
- data/lib/flapjack/notification/email.rb +107 -0
- data/lib/flapjack/notification/email/alert.html.haml +48 -0
- data/lib/flapjack/notification/email/alert.text.erb +14 -0
- data/lib/flapjack/notification/sms.rb +42 -0
- data/lib/flapjack/notification/sms/messagenet.rb +49 -0
- data/lib/flapjack/notifier_engine.rb +4 -4
- data/lib/flapjack/notifiers/mailer/mailer.rb +6 -7
- data/lib/flapjack/notifiers/xmpp/xmpp.rb +12 -12
- data/lib/flapjack/pagerduty.rb +230 -0
- data/lib/flapjack/patches.rb +108 -19
- data/lib/flapjack/persistence/data_mapper/models/check.rb +5 -3
- data/lib/flapjack/persistence/data_mapper/models/check_template.rb +2 -0
- data/lib/flapjack/persistence/data_mapper/models/event.rb +2 -0
- data/lib/flapjack/persistence/data_mapper/models/node.rb +3 -1
- data/lib/flapjack/persistence/data_mapper/models/related_check.rb +3 -1
- data/lib/flapjack/pikelet.rb +56 -0
- data/lib/flapjack/transports/beanstalkd.rb +1 -1
- data/lib/flapjack/transports/result.rb +6 -6
- data/lib/flapjack/utility.rb +46 -0
- data/lib/flapjack/version.rb +5 -0
- data/lib/flapjack/web.rb +198 -0
- data/lib/flapjack/web/views/acknowledge.haml +55 -0
- data/lib/flapjack/web/views/check.haml +162 -0
- data/lib/flapjack/web/views/index.haml +92 -0
- data/lib/flapjack/web/views/self_stats.haml +56 -0
- data/lib/flapjack/{applications/worker.rb → worker/application.rb} +0 -0
- data/lib/flapjack/worker/cli.rb +49 -0
- data/{spec → spec.old}/check_sandbox/echo +0 -0
- data/{spec → spec.old}/check_sandbox/sandboxed_check +0 -0
- data/{spec → spec.old}/configs/flapjack-notifier-couchdb.ini +0 -0
- data/{spec → spec.old}/configs/flapjack-notifier.ini +0 -0
- data/{spec → spec.old}/configs/recipients.ini +0 -0
- data/{spec → spec.old}/helpers.rb +0 -0
- data/{spec → spec.old}/inifile_spec.rb +0 -0
- data/{spec → spec.old}/mock-notifiers/mock/init.rb +0 -0
- data/{spec → spec.old}/mock-notifiers/mock/mock.rb +0 -0
- data/{spec → spec.old}/notifier-directories/spoons/testmailer/init.rb +0 -0
- data/{spec → spec.old}/notifier_application_spec.rb +0 -0
- data/{spec → spec.old}/notifier_filters_spec.rb +0 -0
- data/{spec → spec.old}/notifier_options_multiplexer_spec.rb +0 -0
- data/{spec → spec.old}/notifier_options_spec.rb +0 -0
- data/{spec → spec.old}/notifier_spec.rb +0 -0
- data/{spec → spec.old}/notifiers/mailer_spec.rb +0 -0
- data/{spec → spec.old}/notifiers/xmpp_spec.rb +0 -0
- data/{spec → spec.old}/persistence/datamapper_spec.rb +0 -0
- data/{spec → spec.old}/persistence/mock_persistence_backend.rb +0 -0
- data/{spec → spec.old}/simple.ini +0 -0
- data/{spec → spec.old}/spec.opts +0 -0
- data/{spec → spec.old}/test-filters/blocker.rb +0 -0
- data/{spec → spec.old}/test-filters/mock.rb +0 -0
- data/{spec → spec.old}/transports/beanstalkd_spec.rb +0 -0
- data/{spec → spec.old}/transports/mock_transport.rb +0 -0
- data/{spec → spec.old}/worker_application_spec.rb +0 -0
- data/{spec → spec.old}/worker_options_spec.rb +0 -0
- data/spec/lib/flapjack/api/entity_check_presenter_spec.rb +117 -0
- data/spec/lib/flapjack/api/entity_presenter_spec.rb +92 -0
- data/spec/lib/flapjack/api_spec.rb +170 -0
- data/spec/lib/flapjack/coordinator_spec.rb +16 -0
- data/spec/lib/flapjack/data/entity_check_spec.rb +398 -0
- data/spec/lib/flapjack/data/entity_spec.rb +71 -0
- data/spec/lib/flapjack/data/event_spec.rb +6 -0
- data/spec/lib/flapjack/executive_spec.rb +59 -0
- data/spec/lib/flapjack/filters/acknowledgement_spec.rb +6 -0
- data/spec/lib/flapjack/filters/delays_spec.rb +6 -0
- data/spec/lib/flapjack/filters/detect_mass_client_failures_spec.rb +6 -0
- data/spec/lib/flapjack/filters/ok_spec.rb +6 -0
- data/spec/lib/flapjack/filters/scheduled_maintenance_spec.rb +6 -0
- data/spec/lib/flapjack/filters/unscheduled_maintenance_spec.rb +6 -0
- data/spec/lib/flapjack/jabber_spec.rb +150 -0
- data/spec/lib/flapjack/notification/email_spec.rb +6 -0
- data/spec/lib/flapjack/notification/sms_spec.rb +6 -0
- data/spec/lib/flapjack/pikelet_spec.rb +28 -0
- data/spec/lib/flapjack/web_spec.rb +188 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/profile_all_formatter.rb +44 -0
- data/spec/support/uncolored_doc_formatter.rb +9 -0
- data/tasks/events.rake +85 -0
- data/tmp/acknowledge.rb +14 -0
- data/tmp/create_config_yaml.rb +16 -0
- data/tmp/create_events_failure.rb +33 -0
- data/tmp/create_events_ok.rb +33 -0
- data/tmp/create_events_ok_fail_ack_ok.rb +54 -0
- data/tmp/create_events_ok_failure.rb +40 -0
- data/tmp/create_events_ok_failure_ack.rb +54 -0
- data/tmp/dummy_entities.json +1 -0
- data/tmp/generate_nagios_test_hosts.rb +16 -0
- data/tmp/parse_config_yaml.rb +7 -0
- data/tmp/redis_delete_all_keys.rb +11 -0
- data/tmp/test_entities.json +1 -0
- metadata +482 -221
- data/TODO.md +0 -36
- data/VERSION +0 -1
- data/bin/flapjack-benchmark +0 -50
- data/bin/flapjack-notifier +0 -21
- data/bin/flapjack-notifier-manager +0 -43
- data/bin/flapjack-stats +0 -27
- data/bin/flapjack-worker +0 -13
- data/bin/flapjack-worker-manager +0 -35
- data/dist/etc/init.d/flapjack-notifier +0 -47
- data/dist/etc/init.d/flapjack-workers +0 -44
- data/features/flapjack-notifier-manager.feature +0 -19
- data/features/flapjack-worker-manager.feature +0 -27
- data/features/flapjack-worker.feature +0 -27
- data/features/netsaint-config-converter.feature +0 -126
- data/features/persistence/couch.feature +0 -105
- data/features/persistence/sqlite3.feature +0 -105
- data/features/persistence/steps/couch_steps.rb +0 -25
- data/features/persistence/steps/generic_steps.rb +0 -102
- data/features/persistence/steps/sqlite3_steps.rb +0 -13
- data/features/steps/flapjack-notifier-manager_steps.rb +0 -24
- data/features/steps/flapjack-worker-manager_steps.rb +0 -48
- data/lib/flapjack/applications/notifier.rb +0 -222
- data/lib/flapjack/cli/notifier.rb +0 -108
- data/lib/flapjack/cli/notifier_manager.rb +0 -86
- 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,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,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,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
|