flapjack 0.5.4 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/flapjack-worker +1 -10
- data/features/flapjack-worker-manager.feature +6 -4
- data/features/flapjack-worker.feature +27 -0
- data/features/steps/flapjack-importer_steps.rb +2 -2
- data/features/steps/flapjack-worker_steps.rb +61 -0
- data/features/support/env.rb +44 -18
- data/flapjack.gemspec +4 -2
- data/lib/flapjack/applications/worker.rb +38 -16
- data/lib/flapjack/transports/beanstalkd.rb +21 -4
- metadata +6 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.5
|
data/bin/flapjack-worker
CHANGED
@@ -1,19 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$: << File.
|
3
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
4
|
|
5
5
|
require 'flapjack/cli/worker'
|
6
6
|
require 'flapjack/applications/worker'
|
7
7
|
|
8
|
-
at_exit do
|
9
|
-
puts "Shutting down"
|
10
|
-
end
|
11
|
-
|
12
|
-
trap("INT") do
|
13
|
-
puts "Caught shutdown signal, cleaning up."
|
14
|
-
exit
|
15
|
-
end
|
16
|
-
|
17
8
|
@options = Flapjack::WorkerOptions.parse(ARGV)
|
18
9
|
app = Flapjack::Worker::Application.run(:host => @options.host,
|
19
10
|
:port => @options.port,
|
@@ -1,25 +1,27 @@
|
|
1
|
-
Feature: flapjack-
|
1
|
+
Feature: flapjack-worker-manager
|
2
2
|
To scale Flapjack easily and efficiently
|
3
3
|
A sysadmin
|
4
4
|
Must be able to manage clusters of workers
|
5
|
+
With ease
|
6
|
+
From the command line
|
5
7
|
|
6
8
|
Scenario: Running multiple workers
|
7
9
|
Given the flapjack-worker-manager is on my path
|
8
10
|
And beanstalkd is running on localhost
|
9
11
|
And there are no instances of flapjack-worker running
|
10
|
-
When I run "flapjack-worker-manager start"
|
12
|
+
When I run "flapjack-worker-manager start"
|
11
13
|
Then 5 instances of "flapjack-worker" should be running
|
12
14
|
|
13
15
|
Scenario: Running a specified number of workers
|
14
16
|
Given the flapjack-worker-manager is on my path
|
15
17
|
And beanstalkd is running on localhost
|
16
18
|
And there are no instances of flapjack-worker running
|
17
|
-
When I run "flapjack-worker-manager start --workers=10"
|
19
|
+
When I run "flapjack-worker-manager start --workers=10"
|
18
20
|
Then 10 instances of "flapjack-worker" should be running
|
19
21
|
|
20
22
|
Scenario: Stopping all workers
|
21
23
|
Given there are 5 instances of the flapjack-worker running
|
22
24
|
And beanstalkd is running on localhost
|
23
|
-
When I run "flapjack-worker-manager stop"
|
25
|
+
When I run "flapjack-worker-manager stop"
|
24
26
|
Then 0 instances of "flapjack-worker" should be running
|
25
27
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Feature: flapjack-worker
|
2
|
+
To be alerted to problems
|
3
|
+
A user
|
4
|
+
Needs checks executed
|
5
|
+
On a regular schedule
|
6
|
+
And the results of those checks
|
7
|
+
Need to be reported
|
8
|
+
|
9
|
+
Scenario: Start a worker
|
10
|
+
Given beanstalkd is running
|
11
|
+
When I background run "flapjack-worker"
|
12
|
+
Then I should see "flapjack-worker" running
|
13
|
+
Then I should see "Waiting for check" in the "flapjack-worker" output
|
14
|
+
|
15
|
+
Scenario: Start a worker without beanstalk running
|
16
|
+
Given beanstalkd is not running
|
17
|
+
When I background run "flapjack-worker"
|
18
|
+
Then I should see "flapjack-worker" running
|
19
|
+
Then I should not see "Shutting down" in the "flapjack-worker" output
|
20
|
+
|
21
|
+
Scenario: Beanstalk disappears while worker running
|
22
|
+
Given beanstalkd is running
|
23
|
+
When I background run "flapjack-worker"
|
24
|
+
And beanstalkd is killed
|
25
|
+
Then I should see "flapjack-worker" running
|
26
|
+
Then I should not see "Shutting down" in the "flapjack-worker" output
|
27
|
+
Then I should see "went away" in the "flapjack-worker" output
|
@@ -71,13 +71,13 @@ end
|
|
71
71
|
Given /^beanstalkd is running$/ do
|
72
72
|
system("which beanstalkd > /dev/null 2>&1").should be_true
|
73
73
|
|
74
|
-
@
|
74
|
+
@beanstalk = IO.popen("beanstalkd")
|
75
75
|
|
76
76
|
# So beanstalkd has a moment to catch its breath.
|
77
77
|
sleep 0.5
|
78
78
|
|
79
79
|
at_exit do
|
80
|
-
Process.kill("KILL", @
|
80
|
+
Process.kill("KILL", @beanstalk.pid)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
Given /^beanstalkd is not running$/ do
|
2
|
+
if @beanstalk
|
3
|
+
Process.kill("KILL", @beanstalk.pid)
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
Then /^I should see "([^"]*)" running$/ do |command|
|
8
|
+
instance_variable_name = "@" + command.split("-")[1]
|
9
|
+
pipe = instance_variable_get(instance_variable_name)
|
10
|
+
pipe.should_not be_nil
|
11
|
+
`ps -p #{pipe.pid}`.split("\n").size.should == 2
|
12
|
+
end
|
13
|
+
|
14
|
+
When /^I background run "flapjack-worker"$/ do
|
15
|
+
@root = Pathname.new(File.dirname(__FILE__)).parent.parent.expand_path
|
16
|
+
bin_path = @root.join('bin')
|
17
|
+
command = "#{bin_path}/flapjack-worker 2>&1"
|
18
|
+
|
19
|
+
@worker = IO.popen(command, 'r')
|
20
|
+
|
21
|
+
sleep 1
|
22
|
+
|
23
|
+
at_exit do
|
24
|
+
Process.kill("KILL", @worker.pid)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^I should see "([^"]*)" in the "([^"]*)" output$/ do |string, command|
|
29
|
+
instance_variable_name = "@" + command.split("-")[1]
|
30
|
+
pipe = instance_variable_get(instance_variable_name)
|
31
|
+
pipe.should_not be_nil
|
32
|
+
|
33
|
+
@output = read_until_timeout(pipe, 4)
|
34
|
+
@output.grep(/#{string}/).size.should > 0
|
35
|
+
end
|
36
|
+
|
37
|
+
Then /^I should not see "([^"]*)" in the "([^"]*)" output$/ do |string, command|
|
38
|
+
instance_variable_name = "@" + command.split("-")[1]
|
39
|
+
pipe = instance_variable_get(instance_variable_name)
|
40
|
+
pipe.should_not be_nil
|
41
|
+
|
42
|
+
@output = read_until_timeout(pipe, 4)
|
43
|
+
@output.grep(/#{string}/).size.should == 0
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^beanstalkd is killed$/ do
|
47
|
+
Given "beanstalkd is not running"
|
48
|
+
end
|
49
|
+
|
50
|
+
Then /^show me the output from "([^"]*)"$/ do |command|
|
51
|
+
instance_variable_name = "@" + command.split("-")[1]
|
52
|
+
pipe = instance_variable_get(instance_variable_name)
|
53
|
+
pipe.should_not be_nil
|
54
|
+
|
55
|
+
@output = read_until_timeout(pipe, 5)
|
56
|
+
puts @output
|
57
|
+
end
|
58
|
+
|
59
|
+
When /^I sleep "(\d+)" seconds$/ do |time|
|
60
|
+
sleep(time.to_i)
|
61
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -2,24 +2,50 @@
|
|
2
2
|
|
3
3
|
$: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
4
4
|
|
5
|
+
require 'pathname'
|
5
6
|
require 'yajl'
|
6
7
|
require 'beanstalk-client'
|
7
8
|
|
8
|
-
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
9
|
+
class ProcessManagement
|
10
|
+
# Cleans up daemons that were started in a scenario.
|
11
|
+
# We kill these daemons so the test state is clean at the beginning of every
|
12
|
+
# scenario, and scenarios don't become coupled with one another.
|
13
|
+
def kill_lingering_daemons
|
14
|
+
# FIXME: iterate through a collection of daemons registered during the scenario
|
15
|
+
Process.kill("KILL", @beanstalk.pid) if @beanstalk
|
16
|
+
end
|
17
|
+
|
18
|
+
# Testing daemons with Ruby backticks blocks indefinitely, because the
|
19
|
+
# backtick method waits for the program to exit. We use the select() system
|
20
|
+
# call to read from a pipe connected to a daemon, and return if no data is
|
21
|
+
# read within the specified timeout.
|
22
|
+
#
|
23
|
+
# http://weblog.jamisbuck.org/assets/2006/9/25/gdb.rb
|
24
|
+
def read_until_timeout(pipe, timeout=1, verbose=false)
|
25
|
+
output = []
|
26
|
+
line = ""
|
27
|
+
while data = IO.select([pipe], nil, nil, timeout) do
|
28
|
+
next if data.empty?
|
29
|
+
char = pipe.read(1)
|
30
|
+
break if char.nil?
|
31
|
+
|
32
|
+
line << char
|
33
|
+
if line[-1] == ?\n
|
34
|
+
puts line if verbose
|
35
|
+
output << line
|
36
|
+
line = ""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
output
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
After do |scenario|
|
46
|
+
kill_lingering_daemons
|
47
|
+
end
|
48
|
+
|
49
|
+
World do
|
50
|
+
ProcessManagement.new
|
51
|
+
end
|
data/flapjack.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{flapjack}
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Lindsay Holmwood"]
|
12
|
-
s.date = %q{2011-01-
|
12
|
+
s.date = %q{2011-01-18}
|
13
13
|
s.description = %q{lapjack is highly scalable and distributed monitoring system. It understands the Nagios plugin format, and can easily be scaled from 1 server to 1000.}
|
14
14
|
s.email = %q{lindsay@holmwood.id.au}
|
15
15
|
s.executables = ["flapjack-benchmark", "flapjack-netsaint-parser", "flapjack-notifier", "flapjack-notifier-manager", "flapjack-populator", "flapjack-stats", "flapjack-worker", "flapjack-worker-manager", "install-flapjack-systemwide"]
|
@@ -52,6 +52,7 @@ Gem::Specification.new do |s|
|
|
52
52
|
"doc/PACKAGING.md",
|
53
53
|
"features/flapjack-notifier-manager.feature",
|
54
54
|
"features/flapjack-worker-manager.feature",
|
55
|
+
"features/flapjack-worker.feature",
|
55
56
|
"features/netsaint-config-converter.feature",
|
56
57
|
"features/packaging-lintian.feature",
|
57
58
|
"features/persistence/couch.feature",
|
@@ -63,6 +64,7 @@ Gem::Specification.new do |s|
|
|
63
64
|
"features/steps/flapjack-netsaint-parser_steps.rb",
|
64
65
|
"features/steps/flapjack-notifier-manager_steps.rb",
|
65
66
|
"features/steps/flapjack-worker-manager_steps.rb",
|
67
|
+
"features/steps/flapjack-worker_steps.rb",
|
66
68
|
"features/steps/packaging-lintian_steps.rb",
|
67
69
|
"features/support/env.rb",
|
68
70
|
"features/support/silent_system.rb",
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'log4r'
|
4
4
|
require 'log4r/outputter/syslogoutputter'
|
@@ -7,8 +7,8 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'patches'))
|
|
7
7
|
module Flapjack
|
8
8
|
module Worker
|
9
9
|
class Application
|
10
|
-
|
11
|
-
# boots the
|
10
|
+
|
11
|
+
# boots the worker
|
12
12
|
def self.run(options={})
|
13
13
|
app = self.new(options)
|
14
14
|
app.setup_loggers
|
@@ -22,15 +22,28 @@ module Flapjack
|
|
22
22
|
|
23
23
|
def initialize(options={})
|
24
24
|
@log = options[:log]
|
25
|
-
@notifier_directories = options[:notifier_directories]
|
26
25
|
@options = options
|
26
|
+
|
27
|
+
setup_event_handlers
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def setup_event_handlers
|
32
|
+
at_exit do
|
33
|
+
@log.info("Shutting down")
|
34
|
+
end
|
35
|
+
|
36
|
+
trap("INT") do
|
37
|
+
puts "Caught shutdown signal, cleaning up."
|
38
|
+
exit
|
39
|
+
end
|
27
40
|
end
|
28
41
|
|
29
42
|
def setup_loggers
|
30
43
|
unless @log
|
31
|
-
|
32
|
-
|
33
|
-
|
44
|
+
@log = Log4r::Logger.new("worker")
|
45
|
+
@log.add(Log4r::StdoutOutputter.new("worker"))
|
46
|
+
@log.add(Log4r::SyslogOutputter.new("worker"))
|
34
47
|
end
|
35
48
|
end
|
36
49
|
|
@@ -39,25 +52,26 @@ module Flapjack
|
|
39
52
|
end
|
40
53
|
|
41
54
|
def setup_queues
|
42
|
-
defaults = { :backend => :beanstalkd,
|
43
|
-
:host => 'localhost',
|
55
|
+
defaults = { :backend => :beanstalkd,
|
56
|
+
:host => 'localhost',
|
44
57
|
:port => '11300',
|
45
58
|
:log => @log }
|
46
59
|
config = defaults.merge(@config.transport || {})
|
47
60
|
basedir = config.delete(:basedir) || File.join(File.dirname(__FILE__), '..', 'transports')
|
48
61
|
|
49
62
|
%w(results checks).each do |queue_name|
|
50
|
-
|
63
|
+
|
51
64
|
queue_config = config.merge(:queue_name => queue_name)
|
52
|
-
|
65
|
+
|
53
66
|
class_name = config[:backend].to_s.camel_case
|
54
|
-
filename = File.join(basedir, "#{config[:backend]}.rb")
|
55
|
-
|
67
|
+
filename = File.expand_path(File.join(basedir, "#{config[:backend]}.rb"))
|
68
|
+
|
56
69
|
@log.info("Loading the #{class_name} transport for queue: #{queue_name}.")
|
57
70
|
|
58
|
-
begin
|
71
|
+
begin
|
59
72
|
require filename
|
60
|
-
|
73
|
+
transport = Flapjack::Transport.const_get("#{class_name}")
|
74
|
+
queue = transport.new(queue_config)
|
61
75
|
instance_variable_set("@#{queue_name}_queue", queue)
|
62
76
|
rescue LoadError => e
|
63
77
|
@log.warning("Attempted to load #{class_name} transport, but it doesn't exist!")
|
@@ -67,6 +81,14 @@ module Flapjack
|
|
67
81
|
end
|
68
82
|
end
|
69
83
|
|
84
|
+
def log(level, opts={})
|
85
|
+
if opts[:data]
|
86
|
+
@log.method(level).call(pp opts[:data])
|
87
|
+
else
|
88
|
+
@log.method(level).call(opts[:message])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
70
92
|
def process_check
|
71
93
|
@log.info("Waiting for check...")
|
72
94
|
check = @checks_queue.next
|
@@ -89,7 +111,7 @@ module Flapjack
|
|
89
111
|
|
90
112
|
def main
|
91
113
|
@log.info("Booting main loop.")
|
92
|
-
loop do
|
114
|
+
loop do
|
93
115
|
process_check
|
94
116
|
end
|
95
117
|
end
|
@@ -10,18 +10,35 @@ module Flapjack
|
|
10
10
|
def initialize(options={})
|
11
11
|
@options = options
|
12
12
|
@config = OpenStruct.new(options)
|
13
|
+
@log = @config.log
|
13
14
|
|
14
15
|
unless @config.host && @config.port && @config.queue_name
|
15
16
|
raise ArgumentError, "You need to specify a beanstalkd host, port, and queue name to connect to."
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
+
connect
|
20
|
+
end
|
21
|
+
|
22
|
+
def connect
|
23
|
+
begin
|
24
|
+
@queue = Beanstalk::Pool.new(["#{@config.host}:#{@config.port}"], @config.queue_name)
|
25
|
+
rescue Beanstalk::NotConnected => e
|
26
|
+
@log.error("Couldn't connect to the '#{@config.queue_name}' Beanstalk queue. Waiting 5 seconds, then retrying.")
|
27
|
+
sleep 5
|
28
|
+
retry
|
29
|
+
end
|
19
30
|
end
|
20
31
|
|
21
32
|
def next
|
22
|
-
|
23
|
-
|
24
|
-
|
33
|
+
begin
|
34
|
+
job = @queue.reserve # blocks
|
35
|
+
result = YAML::load(job.body)
|
36
|
+
Flapjack::Transport::Result.new(:job => job, :result => result)
|
37
|
+
rescue Beanstalk::NotConnected
|
38
|
+
@log.error("The '#{@config.queue_name}' Beanstalk queue went away. Waiting 5 seconds, then retrying.")
|
39
|
+
sleep 5
|
40
|
+
retry
|
41
|
+
end
|
25
42
|
end
|
26
43
|
|
27
44
|
def delete(result)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flapjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 5
|
10
|
+
version: 0.5.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Lindsay Holmwood
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-01-
|
18
|
+
date: 2011-01-18 00:00:00 +11:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -182,6 +182,7 @@ files:
|
|
182
182
|
- doc/PACKAGING.md
|
183
183
|
- features/flapjack-notifier-manager.feature
|
184
184
|
- features/flapjack-worker-manager.feature
|
185
|
+
- features/flapjack-worker.feature
|
185
186
|
- features/netsaint-config-converter.feature
|
186
187
|
- features/packaging-lintian.feature
|
187
188
|
- features/persistence/couch.feature
|
@@ -193,6 +194,7 @@ files:
|
|
193
194
|
- features/steps/flapjack-netsaint-parser_steps.rb
|
194
195
|
- features/steps/flapjack-notifier-manager_steps.rb
|
195
196
|
- features/steps/flapjack-worker-manager_steps.rb
|
197
|
+
- features/steps/flapjack-worker_steps.rb
|
196
198
|
- features/steps/packaging-lintian_steps.rb
|
197
199
|
- features/support/env.rb
|
198
200
|
- features/support/silent_system.rb
|