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,66 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'inifile')
4
+ require File.join(File.dirname(__FILE__), 'helpers')
5
+
6
+ describe "inifile reader" do
7
+
8
+ it "should turn sections into keys" do
9
+ example = "[forks]\nhello = world\n[spoons]\nfoo = bar\n[splades]\nbar = baz"
10
+ ini = Flapjack::Inifile.new(example)
11
+ ini.keys.sort.should == %w{forks splades spoons}
12
+ end
13
+
14
+ it "should nest parameters under a section" do
15
+ example = "[forks]\nhello = world\n[spoons]\nfoo = bar\n[splades]\nbar = baz"
16
+ ini = Flapjack::Inifile.new(example)
17
+ ini['forks']['hello'].should == "world"
18
+ ini['spoons']['foo'].should == "bar"
19
+ ini['splades']['bar'].should == "baz"
20
+ end
21
+
22
+ it "should read a file" do
23
+ filename = File.join(File.dirname(__FILE__), 'simple.ini')
24
+ ini = Flapjack::Inifile.read(filename)
25
+ ini['forks']['hello'].should == "world"
26
+ ini['spoons']['foo'].should == "bar"
27
+ ini['splades']['bar'].should == "baz"
28
+ end
29
+
30
+ it "should ignore commented lines" do
31
+ example = "[forks]\nhello = world\n[spoons]\nfoo = bar\n# comment goes here\n[splades]\nbar = baz"
32
+ ini = Flapjack::Inifile.new(example)
33
+ ini['spoons'].keys.include?(/#/).should be_false
34
+ ini['spoons'].keys.include?(/comment goes here/).should be_false
35
+ ini['spoons'].values.include?(/#/).should be_false
36
+ ini['spoons'].values.include?(/comment goes here/).should be_false
37
+ end
38
+
39
+ it "should ignore blank lines" do
40
+ example = "\n\n\n\n\n\n\n[spoons]\n\n\n\n[of]\n[doom]"
41
+ ini = Flapjack::Inifile.new(example)
42
+ ini.keys.sort.should == %w(doom of spoons)
43
+ end
44
+
45
+ it "should ignore mid-line comments" do
46
+ example = "[forks] ; a comment \nhello = world ; another comment\n\n"
47
+ ini = Flapjack::Inifile.new(example)
48
+ ini.keys.include?("forks").should be_true
49
+ ini['forks']['hello'].should == 'world'
50
+ end
51
+
52
+ it "should append re-opened sections" do
53
+ example = "[forks]\nhello = world\n[forks]\nfoo = bar\n\n[forks]\nbar = baz"
54
+ ini = Flapjack::Inifile.new(example)
55
+ ini.keys.include?("forks").should be_true
56
+ ini["forks"].keys.sort.should == %w(bar foo hello)
57
+ end
58
+
59
+ it "should dump the raw config" do
60
+ example = "[forks]\nhello = world\n[spoons]\nfoo = bar\n[splades]\nbar = baz"
61
+ ini = Flapjack::Inifile.new(example)
62
+ ini.all.size.should == 3
63
+ end
64
+
65
+
66
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), 'mock')
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'xmpp4r-simple'
4
+
5
+ module Flapjack
6
+ module Notifiers
7
+ class Mock
8
+
9
+ attr_accessor :log, :website_uri
10
+
11
+ def initialize(opts={})
12
+ @log = opts[:log]
13
+ @website_uri = opts[:website_uri]
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Flapjack
4
+ module Notifiers
5
+ class Testmailer
6
+
7
+ def initialize(opts={})
8
+ @log = opts[:log]
9
+ end
10
+
11
+ def notify(opts={})
12
+ @log.debug("TestMailer notifying #{opts[:who].name}")
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+
19
+
20
+
@@ -0,0 +1,222 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'applications', 'notifier')
2
+ require File.join(File.dirname(__FILE__), 'helpers')
3
+
4
+ describe "notifier application" do
5
+
6
+ #
7
+ # booting interface
8
+ #
9
+
10
+ it "should have a simple interface to start the notifier" do
11
+ options = { :notifiers => {},
12
+ :filters => [],
13
+ :log => MockLogger.new,
14
+ :persistence => {:backend => :mock_persistence_backend,
15
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
16
+ app = Flapjack::Notifier::Application.run(options)
17
+ end
18
+
19
+ it "should log when loading a notifier" do
20
+ options = { :notifiers => {:testmailer => {}},
21
+ :filters => [],
22
+ :log => MockLogger.new,
23
+ :notifier_directories => [File.join(File.dirname(__FILE__),'notifier-directories', 'spoons')],
24
+ :persistence => {:backend => :mock_persistence_backend,
25
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
26
+ app = Flapjack::Notifier::Application.run(options)
27
+ app.log.messages.find {|msg| msg =~ /loading the testmailer notifier/i}.should_not be_nil
28
+ end
29
+
30
+ it "should warn if a specified notifier doesn't exist" do
31
+ options = { :notifiers => {:nonexistant => {}},
32
+ :filters => [],
33
+ :log => MockLogger.new,
34
+ :persistence => {:backend => :mock_persistence_backend,
35
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
36
+ app = Flapjack::Notifier::Application.run(options)
37
+ app.log.messages.find {|msg| msg =~ /Flapjack::Notifiers::Nonexistant doesn't exist/}.should_not be_nil
38
+ end
39
+
40
+ it "should give precedence to notifiers in user-specified notifier directories" do
41
+ options = { :notifiers => {:testmailer => {}},
42
+ :filters => [],
43
+ :log => MockLogger.new,
44
+ :notifier_directories => [File.join(File.dirname(__FILE__),'notifier-directories', 'spoons')],
45
+ :persistence => {:backend => :mock_persistence_backend,
46
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
47
+ app = Flapjack::Notifier::Application.run(options)
48
+ app.log.messages.find {|msg| msg =~ /spoons/i}.should_not be_nil
49
+ # this will raise an exception if the notifier directory isn't specified,
50
+ # as the mailer notifier requires several arguments anyhow
51
+ end
52
+
53
+ it "should pass global notifier config options to each notifier"
54
+
55
+ it "should setup recipients from a list" do
56
+ options = { :notifiers => {},
57
+ :filters => [],
58
+ :log => MockLogger.new,
59
+ :recipients => [{:name => "Spoons McDoom"}],
60
+ :persistence => {:backend => :mock_persistence_backend,
61
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
62
+ app = Flapjack::Notifier::Application.run(options)
63
+ # 1 passed recipient should be here
64
+ app.recipients.size.should == 1
65
+ end
66
+
67
+ #
68
+ # transports
69
+ #
70
+
71
+ it "should use beanstalkd as the default transport" do
72
+ options = { :notifiers => {},
73
+ :filters => [],
74
+ :log => MockLogger.new,
75
+ :persistence => {:backend => :mock_persistence_backend,
76
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
77
+ app = Flapjack::Notifier::Application.run(options)
78
+ app.log.messages.find {|msg| msg =~ /loading.+beanstalkd.+transport/i}.should_not be_nil
79
+ end
80
+
81
+ it "should use a transport as specified in options" do
82
+ options = { :notifiers => {},
83
+ :filters => [],
84
+ :log => MockLogger.new,
85
+ :transport => {:backend => :beanstalkd},
86
+ :persistence => {:backend => :mock_persistence_backend,
87
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
88
+ app = Flapjack::Notifier::Application.run(options)
89
+ app.log.messages.find {|msg| msg =~ /loading.+beanstalkd.+transport/i}.should_not be_nil
90
+ end
91
+
92
+ it "should error if the specified transport doesn't exist" do
93
+ options = { :notifiers => {},
94
+ :filters => [],
95
+ :log => MockLogger.new,
96
+ :transport => {:backend => :nonexistant} }
97
+ lambda {
98
+ app = Flapjack::Notifier::Application.run(options)
99
+ #app.log.messages.find {|msg| msg =~ /attempted to load nonexistant/i}.should_not be_nil
100
+ }.should raise_error
101
+ end
102
+
103
+ it "should use a limited interface for dealing with the results queue" do
104
+
105
+ # Interface for a Flapjack::Transport::<transport> is as follows:
106
+ #
107
+ # methods: next, delete
108
+ #
109
+
110
+ options = { :notifiers => {},
111
+ :filters => [],
112
+ :log => MockLogger.new,
113
+ :transport => {:backend => :mock_transport,
114
+ :basedir => File.join(File.dirname(__FILE__), 'transports')},
115
+ :persistence => {:backend => :mock_persistence_backend,
116
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
117
+ app = Flapjack::Notifier::Application.run(options)
118
+
119
+ # processes a single result
120
+ app.process_result
121
+
122
+ # check that allowed methods were called
123
+ allowed_methods = %w(next delete)
124
+ allowed_methods.each do |method|
125
+ app.log.messages.find {|msg| msg =~ /#{method.gsub(/\?/,'\?')} was called on MockTransport/i}.should_not be_nil
126
+ end
127
+
128
+ # check that no other methods were
129
+ called_methods = app.log.messages.find_all {|msg| msg =~ /^method .+ was called on MockTransport$/i }.map {|msg| msg.split(' ')[1]}
130
+ (allowed_methods - called_methods).size.should == 0
131
+ end
132
+
133
+ it "should use a limited interface for dealing with results" do
134
+
135
+ # Interface for a Flapjack::Transport::Result is as follows:
136
+ #
137
+ # methods: id, warning?, critical?
138
+ #
139
+
140
+ options = { :notifiers => {},
141
+ :filters => ['ok'],
142
+ :log => MockLogger.new,
143
+ :transport => {:backend => :mock_transport,
144
+ :basedir => File.join(File.dirname(__FILE__), 'transports')},
145
+ :persistence => {:backend => :mock_persistence_backend,
146
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
147
+ app = Flapjack::Notifier::Application.run(options)
148
+
149
+ # processes a single result
150
+ app.process_result
151
+
152
+ # check that allowed methods were called
153
+ allowed_methods = %w(check_id warning?)
154
+ allowed_methods.each do |method|
155
+ app.log.messages.find {|msg| msg =~ /#{method.gsub(/\?/,'\?')} was called/i}.should_not be_nil
156
+ end
157
+
158
+ # check that no other methods were called
159
+ called_methods = app.log.messages.find_all {|msg| msg =~ /^method .+ was called on MockResult$/i }.map {|msg| msg.split(' ')[1]}.uniq
160
+ (allowed_methods - called_methods).size.should == 0
161
+ end
162
+
163
+ it "should use a limited interface for dealing with the persistence backend" do
164
+
165
+ # Interface for a Flapjack::Persistence::<backend> is as follows:
166
+ #
167
+ # methods: any_parents_failed?, save
168
+ #
169
+
170
+ options = { :notifiers => {},
171
+ :filters => ['any_parents_failed'],
172
+ :log => MockLogger.new,
173
+ :transport => {:backend => :mock_transport,
174
+ :basedir => File.join(File.dirname(__FILE__), 'transports')},
175
+ :persistence => {:backend => :mock_persistence_backend,
176
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
177
+ app = Flapjack::Notifier::Application.run(options)
178
+
179
+ # processes a single result
180
+ app.process_result
181
+
182
+ # check that allowed methods were called
183
+ allowed_methods = %w(any_parents_failed? save)
184
+ allowed_methods.each do |method|
185
+ app.log.messages.find {|msg| msg =~ /#{method.gsub(/\?/,'\?')} was called/i}.should_not be_nil
186
+ end
187
+
188
+ # check that no other methods were called
189
+ called_methods = app.log.messages.find_all {|msg| msg =~ /^method .+ was called on MockPersistenceBackend$/i }.map {|msg| msg.split(' ')[1]}
190
+ (allowed_methods - called_methods).size.should == 0
191
+ end
192
+
193
+
194
+ #
195
+ # persistence backend
196
+ #
197
+
198
+ it "should load couchdb as the default persistence backend"
199
+
200
+ it "should load a persistence backend as specified in options" do
201
+ options = { :notifiers => {},
202
+ :filters => [],
203
+ :log => MockLogger.new,
204
+ :persistence => {:backend => :mock_persistence_backend,
205
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')} }
206
+ app = Flapjack::Notifier::Application.run(options)
207
+ app.log.messages.find {|msg| msg =~ /loading.+MockPersistenceBackend.+backend/i}.should_not be_nil
208
+ end
209
+
210
+ it "should raise if the specified persistence backend doesn't exist" do
211
+ options = { :notifiers => {},
212
+ :filters => [],
213
+ :log => MockLogger.new,
214
+ :persistence => {:backend => :nonexistant} }
215
+ lambda {
216
+ app = Flapjack::Notifier::Application.run(options)
217
+ }.should raise_error(LoadError)
218
+ end
219
+
220
+ end
221
+
222
+ def puts(*args) ; end
@@ -0,0 +1,52 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'applications', 'notifier')
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(:all) do
8
+ @options = { :notifiers => {:testmailer => {}},
9
+ :notifier_directories => [File.join(File.dirname(__FILE__),'notifier-directories', 'spoons')],
10
+ :recipients => [{:name => "Spoons McDoom"}],
11
+ :transport => {:backend => :mock_transport,
12
+ :basedir => File.join(File.dirname(__FILE__), 'transports')},
13
+ :persistence => {:backend => :mock_persistence_backend,
14
+ :basedir => File.join(File.dirname(__FILE__), 'persistence')},
15
+ :filter_directories => [File.join(File.dirname(__FILE__),'test-filters')]
16
+ }
17
+ end
18
+
19
+ it "should notify by default" do
20
+ @options[:filters] = []
21
+ @options[:log] = MockLogger.new
22
+
23
+ app = Flapjack::Notifier::Application.run(@options)
24
+ # processes a MockResult, as defined in spec/transports/mock_transport.rb
25
+ app.process_result
26
+
27
+ app.log.messages.find {|m| m =~ /testmailer notifying/i}.should be_true
28
+ end
29
+
30
+ it "should not notify if any filters fail" do
31
+ @options[:filters] = ['blocker']
32
+ @options[:log] = MockLogger.new
33
+
34
+ app = Flapjack::Notifier::Application.run(@options)
35
+ # processes a MockResult, as defined in spec/transports/mock_transport.rb
36
+ app.process_result
37
+
38
+ app.log.messages.find {|m| m =~ /testmailer notifying/i}.should be_nil
39
+ end
40
+
41
+ it "should notify if all filters pass" do
42
+ @options[:filters] = ['mock']
43
+ @options[:log] = MockLogger.new
44
+
45
+ app = Flapjack::Notifier::Application.run(@options)
46
+ # processes a MockResult, as defined in spec/transports/mock_transport.rb
47
+ app.process_result
48
+
49
+ app.log.messages.find {|m| m =~ /testmailer notifying/i}.should be_true
50
+ end
51
+
52
+ end
@@ -0,0 +1,71 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'cli', 'notifier')
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'flapjack', 'patches')
3
+
4
+
5
+ describe "notifier options multiplexer" do
6
+
7
+ before(:all) do
8
+ @config_filename = File.join(File.dirname(__FILE__), 'configs', 'flapjack-notifier.ini')
9
+ @recipients_filename = File.join(File.dirname(__FILE__), 'configs', 'recipients.ini')
10
+
11
+ @couchdb_config_filename = File.join(File.dirname(__FILE__), 'configs', 'flapjack-notifier-couchdb.ini')
12
+ end
13
+
14
+ it "should setup notifier options from specified config file" do
15
+ args = ["-c", @config_filename, "-r", @recipients_filename]
16
+ config = Flapjack::Notifier::Options.parse(args)
17
+ config.notifiers.each do |key, value|
18
+ %w(mailer xmpp).include?(key)
19
+ end
20
+
21
+ config.notifier_directories.each do |dir|
22
+ %w(/usr/lib/flapjack/notifiers/ /path/to/my/notifiers).include?(dir)
23
+ end
24
+ end
25
+
26
+ it "should setup beanstalkd transport options from specified config file" do
27
+ args = ["-c", @config_filename, "-r", @recipients_filename]
28
+ config = Flapjack::Notifier::Options.parse(args)
29
+ config.transport[:backend].should == "beanstalkd"
30
+ config.transport[:host].should == "localhost"
31
+ config.transport[:port].should == "11300"
32
+ end
33
+
34
+ it "should setup datamapper persistence options from specified config file" do
35
+ args = ["-c", @config_filename, "-r", @recipients_filename]
36
+ config = Flapjack::Notifier::Options.parse(args)
37
+ config.persistence[:backend].should == "data_mapper"
38
+ config.persistence[:uri].should == "sqlite3:///tmp/flapjack.db"
39
+ end
40
+
41
+ it "should setup couchdb persistence backend from specified config file" do
42
+ args = [ "-c", @couchdb_config_filename, "-r", @recipients_filename ]
43
+ config = Flapjack::Notifier::Options.parse(args)
44
+ config.persistence[:backend].should == "couchdb"
45
+ config.persistence[:host].should == "localhost"
46
+ config.persistence[:port].should == "5984"
47
+ config.persistence[:version].should == "0.8"
48
+ config.persistence[:database].should == "flapjack_production"
49
+ end
50
+
51
+ it "should setup individual notifiers from a specified config file" do
52
+ args = [ "-c", @config_filename, "-r", @recipients_filename ]
53
+ config = Flapjack::Notifier::Options.parse(args)
54
+ config.notifiers.size.should > 0
55
+ end
56
+
57
+ it "should setup notifier directories options from a specified config file" do
58
+ args = [ "-c", @config_filename, "-r", @recipients_filename ]
59
+ config = Flapjack::Notifier::Options.parse(args)
60
+ config.notifier_directories.size.should > 0
61
+ end
62
+
63
+ it "should setup recipients from a specified config file" do
64
+ args = [ "-c", @config_filename, "-r", @recipients_filename ]
65
+ config = Flapjack::Notifier::Options.parse(args)
66
+ config.recipients.size.should > 0
67
+ end
68
+
69
+ end
70
+
71
+