flapjack 0.5.1 → 0.5.3

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/.gitignore +16 -0
  2. data/Rakefile +72 -32
  3. data/VERSION +1 -0
  4. data/bin/flapjack-netsaint-parser +433 -0
  5. data/bin/flapjack-populator +29 -0
  6. data/bin/flapjack-stats +10 -5
  7. data/{etc → dist/etc}/default/flapjack-notifier +0 -0
  8. data/{etc → dist/etc}/default/flapjack-workers +0 -0
  9. data/{etc → dist/etc}/flapjack/flapjack-notifier.conf.example +0 -0
  10. data/{etc → dist/etc}/flapjack/recipients.conf.example +0 -0
  11. data/{etc → dist/etc}/init.d/flapjack-notifier +0 -0
  12. data/{etc → dist/etc}/init.d/flapjack-workers +7 -7
  13. data/dist/puppet/flapjack/files/.stub +0 -0
  14. data/dist/puppet/flapjack/manifests/common.pp +61 -0
  15. data/dist/puppet/flapjack/manifests/notifier.pp +13 -0
  16. data/dist/puppet/flapjack/manifests/worker.pp +13 -0
  17. data/dist/puppet/flapjack/templates/.stub +0 -0
  18. data/dist/puppet/ruby/manifests/dev.pp +5 -0
  19. data/dist/puppet/ruby/manifests/rubygems.pp +14 -0
  20. data/dist/puppet/sqlite3/manifests/dev.pp +5 -0
  21. data/features/netsaint-config-converter.feature +126 -0
  22. data/features/steps/flapjack-importer_steps.rb +112 -0
  23. data/features/steps/flapjack-netsaint-parser_steps.rb +51 -0
  24. data/features/steps/flapjack-worker-manager_steps.rb +6 -8
  25. data/features/support/env.rb +22 -19
  26. data/flapjack.gemspec +186 -23
  27. data/lib/flapjack.rb +4 -0
  28. data/spec/check_sandbox/echo +3 -0
  29. data/spec/check_sandbox/sandboxed_check +5 -0
  30. data/spec/configs/flapjack-notifier-couchdb.ini +25 -0
  31. data/spec/configs/flapjack-notifier.ini +39 -0
  32. data/spec/configs/recipients.ini +14 -0
  33. data/spec/helpers.rb +15 -0
  34. data/spec/inifile_spec.rb +66 -0
  35. data/spec/mock-notifiers/mock/init.rb +3 -0
  36. data/spec/mock-notifiers/mock/mock.rb +19 -0
  37. data/spec/notifier-directories/spoons/testmailer/init.rb +20 -0
  38. data/spec/notifier_application_spec.rb +222 -0
  39. data/spec/notifier_filters_spec.rb +52 -0
  40. data/spec/notifier_options_multiplexer_spec.rb +71 -0
  41. data/spec/notifier_options_spec.rb +115 -0
  42. data/spec/notifier_spec.rb +57 -0
  43. data/spec/notifiers/mailer_spec.rb +36 -0
  44. data/spec/notifiers/xmpp_spec.rb +36 -0
  45. data/spec/persistence/datamapper_spec.rb +74 -0
  46. data/spec/persistence/mock_persistence_backend.rb +26 -0
  47. data/spec/simple.ini +6 -0
  48. data/spec/spec.opts +4 -0
  49. data/spec/test-filters/blocker.rb +13 -0
  50. data/spec/test-filters/mock.rb +13 -0
  51. data/spec/transports/beanstalkd_spec.rb +44 -0
  52. data/spec/transports/mock_transport.rb +58 -0
  53. data/spec/worker_application_spec.rb +62 -0
  54. data/spec/worker_options_spec.rb +83 -0
  55. metadata +166 -47
@@ -0,0 +1,115 @@
1
+ ##!/usr/bin/env ruby
2
+ ##
3
+ #require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'cli', 'notifier')
4
+ #
5
+ #describe Flapjack::Notifier::Options do
6
+ #
7
+ # # beanstalk
8
+ # it "should accept the location of a beanstalk queue in short form" do
9
+ # args = %w(-b localhost -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
10
+ # options = Flapjack::Notifier::Options.parse(args)
11
+ # options.host.should == "localhost"
12
+ # end
13
+ #
14
+ # it "should accept the location of a beanstalk queue in long form" do
15
+ # args = %w(--beanstalk localhost -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
16
+ # options = Flapjack::Notifier::Options.parse(args)
17
+ # options.host.should == "localhost"
18
+ # end
19
+ #
20
+ # it "should set a default beanstalk host" do
21
+ # args = %w(-r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
22
+ # options = Flapjack::Notifier::Options.parse(args)
23
+ # options.host.should == 'localhost'
24
+ # end
25
+ #
26
+ # # beanstalk port
27
+ # it "should accept a specified beanstalk port in short form" do
28
+ # args = %w(-b localhost -p 11340 -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
29
+ # options = Flapjack::Notifier::Options.parse(args)
30
+ # options.port.should == 11340
31
+ # end
32
+ #
33
+ # it "should accept a specified beanstalk port in long form" do
34
+ # args = %w(-b localhost --port 11399 -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
35
+ # options = Flapjack::Notifier::Options.parse(args)
36
+ # options.port.should == 11399
37
+ # end
38
+ #
39
+ # it "should set a default beanstalk port" do
40
+ # args = %w(-b localhost -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
41
+ # options = Flapjack::Notifier::Options.parse(args)
42
+ # options.port.should == 11300
43
+ # end
44
+ #
45
+ # # recipients
46
+ # it "should accept the location of a recipients file in short form" do
47
+ # args = %w(-b localhost -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
48
+ # options = Flapjack::Notifier::Options.parse(args)
49
+ # options.recipients.should == "spec/recipients.yaml"
50
+ # end
51
+ #
52
+ # it "should accept the location of a recipients file in long form" do
53
+ # args = %w(-b localhost --recipient spec/recipients.yaml -c spec/flapjack-notifier.yaml)
54
+ # options = Flapjack::Notifier::Options.parse(args)
55
+ # options.recipients.should == "spec/recipients.yaml"
56
+ # end
57
+ #
58
+ # it "should exit if the recipients file doesn't exist" do
59
+ # args = %w(-b localhost -r spec/wangity.yaml -c spec/flapjack-notifier.yaml)
60
+ # lambda {
61
+ # Flapjack::Notifier::Options.parse(args)
62
+ # }.should raise_error(SystemExit)
63
+ # end
64
+ #
65
+ # it "should exit if the recipients file isn't specified" do
66
+ # args = %w(-b localhost -c spec/flapjack-notifier.yaml)
67
+ # lambda {
68
+ # Flapjack::Notifier::Options.parse(args)
69
+ # }.should raise_error(SystemExit)
70
+ # end
71
+ #
72
+ # # config
73
+ # it "should accept the location of a config file in short form" do
74
+ # args = %w(-b localhost -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
75
+ # options = Flapjack::Notifier::Options.parse(args)
76
+ # options.config_filename.should == "spec/flapjack-notifier.yaml"
77
+ # end
78
+ #
79
+ # it "should accept the location of a config file in long form" do
80
+ # args = %w(-b localhost -r spec/recipients.yaml --config spec/flapjack-notifier.yaml)
81
+ # options = Flapjack::Notifier::Options.parse(args)
82
+ # options.config_filename.should == "spec/flapjack-notifier.yaml"
83
+ # end
84
+ #
85
+ # it "should provide a default config file if not specified" do
86
+ # args = %w(-b localhost -r spec/recipients.yaml -c spec/flapjack-notifier.yaml)
87
+ # options = Flapjack::Notifier::Options.parse(args)
88
+ # options.config_filename.should_not be_nil
89
+ # end
90
+ #
91
+ # it "should exit if the config file doesn't exist" do
92
+ # args = %w(-b localhost --config spec/wangity.yaml)
93
+ # lambda {
94
+ # Flapjack::Notifier::Options.parse(args)
95
+ # }.should raise_error(SystemExit)
96
+ # end
97
+ #
98
+ # # general
99
+ # it "should exit when asked for help in short form" do
100
+ # args = %w(-h)
101
+ # lambda {
102
+ # Flapjack::Notifier::Options.parse(args)
103
+ # }.should raise_error(SystemExit)
104
+ # end
105
+ #
106
+ # it "should exit when asked for help in long form" do
107
+ # args = %w(--help)
108
+ # lambda {
109
+ # Flapjack::Notifier::Options.parse(args)
110
+ # }.should raise_error(SystemExit)
111
+ # end
112
+ #end
113
+ #
114
+ #
115
+ #def puts(*args) ; end
@@ -0,0 +1,57 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'notifier_engine')
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'transports', 'result')
3
+ require File.join(File.dirname(__FILE__), 'helpers')
4
+
5
+ describe "running the notifier" do
6
+
7
+ before(:each) do
8
+ end
9
+
10
+ it "should complain if no logger has been specified" do
11
+ lambda {
12
+ n = Flapjack::NotifierEngine.new
13
+ }.should raise_error(RuntimeError)
14
+ end
15
+
16
+ it "should warn if no notifiers have been specified" do
17
+ n = Flapjack::NotifierEngine.new(:log => MockLogger.new)
18
+ n.log.messages.last.should =~ /no notifiers/
19
+ end
20
+
21
+ it "should log when adding a new notifier" do
22
+ mock_notifier = mock("MockFlapjack::NotifierEngine")
23
+ n = Flapjack::NotifierEngine.new(:log => MockLogger.new,
24
+ :notifiers => [mock_notifier])
25
+ n.log.messages.last.should =~ /using the (.+) notifier/
26
+ end
27
+
28
+ it "should call notify on each notifier when notifying" do
29
+ mock_notifier = mock("MockFlapjack::NotifierEngine")
30
+ mock_notifier.should_receive(:notify)
31
+
32
+ result = Flapjack::Transport::Result.new(:result => {:check_id => 12345})
33
+
34
+ n = Flapjack::NotifierEngine.new(:log => MockLogger.new,
35
+ :notifiers => [mock_notifier])
36
+ n.notify!(:result => result,
37
+ :event => true,
38
+ :recipients => [OpenStruct.new({:name => "John Doe"})])
39
+ end
40
+
41
+ it "should log notification on each notifier" do
42
+ mock_notifier = mock("MockFlapjack::NotifierEngine")
43
+ mock_notifier.stub!(:notify)
44
+
45
+ result = Flapjack::Transport::Result.new(:result => {:check_id => 12345})
46
+
47
+ n = Flapjack::NotifierEngine.new(:log => MockLogger.new,
48
+ :notifiers => [mock_notifier])
49
+ n.notify!(:result => result,
50
+ :event => true,
51
+ :recipients => [OpenStruct.new({:name => "John Doe"})])
52
+ n.log.messages.last.should =~ /12345/
53
+ n.log.messages.last.should =~ /John Doe/
54
+ end
55
+ end
56
+
57
+
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'flapjack', 'notifiers', 'mailer', 'init')
2
+ require File.join(File.dirname(__FILE__), '..', 'helpers')
3
+
4
+ describe "mailing notifier" do
5
+
6
+ it "should error if no from address is provided" do
7
+ lambda {
8
+ mailer = Flapjack::Notifiers::Mailer.new(:log => MockLogger.new)
9
+ }.should raise_error(ArgumentError, /from address/)
10
+ end
11
+
12
+ it "should error if no recipient is provided" do
13
+ mailer = Flapjack::Notifiers::Mailer.new(:from_address => "test@example.org")
14
+ lambda {
15
+ mailer.notify()
16
+ }.should raise_error(ArgumentError, /recipient/)
17
+ end
18
+
19
+ it "should error if no result is provided" do
20
+ mailer = Flapjack::Notifiers::Mailer.new(:from_address => "test@example.org")
21
+ lambda {
22
+ mailer.notify(:who => 'foo')
23
+ }.should raise_error(ArgumentError, /result/)
24
+ end
25
+
26
+ it "should deliver mail to a recipient" do
27
+ mailer = Flapjack::Notifiers::Mailer.new(:from_address => "test@example.org")
28
+ response = mailer.notify(:who => OpenStruct.new(:email => "nobody@example.org"),
29
+ :result => OpenStruct.new(:id => 11, :status => 2, :output => "foo"))
30
+ response.status.should == '250'
31
+ end
32
+
33
+ it "should have a configurable server to send through"
34
+ end
35
+
36
+
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'flapjack', 'notifiers', 'xmpp', 'init')
2
+ require File.join(File.dirname(__FILE__), '..', 'helpers')
3
+
4
+ describe "xmpp notifier" do
5
+
6
+ it "should error if no login details provided" do
7
+ lambda {
8
+ xmpp = Flapjack::Notifiers::Xmpp.new
9
+ }.should raise_error(ArgumentError)
10
+ end
11
+
12
+ it "should error if no recipient is provided" do
13
+ xmpp = Flapjack::Notifiers::Xmpp.new(:jid => "5b73a016c5c644e9bf1601a241fc27f5@jabber.org", :password => "5b73a016c5c644e9bf1601a241fc27f5")
14
+ lambda {
15
+ xmpp.notify(:result => 'foo')
16
+ }.should raise_error(ArgumentError, /recipient/)
17
+ end
18
+
19
+ it "should error if no result is provided" do
20
+ xmpp = Flapjack::Notifiers::Xmpp.new(:jid => "5b73a016c5c644e9bf1601a241fc27f5@jabber.org", :password => "5b73a016c5c644e9bf1601a241fc27f5")
21
+ lambda {
22
+ xmpp.notify(:who => 'foo')
23
+ }.should raise_error(ArgumentError, /result/)
24
+ end
25
+
26
+ it "should deliver message to a recipient" do
27
+ xmpp = Flapjack::Notifiers::Xmpp.new(:jid => "5b73a016c5c644e9bf1601a241fc27f5@jabber.org", :password => "5b73a016c5c644e9bf1601a241fc27f5")
28
+ lambda {
29
+ response = xmpp.notify(:who => OpenStruct.new(:jid => "5b73a016c5c644e9bf1601a241fc27f5@jabber.org"),
30
+ :result => OpenStruct.new(:id => 11, :status => 2, :output => "foo"))
31
+ }.should_not raise_error
32
+ end
33
+
34
+ end
35
+
36
+
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'flapjack', 'applications', 'notifier')
4
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'flapjack', 'persistence', 'data_mapper')
5
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'flapjack', 'transports', 'result')
6
+ require File.join(File.dirname(__FILE__), '..', 'helpers')
7
+ require 'tmpdir'
8
+
9
+ describe "datamapper persistence backend" do
10
+
11
+ it "should query its parent's statuses" do
12
+ backend_options = { :uri => "sqlite3://#{Dir.mktmpdir}/flapjack.db", :log => MockLogger.new }
13
+ DataMapper.setup(:default, backend_options[:uri])
14
+ DataMapper.auto_migrate!
15
+
16
+ bad = Check.new(:command => "exit 1", :name => "bad")
17
+ bad.save.should be_true
18
+
19
+ good = Check.new(:command => "exit 0", :name => "good")
20
+ good.save.should be_true
21
+
22
+ relation = RelatedCheck.new(:parent_check => bad, :child_check => good)
23
+ relation.save.should be_true
24
+
25
+ # the bad check doesn't have failing parents
26
+ raw_result = {:check_id => bad.id, :retval => 2}
27
+ result = Flapjack::Transport::Result.new(:result => raw_result)
28
+
29
+ backend = Flapjack::Persistence::DataMapper.new(backend_options)
30
+ backend.any_parents_failed?(result).should be_false
31
+
32
+ bad.status = 2
33
+ bad.save
34
+
35
+ # the good check has a failing parent (bad)
36
+ raw_result = {:check_id => good.id, :retval => 0}
37
+ result = Flapjack::Transport::Result.new(:result => raw_result)
38
+ backend.any_parents_failed?(result).should be_true
39
+ end
40
+
41
+ it "should persist a result" do
42
+ backend_options = { :uri => "sqlite3://#{Dir.mktmpdir}/flapjack.db", :log => MockLogger.new }
43
+ DataMapper.setup(:default, backend_options[:uri])
44
+ DataMapper.auto_migrate!
45
+
46
+ backend = Flapjack::Persistence::DataMapper.new(backend_options)
47
+
48
+ check = Check.new(:command => "exit 0", :name => "good")
49
+ check.save.should be_true
50
+
51
+ raw_result = {:check_id => check.id, :retval => 2}
52
+ result = Flapjack::Transport::Result.new(:result => raw_result)
53
+
54
+ backend.save(result).should be_true
55
+ end
56
+
57
+ it "should create an event" do
58
+ backend_options = { :uri => "sqlite3://#{Dir.mktmpdir}/flapjack.db", :log => MockLogger.new }
59
+ DataMapper.setup(:default, backend_options[:uri])
60
+ DataMapper.auto_migrate!
61
+
62
+ backend = Flapjack::Persistence::DataMapper.new(backend_options)
63
+
64
+ check = Check.new(:command => "exit 0", :name => "good")
65
+ check.save.should be_true
66
+
67
+ raw_result = {:check_id => check.id, :retval => 2}
68
+ result = Flapjack::Transport::Result.new(:result => raw_result)
69
+
70
+ backend.create_event(result).should be_true
71
+ end
72
+
73
+ end
74
+
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ module Flapjack
5
+ module Persistence
6
+ class MockPersistenceBackend
7
+ def initialize(options={})
8
+ @options = options
9
+ @config = OpenStruct.new(@options)
10
+ @queue = []
11
+ @log = @config.log
12
+ end
13
+
14
+ # log if the method is called (essentially, these are dodgy mocks)
15
+ %w(any_parents_failed? save create_event).each do |method|
16
+ class_eval <<-HERE
17
+ def #{method}(*args)
18
+ @log.info("method #{method} was called on MockPersistenceBackend")
19
+ end
20
+ HERE
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+
data/spec/simple.ini ADDED
@@ -0,0 +1,6 @@
1
+ [forks]
2
+ hello = world
3
+ [spoons]
4
+ foo = bar
5
+ [splades]
6
+ bar = baz
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format
3
+ progress
4
+ --diff
@@ -0,0 +1,13 @@
1
+ module Flapjack
2
+ module Filters
3
+ class Blocker
4
+ def initialize(opts={})
5
+ @log = opts[:log]
6
+ end
7
+
8
+ def block?(result)
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Flapjack
2
+ module Filters
3
+ class Mock
4
+ def initialize(opts={})
5
+ @log = opts[:log]
6
+ end
7
+
8
+ def block?(result)
9
+ false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'flapjack', 'applications', 'notifier')
2
+ require File.join(File.dirname(__FILE__), '..', 'helpers')
3
+ require 'beanstalk-client'
4
+
5
+ describe "notifier application" do
6
+
7
+ before(:each) do
8
+ lambda {
9
+ begin
10
+ @beanstalk = Beanstalk::Connection.new('localhost:11300', 'results')
11
+ rescue => e
12
+ # give helpful error messages to people unfamiliar with the test suite
13
+ puts
14
+ puts "You need to have an instance of beanstalkd running locally to run these tests!"
15
+ puts
16
+ raise
17
+ end
18
+ }.should_not raise_error
19
+ end
20
+
21
+ it "should handle good, bad, and ugly test result" do
22
+ [ {:output => "", :id => 1, :retval => 0},
23
+ {:output => "", :id => 2, :retval => 1},
24
+ {:output => "", :id => 3, :retval => 2} ].each do |result|
25
+ @beanstalk.yput(result)
26
+ end
27
+
28
+ options = { :notifiers => {},
29
+ :filters => [],
30
+ :log => MockLogger.new,
31
+ :transport => {:backend => :beanstalkd},
32
+ :persistence => {:backend => :mock_persistence_backend,
33
+ :basedir => File.join(File.dirname(__FILE__), '..', 'persistence')}}
34
+ app = Flapjack::Notifier::Application.run(options)
35
+
36
+ 3.times do |n|
37
+ lambda {
38
+ app.process_result
39
+ }.should_not raise_error
40
+ end
41
+ end
42
+
43
+ end
44
+
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ module Flapjack
5
+ module Transport
6
+ class MockTransport
7
+ def initialize(options={})
8
+ @options = options
9
+ @config = OpenStruct.new(@options)
10
+ @queue = []
11
+ @log = @config.log
12
+ end
13
+
14
+ %w(delete put).each do |method|
15
+ class_eval <<-HERE
16
+ def #{method}(*args)
17
+ @log.info("method #{method} was called on MockTransport")
18
+ end
19
+ HERE
20
+ end
21
+
22
+ # exactly the same as above, just returns a real object
23
+ def next
24
+ @log.info("method next was called on MockTransport")
25
+ MockResult.new(@options)
26
+ end
27
+
28
+
29
+ end
30
+ end
31
+ end
32
+
33
+ module Flapjack
34
+ module Transport
35
+ class MockResult
36
+ def initialize(options={})
37
+ @options = options
38
+ @config = OpenStruct.new(@options)
39
+ @log = @config.log
40
+ end
41
+
42
+ # log if the method is called (essentially, these are dodgy mocks)
43
+ %w(warning? critical? any_parents_failed? save check_id frequency).each do |method|
44
+ class_eval <<-HERE
45
+ def #{method}(*args)
46
+ @log.info("method #{method} was called on MockResult")
47
+ end
48
+ HERE
49
+ end
50
+
51
+ # exactly the same as above, just returns a real object
52
+ def command(*args)
53
+ @log.info("method command was called on MockResult")
54
+ "echo foo"
55
+ end
56
+ end
57
+ end
58
+ end