flapjack 0.5.1 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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