flapjack 0.4.12 → 0.5.1

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 (55) hide show
  1. data/README.md +77 -50
  2. data/Rakefile +78 -26
  3. data/TODO.md +15 -32
  4. data/bin/flapjack-benchmark +50 -0
  5. data/bin/flapjack-notifier +11 -36
  6. data/bin/flapjack-notifier-manager +1 -3
  7. data/bin/flapjack-worker +5 -19
  8. data/doc/PACKAGING.md +25 -0
  9. data/etc/flapjack/flapjack-notifier.conf.example +34 -0
  10. data/etc/flapjack/recipients.conf.example +14 -0
  11. data/features/flapjack-notifier-manager.feature +19 -0
  12. data/features/flapjack-worker-manager.feature +25 -0
  13. data/features/packaging-lintian.feature +15 -0
  14. data/features/persistence/couch.feature +105 -0
  15. data/features/persistence/sqlite3.feature +105 -0
  16. data/features/persistence/steps/couch_steps.rb +25 -0
  17. data/features/persistence/steps/generic_steps.rb +102 -0
  18. data/features/persistence/steps/sqlite3_steps.rb +13 -0
  19. data/features/steps/flapjack-notifier-manager_steps.rb +24 -0
  20. data/features/steps/flapjack-worker-manager_steps.rb +50 -0
  21. data/features/steps/packaging-lintian_steps.rb +13 -0
  22. data/features/support/env.rb +22 -0
  23. data/features/support/silent_system.rb +4 -0
  24. data/flapjack.gemspec +7 -11
  25. data/lib/flapjack/applications/notifier.rb +222 -0
  26. data/lib/flapjack/applications/worker.rb +99 -0
  27. data/lib/flapjack/checks/ping +10 -0
  28. data/lib/flapjack/cli/notifier.rb +80 -218
  29. data/lib/flapjack/cli/worker.rb +1 -86
  30. data/lib/flapjack/filters/any_parents_failed.rb +14 -0
  31. data/lib/flapjack/filters/ok.rb +13 -0
  32. data/lib/flapjack/inifile.rb +44 -0
  33. data/lib/flapjack/{notifier.rb → notifier_engine.rb} +13 -9
  34. data/lib/flapjack/notifiers/mailer/mailer.rb +12 -13
  35. data/lib/flapjack/notifiers/xmpp/xmpp.rb +2 -2
  36. data/lib/flapjack/patches.rb +25 -0
  37. data/lib/flapjack/persistence/couch.rb +5 -0
  38. data/lib/flapjack/persistence/couch/connection.rb +66 -0
  39. data/lib/flapjack/persistence/couch/couch.rb +63 -0
  40. data/lib/flapjack/persistence/data_mapper.rb +3 -0
  41. data/lib/flapjack/persistence/data_mapper/data_mapper.rb +67 -0
  42. data/lib/flapjack/{models → persistence/data_mapper/models}/check.rb +3 -7
  43. data/lib/flapjack/{models → persistence/data_mapper/models}/check_template.rb +0 -0
  44. data/lib/flapjack/persistence/data_mapper/models/event.rb +17 -0
  45. data/lib/flapjack/{models → persistence/data_mapper/models}/node.rb +0 -0
  46. data/lib/flapjack/{models → persistence/data_mapper/models}/related_check.rb +0 -0
  47. data/lib/flapjack/persistence/sqlite3.rb +3 -0
  48. data/lib/flapjack/persistence/sqlite3/sqlite3.rb +166 -0
  49. data/lib/flapjack/transports/beanstalkd.rb +33 -0
  50. data/lib/flapjack/transports/result.rb +58 -0
  51. metadata +46 -56
  52. data/etc/flapjack/flapjack-notifier.yaml.example +0 -8
  53. data/etc/flapjack/recipients.yaml.example +0 -10
  54. data/lib/flapjack/database.rb +0 -10
  55. data/lib/flapjack/result.rb +0 -47
@@ -31,9 +31,7 @@ end
31
31
  daemon_args = args
32
32
  if args.first != "stop"
33
33
  # if we're not stopping the daemon, pass options to it
34
- daemon_args += ['--', '--beanstalk', options.host,
35
- '--port', options.port.to_s,
36
- '--recipients', options.recipients,
34
+ daemon_args += ['--', '--recipients', options.recipients,
37
35
  '--config', File.expand_path(options.config_filename)]
38
36
  end
39
37
 
data/bin/flapjack-worker CHANGED
@@ -2,10 +2,8 @@
2
2
 
3
3
  $: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
4
4
 
5
- require 'rubygems'
6
- require 'log4r'
7
- require 'log4r/outputter/syslogoutputter'
8
5
  require 'flapjack/cli/worker'
6
+ require 'flapjack/applications/worker'
9
7
 
10
8
  at_exit do
11
9
  puts "Shutting down"
@@ -17,20 +15,8 @@ trap("INT") do
17
15
  end
18
16
 
19
17
  @options = Flapjack::WorkerOptions.parse(ARGV)
20
- @worker = Flapjack::Worker.new(:host => @options.host,
21
- :port => @options.port,
22
- :checks_directory => @options.check_directory)
23
-
24
- begin
25
- @worker.process_loop
26
- rescue Beanstalk::NotConnected
27
- puts "Couldn't connect to the beanstalk!"
28
-
29
- timeout = 5
30
- puts "Retrying in #{timeout} seconds"
31
- sleep timeout
32
-
33
- puts "Retrying..."
34
- retry
35
- end
18
+ app = Flapjack::Worker::Application.run(:host => @options.host,
19
+ :port => @options.port,
20
+ :check_directory => @options.check_directory)
21
+ app.main
36
22
 
data/doc/PACKAGING.md ADDED
@@ -0,0 +1,25 @@
1
+ Debian / Ubuntu
2
+ ===============
3
+
4
+ Packaged dependencies:
5
+
6
+ * libdaemons-ruby
7
+ * liblog4r-ruby
8
+ * libxmpp4r-ruby
9
+ * libtmail-ruby
10
+
11
+ Unpackaged dependencies:
12
+
13
+ * beanstalkd-client (libbeanstalkd-ruby)
14
+ * dm-core
15
+ * dm-timestamps
16
+ * dm-types
17
+ * dm-validations
18
+ * data_objects
19
+ * do_sqlite3
20
+ * do_mysql
21
+
22
+ The unpackaged dependencies need to be packaged to make Flapjack packagable.
23
+
24
+ Current development efforts are working towards abstracting the
25
+ DataMapper/DataObjects dependency so packaging isn't a complete travesty.
@@ -0,0 +1,34 @@
1
+ # top level
2
+ [notifier]
3
+ notifier-directories = /usr/lib/flapjack/notifiers/ /path/to/my/notifiers
4
+ notifiers = mailer, xmpp
5
+
6
+ # persistence layers
7
+ [persistence]
8
+ backend = data_mapper
9
+ uri = sqlite3:///tmp/flapjack.db
10
+
11
+ # couchdb backend
12
+ #[persistence]
13
+ # backend = couchdb
14
+ # version = 0.8
15
+ # host = localhost
16
+ # port = 5984
17
+ # database = flapjack_production
18
+
19
+ # message transports
20
+ [transport]
21
+ backend = beanstalkd
22
+ host = localhost
23
+ port = 11300
24
+
25
+ # notifiers
26
+ [mailer-notifier]
27
+ from_address = foo@bar.com
28
+
29
+ [xmpp-notifier]
30
+ jid = foo@bar.com
31
+ password = barfoo
32
+
33
+
34
+
@@ -0,0 +1,14 @@
1
+ # example recipients.conf
2
+
3
+ [John Doe]
4
+ email = johndoe@example.org
5
+ jid = john@example.org
6
+ phone = +61 400 111 222
7
+ pager = 61400111222
8
+
9
+ [Jane Doe]
10
+ email = janedoe@example.org
11
+ jid = jane@example.org
12
+ phone = +61 222 333 111
13
+ pager = 61222333111
14
+
@@ -0,0 +1,19 @@
1
+ Feature: flapjack-notifier-manager
2
+ So people can be notified when things break
3
+ A notifier must be started
4
+ Through an easy to use command line tool
5
+
6
+ Scenario: Starting the notifier
7
+ Given the flapjack-notifier-manager is on my path
8
+ And the "/var/run/flapjack" directory exists and is writable
9
+ And beanstalkd is running on localhost
10
+ And there are no instances of flapjack-notifier running
11
+ When I run "flapjack-notifier-manager start --recipients spec/configs/recipients.ini --config spec/configs/flapjack-notifier.ini"
12
+ Then 1 instances of "flapjack-notifier" should be running
13
+
14
+ Scenario: Stopping the notifier
15
+ Given there is an instance of the flapjack-notifier running
16
+ And beanstalkd is running on localhost
17
+ When I run "flapjack-notifier-manager stop"
18
+ Then 0 instances of "flapjack-notifier" should be running
19
+
@@ -0,0 +1,25 @@
1
+ Feature: flapjack-notifier-manager
2
+ To scale Flapjack easily and efficiently
3
+ A sysadmin
4
+ Must be able to manage clusters of workers
5
+
6
+ Scenario: Running multiple workers
7
+ Given the flapjack-worker-manager is on my path
8
+ And beanstalkd is running on localhost
9
+ And there are no instances of flapjack-worker running
10
+ When I run "flapjack-worker-manager start"
11
+ Then 5 instances of "flapjack-worker" should be running
12
+
13
+ Scenario: Running a specified number of workers
14
+ Given the flapjack-worker-manager is on my path
15
+ And beanstalkd is running on localhost
16
+ And there are no instances of flapjack-worker running
17
+ When I run "flapjack-worker-manager start --workers=10"
18
+ Then 10 instances of "flapjack-worker" should be running
19
+
20
+ Scenario: Stopping all workers
21
+ Given there are 5 instances of the flapjack-worker running
22
+ And beanstalkd is running on localhost
23
+ When I run "flapjack-worker-manager stop"
24
+ Then 0 instances of "flapjack-worker" should be running
25
+
@@ -0,0 +1,15 @@
1
+ Feature: Packagability
2
+ To make Flapjack usable to the masses
3
+ It must be easily packagable
4
+
5
+ Scenario: No rubygems references
6
+ Given I am at the project root
7
+ When I run "grep require lib/* bin/* -R |grep rubygems"
8
+ Then I should see 0 lines of output
9
+
10
+ Scenario: A shebang that works everywhere
11
+ Given I am at the project root
12
+ When I run "find lib/ -type 'f' -name '*.rb'"
13
+ Then every file in the output should start with "#!/usr/bin/env ruby"
14
+
15
+
@@ -0,0 +1,105 @@
1
+ Feature: CouchDB persistence backend
2
+ To use a CouchDB backend with Flapjack
3
+ The backend must conform
4
+ To the persistence API
5
+
6
+ Background:
7
+ Given I set up the Couch backend with the following options:
8
+ | host | port | database |
9
+ | localhost | 5984 | flapjack_test |
10
+
11
+ Scenario: Create a check
12
+ When I create the following checks:
13
+ | name | id | command | status | enabled |
14
+ | passing | 1 | exit 0 | 0 | true |
15
+ | warning | 2 | exit 1 | 1 | true |
16
+ | critical | 3 | exit 2 | 2 | true |
17
+ Then looking up the following checks should return documents:
18
+ | id |
19
+ | 1 |
20
+ | 2 |
21
+ | 3 |
22
+
23
+ Scenario: Update a check
24
+ Given the following checks exist:
25
+ | name | id | command | status | enabled |
26
+ | passing | 4 | exit 0 | 0 | true |
27
+ When I update the following checks:
28
+ | name | id | command | status | enabled |
29
+ | passing | 4 | exit 2 | 2 | true |
30
+ Then the updates should succeed
31
+
32
+ Scenario: Delete a check
33
+ Given the following checks exist:
34
+ | name | id | command | status | enabled |
35
+ | passing | 5 | exit 0 | 0 | true |
36
+ When I delete the check with id "4"
37
+ Then the check with id "4" should not exist
38
+
39
+ Scenario: List all checks
40
+ Given the following checks exist:
41
+ | name | id | command | status | enabled |
42
+ | passing | 6 | exit 0 | 0 | true |
43
+ | warning | 7 | exit 1 | 1 | true |
44
+ | critical | 8 | exit 2 | 2 | true |
45
+ When I get all checks
46
+ Then I should have at least 3 checks
47
+
48
+ Scenario: Query for failing parents
49
+ Given the following checks exist:
50
+ | name | id | command | status | enabled |
51
+ | failing parent | 1 | exit 2 | 2 | true |
52
+ | passing child | 2 | exit 0 | 0 | true |
53
+ And the following related checks exist:
54
+ | id | parent_id | child_id |
55
+ | 1 | 1 | 2 |
56
+ Then the following result should not have a failing parent:
57
+ | check_id |
58
+ | 1 |
59
+ Then the following result should have a failing parent:
60
+ | check_id |
61
+ | 2 |
62
+
63
+ Scenario: Saving events
64
+ Given the following checks exist:
65
+ | name | id | command | status | enabled |
66
+ | failing parent | 4 | exit 2 | 4 | true |
67
+ Then the following event should save:
68
+ | check_id | status |
69
+ | 4 | 2 |
70
+ And the check with id "4" on the Sqlite3 backend should have an event created
71
+
72
+ Scenario: List events for a check
73
+ Given the following checks exist:
74
+ | name | id | command | status | enabled |
75
+ | passing child | 12 | exit 2 | 3 | true |
76
+ Given the following events exist:
77
+ | check_id |
78
+ | 12 |
79
+ | 12 |
80
+ | 12 |
81
+ When I get all events for check "12"
82
+ Then I should have at least 3 events
83
+
84
+ Scenario: List all events
85
+ Given the following events exist:
86
+ | check_id |
87
+ | 9 |
88
+ | 10 |
89
+ | 11 |
90
+ When I get all events
91
+ Then I should have at least 3 events
92
+
93
+ Scenario: List all check relationships
94
+ Given the following checks exist:
95
+ | name | id | command | status | enabled |
96
+ | passing | 9 | exit 0 | 0 | true |
97
+ | warning | 10 | exit 1 | 1 | true |
98
+ | critical | 11 | exit 2 | 2 | true |
99
+ And the following related checks exist:
100
+ | parent_id | child_id |
101
+ | 9 | 10 |
102
+ | 10 | 11 |
103
+ | 11 | 9 |
104
+ When I get all check relationships
105
+ Then I should have at least 3 check relationships
@@ -0,0 +1,105 @@
1
+ Feature: SQLite3 persistence backend
2
+ To use a SQLite3 backend with Flapjack
3
+ The backend must conform
4
+ To the persistence API
5
+
6
+ Background:
7
+ Given I set up the Sqlite3 backend with the following options:
8
+ | database | auto_migrate |
9
+ | :memory: | true |
10
+
11
+ Scenario: Create a check
12
+ When I create the following checks:
13
+ | name | id | command | status | enabled |
14
+ | passing | 1 | exit 0 | 0 | true |
15
+ | warning | 2 | exit 1 | 1 | true |
16
+ | critical | 3 | exit 2 | 2 | true |
17
+ Then looking up the following checks should return documents:
18
+ | id |
19
+ | 1 |
20
+ | 2 |
21
+ | 3 |
22
+
23
+ Scenario: Update a check
24
+ Given the following checks exist:
25
+ | name | id | command | status | enabled |
26
+ | passing | 4 | exit 0 | 0 | true |
27
+ When I update the following checks:
28
+ | name | id | command | status | enabled |
29
+ | passing | 4 | exit 2 | 2 | true |
30
+ Then the updates should succeed
31
+
32
+ Scenario: Delete a check
33
+ Given the following checks exist:
34
+ | name | id | command | status | enabled |
35
+ | passing | 5 | exit 0 | 0 | true |
36
+ When I delete the check with id "4"
37
+ Then the check with id "4" should not exist
38
+
39
+ Scenario: List all checks
40
+ Given the following checks exist:
41
+ | name | id | command | status | enabled |
42
+ | passing | 6 | exit 0 | 0 | true |
43
+ | warning | 7 | exit 1 | 1 | true |
44
+ | critical | 8 | exit 2 | 2 | true |
45
+ When I get all checks
46
+ Then I should have at least 3 checks
47
+
48
+ Scenario: Query for failing parents
49
+ Given the following checks exist:
50
+ | name | id | command | status | enabled |
51
+ | failing parent | 1 | exit 2 | 2 | true |
52
+ | passing child | 2 | exit 0 | 0 | true |
53
+ And the following related checks exist:
54
+ | id | parent_id | child_id |
55
+ | 1 | 1 | 2 |
56
+ Then the following result should not have a failing parent:
57
+ | check_id |
58
+ | 1 |
59
+ Then the following result should have a failing parent:
60
+ | check_id |
61
+ | 2 |
62
+
63
+ Scenario: Saving events
64
+ Given the following checks exist:
65
+ | name | id | command | status | enabled |
66
+ | failing parent | 4 | exit 2 | 4 | true |
67
+ Then the following event should save:
68
+ | check_id | status |
69
+ | 4 | 2 |
70
+ And the check with id "4" on the Sqlite3 backend should have an event created
71
+
72
+ Scenario: List events for a check
73
+ Given the following checks exist:
74
+ | name | id | command | status | enabled |
75
+ | passing child | 12 | exit 2 | 3 | true |
76
+ Given the following events exist:
77
+ | check_id |
78
+ | 12 |
79
+ | 12 |
80
+ | 12 |
81
+ When I get all events for check "12"
82
+ Then I should have at least 3 events
83
+
84
+ Scenario: List all events
85
+ Given the following events exist:
86
+ | check_id |
87
+ | 9 |
88
+ | 10 |
89
+ | 11 |
90
+ When I get all events
91
+ Then I should have at least 3 events
92
+
93
+ Scenario: List all check relationships
94
+ Given the following checks exist:
95
+ | name | id | command | status | enabled |
96
+ | passing | 9 | exit 0 | 0 | true |
97
+ | warning | 10 | exit 1 | 1 | true |
98
+ | critical | 11 | exit 2 | 2 | true |
99
+ And the following related checks exist:
100
+ | parent_id | child_id |
101
+ | 9 | 10 |
102
+ | 10 | 11 |
103
+ | 11 | 9 |
104
+ When I get all check relationships
105
+ Then I should have at least 3 check relationships
@@ -0,0 +1,25 @@
1
+ Given /^I set up the Couch backend with the following options:$/ do |table|
2
+ @backend_options = table.hashes.first.symbolize_keys
3
+ uri = "/#{@backend_options[:database]}/"
4
+ request = ::Net::HTTP::Put.new(uri)
5
+ response = ::Net::HTTP.start(@backend_options[:host], @backend_options[:port]) {|http| http.request(request)}
6
+
7
+ @backend = Flapjack::Persistence::Couch.new(@backend_options)
8
+
9
+ uri = "/#{@backend_options[:database]}/_all_docs"
10
+ request = ::Net::HTTP::Get.new(uri)
11
+ response = ::Net::HTTP.start(@backend_options[:host], @backend_options[:port]) {|http| http.request(request)}
12
+
13
+ parser = Yajl::Parser.new
14
+ doc = parser.parse(response.body)
15
+ doc["rows"].each do |row|
16
+ uri = "/#{@backend_options[:database]}/#{row["id"]}?rev=#{row["value"]["rev"]}"
17
+ request = ::Net::HTTP::Delete.new(uri)
18
+ response = ::Net::HTTP.start(@backend_options[:host], @backend_options[:port]) {|http| http.request(request)}
19
+ end
20
+ end
21
+
22
+ Then /^the check with id "([^\"]*)" on the Couch backend should have a status of "([^\"]*)"$/ do |arg1, arg2|
23
+ pending # express the regexp above with the code you wish you had
24
+ end
25
+
@@ -0,0 +1,102 @@
1
+ When /^I create the following checks:$/ do |table|
2
+ table.hashes.each do |attrs|
3
+ @backend.save_check(attrs.symbolize_keys).should be_true
4
+ end
5
+ end
6
+
7
+ Then /^looking up the following checks should return documents:$/ do |table|
8
+ table.hashes.each do |attrs|
9
+ @backend.get_check(attrs['id']).should_not be_nil
10
+ end
11
+ end
12
+
13
+ When /^I update the following checks:$/ do |table|
14
+ table.hashes.each do |attrs|
15
+ @backend.save_check(attrs.symbolize_keys).should be_true
16
+ end
17
+ end
18
+
19
+ Then /^the updates should succeed$/ do
20
+ # matches on "should be_true" above
21
+ end
22
+
23
+ When /^I delete the check with id "([^\"]*)"$/ do |id|
24
+ @backend.delete_check(id).should be_true
25
+ end
26
+
27
+ Then /^the check with id "([^\"]*)" should not exist$/ do |id|
28
+ @backend.get_check(id).should be_nil
29
+ end
30
+
31
+ When /^I get all checks$/ do
32
+ @checks = @backend.all_checks
33
+ end
34
+
35
+ Then /^I should have at least (\d+) checks$/ do |n|
36
+ @checks.size.should >= n.to_i
37
+ end
38
+
39
+ Given /^the following checks exist:$/ do |table|
40
+ table.hashes.each do |attrs|
41
+ @backend.save_check(attrs.symbolize_keys)
42
+ end
43
+ end
44
+
45
+ Then /^the following results should save:$/ do |table|
46
+ table.hashes.each do |attrs|
47
+ @backend.save_check(attrs.symbolize_keys).should be_true
48
+ end
49
+ end
50
+
51
+ Given /^the following related checks exist:$/ do |table|
52
+ table.hashes.each do |attrs|
53
+ @backend.save_check_relationship(attrs).should be_true
54
+ end
55
+ end
56
+
57
+ Then /^the following result should not have a failing parent:$/ do |table|
58
+ table.hashes.each do |attrs|
59
+ @backend.any_parents_failed?(attrs['check_id']).should be_false
60
+ end
61
+ end
62
+
63
+ Then /^the following result should have a failing parent:$/ do |table|
64
+ table.hashes.each do |attrs|
65
+ @backend.any_parents_failed?(attrs['check_id']).should be_true
66
+ end
67
+ end
68
+
69
+ Then /^the following event should save:$/ do |table|
70
+ table.hashes.each do |attrs|
71
+ result = Flapjack::Transport::Result.new(:result => attrs.symbolize_keys)
72
+ @backend.create_event(result).should be_true
73
+ end
74
+ end
75
+
76
+
77
+ When /^I get all check relationships$/ do
78
+ @relationships = @backend.all_check_relationships
79
+ end
80
+
81
+ Then /^I should have at least (\d+) check relationships$/ do |n|
82
+ @relationships.size.should >= n.to_i
83
+ end
84
+
85
+ Given /^the following events exist:$/ do |table|
86
+ table.hashes.each do |attrs|
87
+ result = Flapjack::Transport::Result.new(:result => attrs.symbolize_keys)
88
+ @backend.create_event(result).should be_true
89
+ end
90
+ end
91
+
92
+ When /^I get all events$/ do
93
+ @events = @backend.all_events
94
+ end
95
+
96
+ Then /^I should have at least (\d+) events$/ do |n|
97
+ @events.size.should >= n.to_i
98
+ end
99
+
100
+ When /^I get all events for check "([^\"]*)"$/ do |id|
101
+ @events = @backend.all_events_for(id)
102
+ end