auxesis-flapjack 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +186 -0
- data/Rakefile +65 -0
- data/TODO.md +10 -0
- data/bin/flapjack-notifier +54 -0
- data/bin/flapjack-notifier-manager +30 -0
- data/bin/flapjack-stats +22 -0
- data/bin/flapjack-worker +34 -0
- data/bin/flapjack-worker-manager +33 -0
- data/bin/install-flapjack-systemwide +54 -0
- data/etc/default/flapjack-notifier +15 -0
- data/etc/default/flapjack-workers +14 -0
- data/etc/flapjack/recipients.yaml +10 -0
- data/etc/init.d/flapjack-notifier +47 -0
- data/etc/init.d/flapjack-workers +44 -0
- data/flapjack.gemspec +25 -0
- data/lib/flapjack/cli/notifier.rb +116 -0
- data/lib/flapjack/cli/notifier_manager.rb +64 -0
- data/lib/flapjack/cli/worker.rb +128 -0
- data/lib/flapjack/cli/worker_manager.rb +44 -0
- data/lib/flapjack/notifier.rb +34 -0
- data/lib/flapjack/notifiers/mailer.rb +36 -0
- data/lib/flapjack/notifiers/xmpp.rb +36 -0
- data/lib/flapjack/patches.rb +17 -0
- data/lib/flapjack/result.rb +47 -0
- metadata +130 -0
data/README.md
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
Flapjack
|
2
|
+
========
|
3
|
+
|
4
|
+
Flapjack is highly scalable and distributed monitoring system.
|
5
|
+
|
6
|
+
It understands the Nagios plugin format, and can easily be scaled
|
7
|
+
from 1 server to 1000.
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
Setup dependencies (Ubuntu Hardy)
|
12
|
+
---------------------------------
|
13
|
+
|
14
|
+
Add the following lines to `/etc/apt/sources.list`
|
15
|
+
|
16
|
+
deb http://ppa.launchpad.net/ubuntu-ruby-backports/ubuntu hardy main
|
17
|
+
deb http://ppa.launchpad.net/auxesis/ppa/ubuntu hardy main
|
18
|
+
|
19
|
+
Add GPG keys for the repos:
|
20
|
+
|
21
|
+
sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 288BA53BCB7DA731
|
22
|
+
|
23
|
+
Update your package list:
|
24
|
+
|
25
|
+
sudo aptitude update
|
26
|
+
|
27
|
+
Install rubygems + beanstalkd:
|
28
|
+
|
29
|
+
sudo apt-get install rubygems beanstalkd
|
30
|
+
|
31
|
+
Set `ENABLED=1` in `/etc/default/beanstalkd`.
|
32
|
+
|
33
|
+
Start beanstalkd:
|
34
|
+
|
35
|
+
sudo /etc/init.d/beanstalkd start
|
36
|
+
|
37
|
+
|
38
|
+
Setup dependencies (everyone else)
|
39
|
+
----------------------------------
|
40
|
+
|
41
|
+
Install the following software through your package manager or from source:
|
42
|
+
|
43
|
+
- beanstalkd (from http://xph.us/software/beanstalkd/)
|
44
|
+
- libevent (from http://monkey.org/~provos/libevent/)
|
45
|
+
|
46
|
+
|
47
|
+
Installation
|
48
|
+
------------
|
49
|
+
|
50
|
+
From the checked out code, build + install the gem:
|
51
|
+
|
52
|
+
rake build
|
53
|
+
sudo gem install pkg/flapjack-<latest>.gem
|
54
|
+
|
55
|
+
Then run the magic configuration script to set up init scripts:
|
56
|
+
|
57
|
+
sudo install-flapjack-systemwide
|
58
|
+
|
59
|
+
The script will prompt you if it wants to do anything destructive.
|
60
|
+
|
61
|
+
|
62
|
+
Running
|
63
|
+
-------
|
64
|
+
|
65
|
+
Make sure beanstalkd is running.
|
66
|
+
|
67
|
+
You'll want to set up `/etc/flapjack/recipients.yaml` so notifications can be sent via
|
68
|
+
`flapjack-notifier`:
|
69
|
+
|
70
|
+
- :name: Jane Doe
|
71
|
+
:email: "jane@doe.com"
|
72
|
+
:phone: "+61 444 222 111"
|
73
|
+
:pager: "61444222111"
|
74
|
+
:jid: "jane@doe.com"
|
75
|
+
|
76
|
+
Start up a cluster of workers:
|
77
|
+
|
78
|
+
flapjack-worker-manager start
|
79
|
+
|
80
|
+
This will spin up 5 workers in the background. You can specify how many workers
|
81
|
+
to start:
|
82
|
+
|
83
|
+
flapjack-worker-manager start --workers=10
|
84
|
+
|
85
|
+
Each of the `flapjack-worker`s will output to syslog (check in /var/log/messages).
|
86
|
+
|
87
|
+
Start up the notifier:
|
88
|
+
|
89
|
+
flapjack-notifier --recipients /etc/flapjack/recipients.yaml
|
90
|
+
|
91
|
+
Currently there are email and XMPP notifiers.
|
92
|
+
|
93
|
+
You'll want to get a copy of (http://github.com/auxesis/flapjack-admin/)[flapjack-admin]
|
94
|
+
to set up some checks, then run its' populator to get them into Flapjack.
|
95
|
+
|
96
|
+
What things do
|
97
|
+
--------------
|
98
|
+
|
99
|
+
* `flapjack-worker` => executes checks, reports results
|
100
|
+
* `flapjack-worker-manager` => starts/stops a cluster of `flapjack-worker`
|
101
|
+
* `flapjack-notifier` => gets results, notifies people if necessary
|
102
|
+
* `flapjack-stats` => gets stats from beanstalkd tubes (useful for benchmarks + performance analysis)
|
103
|
+
|
104
|
+
|
105
|
+
init scripts
|
106
|
+
------------
|
107
|
+
|
108
|
+
You can use the provided init scripts to start Flapjack on boot.
|
109
|
+
|
110
|
+
To start:
|
111
|
+
|
112
|
+
/etc/init.d/flapjack-workers start
|
113
|
+
/etc/init.d/flapjack-notifier start
|
114
|
+
|
115
|
+
To set Flapjack to start on boot (Ubuntu):
|
116
|
+
|
117
|
+
sudo update-rc.d flapjack-workers defaults
|
118
|
+
sudo update-rc.d flapjack-notifier defaults
|
119
|
+
|
120
|
+
Config for the init scripts can be found in `/etc/defaults`.
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
Developing
|
125
|
+
----------
|
126
|
+
|
127
|
+
You can write your own notifiers and place them in `lib/flapjack/notifiers/`.
|
128
|
+
|
129
|
+
Your notifier just needs to implement the `notify` method, and take in a hash:
|
130
|
+
|
131
|
+
class Sms
|
132
|
+
def initialize(opts={})
|
133
|
+
# you may want to set from address here
|
134
|
+
end
|
135
|
+
|
136
|
+
def notify(opts={})
|
137
|
+
who = opts[:who]
|
138
|
+
result = opts[:result]
|
139
|
+
# sms to your hearts content
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
Testing
|
145
|
+
-------
|
146
|
+
|
147
|
+
Tests are in `spec/`.
|
148
|
+
|
149
|
+
To run tests:
|
150
|
+
|
151
|
+
$ rake spec
|
152
|
+
|
153
|
+
|
154
|
+
Architecture
|
155
|
+
------------
|
156
|
+
|
157
|
+
-------------------
|
158
|
+
| web interface / |
|
159
|
+
| dsl / flat file |
|
160
|
+
-------------------
|
161
|
+
/
|
162
|
+
|
|
163
|
+
|
|
164
|
+
------------- ------------
|
165
|
+
| populator |--- -----| notifier |
|
166
|
+
------------- | | ------------
|
167
|
+
| |
|
168
|
+
--------------
|
169
|
+
| beanstalkd |
|
170
|
+
--------------
|
171
|
+
|
|
172
|
+
-----------------------------------
|
173
|
+
| | |
|
174
|
+
---------- ---------- ----------
|
175
|
+
| worker | | worker | | worker |
|
176
|
+
---------- ---------- ----------
|
177
|
+
|
178
|
+
|
179
|
+
- populator determines checks that need to occur, and puts checks onto `jobs` tube
|
180
|
+
- populator fetches jobs from a database
|
181
|
+
- populator can be swapped out to get checks from a dsl or flat files
|
182
|
+
- workers pop a check off the beanstalk, perform check, put result onto `results` tube,
|
183
|
+
re-add check to `jobs` tube with a delay.
|
184
|
+
- notifier pops results off `results` tube, notifies as necessary
|
185
|
+
|
186
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
|
8
|
+
Spec::Rake::SpecTask.new do |t|
|
9
|
+
t.spec_opts = ["--options", "spec/spec.opts"]
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
desc "freeze deps"
|
14
|
+
task :deps do
|
15
|
+
|
16
|
+
deps = {'beanstalk-client' => ">= 1.0.2",
|
17
|
+
'log4r' => ">= 1.0.5",
|
18
|
+
'xmpp4r-simple' => ">= 0.8.8",
|
19
|
+
'mailfactory' => ">= 1.4.0"}
|
20
|
+
|
21
|
+
puts "\ninstalling dependencies. this will take a few minutes."
|
22
|
+
|
23
|
+
deps.each_pair do |dep, version|
|
24
|
+
puts "\ninstalling #{dep} (#{version})"
|
25
|
+
system("gem install #{dep} --version '#{version}' -i gems --no-rdoc --no-ri")
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "generate list of files for gemspec"
|
31
|
+
task "gengemfiles" do
|
32
|
+
executables = `git ls-files bin/*`.split.map {|bin| bin.gsub(/^bin\//, '')}
|
33
|
+
files = `git ls-files`.split.delete_if {|file| file =~ /^(spec\/|\.gitignore)/}
|
34
|
+
puts
|
35
|
+
puts "Copy and paste into flapjack.gemspec:"
|
36
|
+
puts
|
37
|
+
puts " s.executables = #{executables.inspect}"
|
38
|
+
puts " s.files = #{files.inspect}"
|
39
|
+
puts
|
40
|
+
puts
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "build gem"
|
44
|
+
task :build do
|
45
|
+
system("gem build flapjack.gemspec")
|
46
|
+
|
47
|
+
FileUtils.mkdir_p('pkg')
|
48
|
+
puts
|
49
|
+
puts "Flapjack gems:"
|
50
|
+
Dir.glob("flapjack-*.gem").each do |gem|
|
51
|
+
dest = File.join('pkg', gem)
|
52
|
+
FileUtils.mv gem, dest
|
53
|
+
puts " " + dest
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
if require 'yard'
|
59
|
+
|
60
|
+
YARD::Rake::YardocTask.new do |t|
|
61
|
+
t.files = ['lib/**/*.rb']
|
62
|
+
t.options = ['--output-dir=doc/', '--readme=README.md']
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/TODO.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
* daemonise notifier
|
2
|
+
* provide config file for notifier
|
3
|
+
* specify which notifier plugins to load
|
4
|
+
* specify configuration for plugins (from address/xmmp login)
|
5
|
+
* write init scripts for notifier/worker-manager
|
6
|
+
* hook notifier into web interface
|
7
|
+
* update status of checks
|
8
|
+
* relationships + cascading notifications
|
9
|
+
* package with pallet
|
10
|
+
* generate .deb/.rpms
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'beanstalk-client'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'optparse'
|
9
|
+
require 'log4r'
|
10
|
+
require 'log4r/outputter/syslogoutputter'
|
11
|
+
require 'flapjack/result'
|
12
|
+
require 'flapjack/notifier'
|
13
|
+
require 'flapjack/notifiers/mailer'
|
14
|
+
require 'flapjack/notifiers/xmpp'
|
15
|
+
require 'daemons'
|
16
|
+
require 'flapjack/patches'
|
17
|
+
|
18
|
+
# command line options are in here
|
19
|
+
require 'flapjack/cli/notifier'
|
20
|
+
|
21
|
+
# boot up the notifier
|
22
|
+
@options = Flapjack::NotifierOptions.parse(ARGV)
|
23
|
+
|
24
|
+
ncli = Flapjack::NotifierCLI.new
|
25
|
+
ncli.setup_loggers
|
26
|
+
ncli.setup_recipients(:filename => @options.recipients)
|
27
|
+
|
28
|
+
ncli.log.debug("Loading Mailer notifier")
|
29
|
+
mailer = Flapjack::Notifiers::Mailer.new
|
30
|
+
ncli.log.debug("Loading XMPP notifier")
|
31
|
+
xmpp = Flapjack::Notifiers::Xmpp.new(:jid => "flapjack-test@jabber.org", :password => "test")
|
32
|
+
ncli.log.debug("Bringing up notifier subsystem")
|
33
|
+
ncli.notifier = Notifier.new(:logger => ncli.log,
|
34
|
+
:notifiers => [mailer], #, xmpp],
|
35
|
+
:recipients => ncli.recipients)
|
36
|
+
|
37
|
+
begin
|
38
|
+
|
39
|
+
ncli.results_queue = Beanstalk::Pool.new(["#{@options.host}:#{@options.port}"], 'results')
|
40
|
+
ncli.log.info("established connection to beanstalkd on #{@options.host}...")
|
41
|
+
|
42
|
+
# process results
|
43
|
+
ncli.process_loop
|
44
|
+
|
45
|
+
rescue Beanstalk::NotConnected
|
46
|
+
ncli.log.error("Couldn't connect to the Beanstalk!")
|
47
|
+
|
48
|
+
timeout = 5
|
49
|
+
ncli.log.error("Retrying in #{timeout} seconds.")
|
50
|
+
sleep timeout
|
51
|
+
|
52
|
+
ncli.log.error("Retrying...")
|
53
|
+
retry
|
54
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'daemons'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'flapjack/cli/notifier_manager'
|
9
|
+
require 'flapjack/patches' # for Daemons
|
10
|
+
|
11
|
+
# reassign ARGV so we don't mess with it directly
|
12
|
+
args = ARGV
|
13
|
+
args << '--help' if args.size == 0
|
14
|
+
options = Flapjack::NotifierManagerOptions.parse(args)
|
15
|
+
|
16
|
+
worker_path = File.join(File.dirname(__FILE__), 'flapjack-notifier')
|
17
|
+
|
18
|
+
# set up pid dir
|
19
|
+
pid_dir = "/var/run/flapjack"
|
20
|
+
FileUtils.mkdir_p(pid_dir)
|
21
|
+
|
22
|
+
daemon_args = (args + ['--', '--beanstalk', options.host,
|
23
|
+
'--port', options.port.to_s,
|
24
|
+
'--recipients', options.recipients])
|
25
|
+
|
26
|
+
Daemons.run(worker_path, :ARGV => daemon_args,
|
27
|
+
:multiple => false,
|
28
|
+
:dir_mode => :normal,
|
29
|
+
:dir => pid_dir)
|
30
|
+
|
data/bin/flapjack-stats
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'beanstalk-client'
|
5
|
+
|
6
|
+
begin
|
7
|
+
beanstalk = Beanstalk::Pool.new(['localhost:11300'])
|
8
|
+
loop do
|
9
|
+
time = Time.now
|
10
|
+
beanstalk.list_tubes['localhost:11300'].each do |tube_name|
|
11
|
+
next if tube_name == 'default'
|
12
|
+
stats = beanstalk.stats_tube(tube_name)
|
13
|
+
puts "#{time.to_i} [#{tube_name}] total: #{stats['total-jobs']}, waiting: #{stats['current-waiting']}, ready: #{stats['current-jobs-ready']}"
|
14
|
+
end
|
15
|
+
sleep 1
|
16
|
+
end
|
17
|
+
rescue Beanstalk::NotConnected
|
18
|
+
puts "beanstalk isn't up!"
|
19
|
+
exit 2
|
20
|
+
end
|
21
|
+
|
22
|
+
|
data/bin/flapjack-worker
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'log4r'
|
7
|
+
require 'log4r/outputter/syslogoutputter'
|
8
|
+
require 'flapjack/cli/worker'
|
9
|
+
|
10
|
+
at_exit do
|
11
|
+
puts "Shutting down"
|
12
|
+
end
|
13
|
+
|
14
|
+
trap("INT") do
|
15
|
+
puts "Caught shutdown signal, cleaning up."
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
|
19
|
+
@options = Flapjack::WorkerOptions.parse(ARGV)
|
20
|
+
@worker = Flapjack::Worker.new(:host => @options.host, :port => @options.port)
|
21
|
+
|
22
|
+
begin
|
23
|
+
@worker.process_loop
|
24
|
+
rescue Beanstalk::NotConnected
|
25
|
+
puts "Couldn't connect to the beanstalk!"
|
26
|
+
|
27
|
+
timeout = 5
|
28
|
+
puts "Retrying in #{timeout} seconds"
|
29
|
+
sleep timeout
|
30
|
+
|
31
|
+
puts "Retrying..."
|
32
|
+
retry
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'daemons'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'flapjack/cli/worker_manager'
|
9
|
+
require 'flapjack/patches' # for Daemons
|
10
|
+
|
11
|
+
# reassign ARGV so we don't mess with it directly
|
12
|
+
args = ARGV
|
13
|
+
args << '--help' if args.size == 0
|
14
|
+
options = WorkerManagerOptions.parse(args)
|
15
|
+
|
16
|
+
worker_path = File.join(File.dirname(__FILE__), 'flapjack-worker')
|
17
|
+
|
18
|
+
# set up pid dir
|
19
|
+
pid_dir = "/var/run/flapjack"
|
20
|
+
FileUtils.mkdir_p(pid_dir)
|
21
|
+
|
22
|
+
# spin up a number of workers (5 is the default).
|
23
|
+
options.workers.times do |n|
|
24
|
+
# we fork for each worker, as Daemons.run backgrounds this script.
|
25
|
+
fork do
|
26
|
+
Daemons.run(worker_path,
|
27
|
+
:ARGV => (args + %w(-- -b localhost)),
|
28
|
+
:multiple => true,
|
29
|
+
:dir_mode => :normal,
|
30
|
+
:dir => pid_dir)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# 28 05 2009
|
4
|
+
# Lindsay Holmwood <lindsay@holmwood.id.au>
|
5
|
+
#
|
6
|
+
# Copies various scripts to appropriate places so Flapjack can be
|
7
|
+
# started as a daemon.
|
8
|
+
#
|
9
|
+
# I abhor these sort of scripts. It's only a stopgap until Flapjack
|
10
|
+
# gets packaged properly.
|
11
|
+
#
|
12
|
+
# If you would like to package, please let me know! Patches welcome.
|
13
|
+
#
|
14
|
+
|
15
|
+
unless ENV["USERNAME"] == "root"
|
16
|
+
puts 'You need to be root to run this script'
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
# prompt/warn the user what is about to happen
|
21
|
+
puts "This script sets up Flapjack to run as a daemon. Specifically it: "
|
22
|
+
puts
|
23
|
+
puts " * installs init scripts and configs into /etc"
|
24
|
+
puts " * sets up /var/run/flapjack "
|
25
|
+
puts " * sets Flapjack to run on boot"
|
26
|
+
puts
|
27
|
+
puts "It will prompt you if it wants to overwrite an existing file."
|
28
|
+
puts
|
29
|
+
print "Do you want to continue? [y/n] "
|
30
|
+
continue = gets.strip
|
31
|
+
puts
|
32
|
+
|
33
|
+
unless continue == "y"
|
34
|
+
puts "Exiting."
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
|
38
|
+
# setup
|
39
|
+
system("mkdir -p /var/run/flapjack")
|
40
|
+
system("chmod a+rw /var/run/flapjack")
|
41
|
+
|
42
|
+
etc_path=`gem contents flapjack |grep etc`.split.first.gsub(/etc\/.+/, 'etc').strip
|
43
|
+
system("cp -aiv #{etc_path}/* /etc")
|
44
|
+
|
45
|
+
# set sequence number to 50 so beanstalkd has a chance to boot
|
46
|
+
system("update-rc.d flapjack-workers defaults 50")
|
47
|
+
system("update-rc.d flapjack-notifier defaults 50")
|
48
|
+
|
49
|
+
puts
|
50
|
+
puts "Setup complete!"
|
51
|
+
puts
|
52
|
+
puts "You may want to customise /etc/flapjack/recipients.yaml"
|
53
|
+
|
54
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Defaults for flapjack-notifier initscript
|
2
|
+
# sourced by /etc/init.d/flapjack-notifier
|
3
|
+
|
4
|
+
# set enabled to 1 if you want the init script to start flapjack-notifier
|
5
|
+
ENABLED=1
|
6
|
+
|
7
|
+
# recipients file
|
8
|
+
RECIPIENTS=/etc/flapjack/recipients.yaml
|
9
|
+
|
10
|
+
# address beanstalkd is bound to
|
11
|
+
BEANSTALKD_ADDR=localhost
|
12
|
+
|
13
|
+
# port beanstalk is listening on
|
14
|
+
BEANSTALKD_PORT=11300
|
15
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Defaults for flapjack-workers initscript
|
2
|
+
# sourced by /etc/init.d/flapjack-workers
|
3
|
+
|
4
|
+
# set enabled to 1 if you want the init script to start flapjack-workers
|
5
|
+
ENABLED=1
|
6
|
+
|
7
|
+
# address beanstalkd is bound to
|
8
|
+
BEANSTALKD_ADDR=localhost
|
9
|
+
|
10
|
+
# port beanstalk is listening on
|
11
|
+
BEANSTALKD_PORT=11300
|
12
|
+
|
13
|
+
# number of workers to spin up
|
14
|
+
WORKERS=5
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009 Lindsay Holmwood <lindsay@holmwood.id.au>
|
4
|
+
#
|
5
|
+
# flapjack-notifier
|
6
|
+
# Boots flapjack-notifier, check executors for Flapjack.
|
7
|
+
#
|
8
|
+
|
9
|
+
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local:/usr/local/sbin:/usr/local/bin
|
10
|
+
|
11
|
+
if [ -f /etc/default/flapjack-notifier ]; then
|
12
|
+
. /etc/default/flapjack-notifier
|
13
|
+
fi
|
14
|
+
|
15
|
+
# Default return value
|
16
|
+
RETVAL=0
|
17
|
+
|
18
|
+
if [ ! $(which flapjack-notifier-manager) ]; then
|
19
|
+
echo "Error: flapjack-notifier-manager isn't on your path."
|
20
|
+
echo "Refusing to start!"
|
21
|
+
exit 1
|
22
|
+
fi
|
23
|
+
|
24
|
+
# Evaluate command
|
25
|
+
case "$1" in
|
26
|
+
start)
|
27
|
+
flapjack-notifier-manager start --recipients $RECIPIENTS \
|
28
|
+
--port $BEANSTALKD_PORT --beanstalk $BEANSTALKD_ADDR
|
29
|
+
RETVAL=$?
|
30
|
+
;;
|
31
|
+
stop)
|
32
|
+
flapjack-notifier-manager stop --recipients $RECIPIENTS \
|
33
|
+
--port $BEANSTALKD_PORT --beanstalk $BEANSTALKD_ADDR
|
34
|
+
RETVAL=$?
|
35
|
+
;;
|
36
|
+
restart)
|
37
|
+
flapjack-notifier-manager restart --recipients $RECIPIENTS \
|
38
|
+
--port $BEANSTALKD_PORT --beanstalk $BEANSTALKD_ADDR
|
39
|
+
RETVAL=$?
|
40
|
+
;;
|
41
|
+
*)
|
42
|
+
echo "Usage: flapjack-notifier {start|stop|restart}"
|
43
|
+
exit 1
|
44
|
+
;;
|
45
|
+
esac
|
46
|
+
|
47
|
+
exit $RETVAL
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009 Lindsay Holmwood <lindsay@holmwood.id.au>
|
4
|
+
#
|
5
|
+
# flapjack-workers
|
6
|
+
# Boots flapjack-workers, check executors for Flapjack.
|
7
|
+
#
|
8
|
+
|
9
|
+
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local:/usr/local/sbin:/usr/local/bin
|
10
|
+
|
11
|
+
if [ -f /etc/default/flapjack-workers ]; then
|
12
|
+
. /etc/default/flapjack-workers
|
13
|
+
fi
|
14
|
+
|
15
|
+
# Default return value
|
16
|
+
RETVAL=0
|
17
|
+
|
18
|
+
if [ ! $(which flapjack-worker-manager) ]; then
|
19
|
+
echo "flapjack-worker-manager isn't on your path."
|
20
|
+
echo "Refusing to start."
|
21
|
+
exit 1
|
22
|
+
fi
|
23
|
+
|
24
|
+
# Evaluate command
|
25
|
+
case "$1" in
|
26
|
+
start)
|
27
|
+
flapjack-worker-manager start --workers $WORKERS
|
28
|
+
RETVAL=$?
|
29
|
+
;;
|
30
|
+
stop)
|
31
|
+
flapjack-worker-manager stop --workers $WORKERS
|
32
|
+
RETVAL=$?
|
33
|
+
;;
|
34
|
+
restart)
|
35
|
+
flapjack-worker-manager restart --workers $WORKERS
|
36
|
+
RETVAL=$?
|
37
|
+
;;
|
38
|
+
*)
|
39
|
+
echo "Usage: flapjack-workers {start|stop|restart}"
|
40
|
+
exit 1
|
41
|
+
;;
|
42
|
+
esac
|
43
|
+
|
44
|
+
exit $RETVAL
|
data/flapjack.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'flapjack'
|
3
|
+
s.version = '0.3.8'
|
4
|
+
s.date = '2009-05-26'
|
5
|
+
|
6
|
+
s.summary = "a scalable and distributed monitoring system"
|
7
|
+
s.description = "Flapjack is highly scalable and distributed monitoring system. It understands the Nagios plugin format, and can easily be scaled from 1 server to 1000."
|
8
|
+
|
9
|
+
s.authors = ['Lindsay Holmwood']
|
10
|
+
s.email = 'lindsay@holmwood.id.au'
|
11
|
+
s.homepage = 'http://flapjack-project.com'
|
12
|
+
s.has_rdoc = false
|
13
|
+
|
14
|
+
s.add_dependency('daemons', '>= 1.0.10')
|
15
|
+
s.add_dependency('beanstalk-client', '>= 1.0.2')
|
16
|
+
s.add_dependency('log4r', '>= 1.0.5')
|
17
|
+
s.add_dependency('xmpp4r-simple', '>= 0.8.8')
|
18
|
+
s.add_dependency('mailfactory', '>= 1.4.0')
|
19
|
+
|
20
|
+
s.bindir = "bin"
|
21
|
+
s.executables = ["flapjack-notifier", "flapjack-notifier-manager", "flapjack-stats", "flapjack-worker", "flapjack-worker-manager", "install-flapjack-systemwide"]
|
22
|
+
s.files = ["README.md", "Rakefile", "TODO.md", "bin/flapjack-notifier", "bin/flapjack-notifier-manager", "bin/flapjack-stats", "bin/flapjack-worker", "bin/flapjack-worker-manager", "bin/install-flapjack-systemwide", "etc/default/flapjack-notifier", "etc/default/flapjack-workers", "etc/flapjack/recipients.yaml", "etc/init.d/flapjack-notifier", "etc/init.d/flapjack-workers", "flapjack.gemspec", "lib/flapjack/cli/notifier.rb", "lib/flapjack/cli/notifier_manager.rb", "lib/flapjack/cli/worker.rb", "lib/flapjack/cli/worker_manager.rb", "lib/flapjack/notifier.rb", "lib/flapjack/notifiers/mailer.rb", "lib/flapjack/notifiers/xmpp.rb", "lib/flapjack/patches.rb", "lib/flapjack/result.rb"]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'optparse'
|
6
|
+
require 'log4r'
|
7
|
+
require 'log4r/outputter/syslogoutputter'
|
8
|
+
|
9
|
+
module Flapjack
|
10
|
+
class NotifierOptions
|
11
|
+
def self.parse(args)
|
12
|
+
options = OpenStruct.new
|
13
|
+
opts = OptionParser.new do |opts|
|
14
|
+
# the available command line options
|
15
|
+
opts.on('-b', '--beanstalk HOST', 'location of the beanstalkd') do |host|
|
16
|
+
options.host = host
|
17
|
+
end
|
18
|
+
opts.on('-p', '--port PORT', 'beanstalkd port') do |port|
|
19
|
+
options.port = port.to_i
|
20
|
+
end
|
21
|
+
opts.on('-r', '--recipients FILE', 'recipients file') do |recipients|
|
22
|
+
options.recipients = recipients.to_s
|
23
|
+
end
|
24
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
25
|
+
puts opts
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# parse the options
|
31
|
+
begin
|
32
|
+
opts.parse!(args)
|
33
|
+
rescue OptionParser::MissingArgument => e
|
34
|
+
# if an --option is missing it's argument
|
35
|
+
puts e.message.capitalize + "\n\n"
|
36
|
+
puts opts
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
# default the host + port
|
41
|
+
options.host ||= 'localhost'
|
42
|
+
options.port ||= 11300
|
43
|
+
|
44
|
+
@errors = []
|
45
|
+
# check that recipients file exists
|
46
|
+
unless File.exists?(options.recipients.to_s)
|
47
|
+
@errors << "The specified recipients file doesn't exist!"
|
48
|
+
end
|
49
|
+
|
50
|
+
# if there are errors, print them out and exit
|
51
|
+
if @errors.size > 0
|
52
|
+
puts "Errors:"
|
53
|
+
@errors.each do |error|
|
54
|
+
puts " - #{error}"
|
55
|
+
end
|
56
|
+
puts
|
57
|
+
puts opts
|
58
|
+
exit 2
|
59
|
+
end
|
60
|
+
|
61
|
+
options
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class NotifierCLI
|
66
|
+
attr_accessor :log, :recipients, :notifier, :results_queue
|
67
|
+
attr_accessor :condition
|
68
|
+
|
69
|
+
def initialize
|
70
|
+
@log = Log4r::Logger.new("notifier")
|
71
|
+
end
|
72
|
+
|
73
|
+
def setup_loggers
|
74
|
+
@log.add(Log4r::StdoutOutputter.new('notifier'))
|
75
|
+
@log.add(Log4r::SyslogOutputter.new('notifier'))
|
76
|
+
end
|
77
|
+
|
78
|
+
def setup_recipients(opts={})
|
79
|
+
|
80
|
+
if opts[:yaml]
|
81
|
+
yaml = opts[:yaml]
|
82
|
+
else
|
83
|
+
opts[:filename] ||= File.join(Dir.pwd, "recipients.yaml")
|
84
|
+
yaml = YAML::load(File.read(opts[:filename]))
|
85
|
+
end
|
86
|
+
|
87
|
+
@recipients = yaml.map do |r|
|
88
|
+
OpenStruct.new(r)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def process_loop
|
93
|
+
@log.info("Processing results...")
|
94
|
+
loop do
|
95
|
+
process_result
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def process_result
|
100
|
+
@log.debug("Waiting for new result...")
|
101
|
+
result_job = @results_queue.reserve
|
102
|
+
result = Result.new(YAML::load(result_job.body))
|
103
|
+
|
104
|
+
@log.info("Processing result for check '#{result.id}'")
|
105
|
+
if result.warning? || result.critical?
|
106
|
+
@log.info("Notifying on check '#{result.id}'")
|
107
|
+
@notifier.notify!(result)
|
108
|
+
end
|
109
|
+
|
110
|
+
@log.debug("Deleting result for check '#{result.id}' from queue")
|
111
|
+
result_job.delete
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
module Flapjack
|
8
|
+
class NotifierManagerOptions
|
9
|
+
def self.parse(args)
|
10
|
+
options = OpenStruct.new
|
11
|
+
opts = OptionParser.new do |opts|
|
12
|
+
opts.banner = "Usage: flapjack-notifier-manager <command> [options]"
|
13
|
+
opts.separator " "
|
14
|
+
opts.separator " where <command> is one of:"
|
15
|
+
opts.separator " start start a worker"
|
16
|
+
opts.separator " stop stop all workers"
|
17
|
+
opts.separator " restart restart workers"
|
18
|
+
opts.separator " "
|
19
|
+
opts.separator " and [options] are:"
|
20
|
+
|
21
|
+
opts.on('-b', '--beanstalk HOST', 'location of the beanstalkd') do |host|
|
22
|
+
options.host = host
|
23
|
+
end
|
24
|
+
opts.on('-p', '--port PORT', 'beanstalkd port') do |port|
|
25
|
+
options.port = port.to_s
|
26
|
+
end
|
27
|
+
opts.on('-r', '--recipients FILE', 'recipients file') do |recipients|
|
28
|
+
options.recipients = File.expand_path(recipients.to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
opts.parse!(args)
|
34
|
+
rescue => e
|
35
|
+
puts e.message.capitalize + "\n\n"
|
36
|
+
puts opts
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
# defaults
|
41
|
+
options.host ||= "localhost"
|
42
|
+
options.port ||= 11300
|
43
|
+
|
44
|
+
unless options.recipients =~ /.+/
|
45
|
+
puts "You must specify a recipients file!\n\n"
|
46
|
+
puts opts
|
47
|
+
exit 2
|
48
|
+
end
|
49
|
+
|
50
|
+
unless File.exists?(options.recipients)
|
51
|
+
puts "The specified recipients file doesn't exist!"
|
52
|
+
exit 2
|
53
|
+
end
|
54
|
+
|
55
|
+
unless %w(start stop restart).include?(args[0])
|
56
|
+
puts opts
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
|
60
|
+
options
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'beanstalk-client'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'optparse'
|
7
|
+
require 'log4r'
|
8
|
+
require 'log4r/outputter/syslogoutputter'
|
9
|
+
require 'flapjack/result'
|
10
|
+
require 'flapjack/patches'
|
11
|
+
|
12
|
+
module Flapjack
|
13
|
+
class WorkerOptions
|
14
|
+
def self.parse(args)
|
15
|
+
options = OpenStruct.new
|
16
|
+
opts = OptionParser.new do |opts|
|
17
|
+
# the available command line options
|
18
|
+
opts.on('-b', '--beanstalk HOST', 'location of the beanstalkd') do |host|
|
19
|
+
options.host = host
|
20
|
+
end
|
21
|
+
opts.on('-p', '--port PORT', 'beanstalkd port') do |port|
|
22
|
+
options.port = port.to_i
|
23
|
+
end
|
24
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
25
|
+
puts opts
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# parse the options
|
31
|
+
begin
|
32
|
+
opts.parse!(args)
|
33
|
+
rescue OptionParser::MissingArgument => e
|
34
|
+
# if an --option is missing it's argument
|
35
|
+
puts e.message.capitalize + "\n\n"
|
36
|
+
puts opts
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
# default the port
|
41
|
+
options.host ||= 'localhost'
|
42
|
+
options.port ||= 11300
|
43
|
+
|
44
|
+
options
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Worker
|
49
|
+
|
50
|
+
attr_accessor :jobs, :results, :log
|
51
|
+
|
52
|
+
def initialize(opts={})
|
53
|
+
@jobs = Beanstalk::Pool.new(["#{opts[:host]}:#{opts[:port]}"], 'jobs')
|
54
|
+
@results = Beanstalk::Pool.new(["#{opts[:host]}:#{opts[:port]}"], 'results')
|
55
|
+
|
56
|
+
if opts[:logger]
|
57
|
+
@log = opts[:logger]
|
58
|
+
else
|
59
|
+
@log = Log4r::Logger.new('worker')
|
60
|
+
@log.add(Log4r::StdoutOutputter.new('worker'))
|
61
|
+
@log.add(Log4r::SyslogOutputter.new('worker'))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def process_loop
|
66
|
+
@log.info("Booting main loop...")
|
67
|
+
loop do
|
68
|
+
process_check
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def process_check
|
73
|
+
# get next check off the beanstalk
|
74
|
+
job, check = get_check()
|
75
|
+
|
76
|
+
# do the actual check
|
77
|
+
result, retval = perform_check(check.command)
|
78
|
+
|
79
|
+
# report the results of the check
|
80
|
+
report_check(:result => result, :retval => retval, :check => check)
|
81
|
+
|
82
|
+
# create another job for the check, delete current job
|
83
|
+
cleanup_job(:job => job, :check => check)
|
84
|
+
end
|
85
|
+
|
86
|
+
def perform_check(cmd)
|
87
|
+
command = "sh -c '#{cmd}'"
|
88
|
+
@log.debug("Executing check: \"#{command}\"")
|
89
|
+
result = `#{command}`
|
90
|
+
retval = $?.exitstatus
|
91
|
+
|
92
|
+
return result, retval
|
93
|
+
end
|
94
|
+
|
95
|
+
def report_check(opts={})
|
96
|
+
raise ArgumentError unless (opts[:result] && opts[:retval] && opts[:check])
|
97
|
+
|
98
|
+
@log.debug "Reporting results for check id #{opts[:check].id}."
|
99
|
+
@results.yput({:id => opts[:check].id,
|
100
|
+
:output => opts[:result],
|
101
|
+
:retval => opts[:retval].to_i})
|
102
|
+
end
|
103
|
+
|
104
|
+
def cleanup_job(opts={})
|
105
|
+
raise ArgumentError unless (opts[:job] && opts[:check])
|
106
|
+
|
107
|
+
# add job back onto stack
|
108
|
+
@log.debug("Putting check back onto beanstalk.")
|
109
|
+
@jobs.yput(opts[:check].to_h, 65536, opts[:check].frequency)
|
110
|
+
|
111
|
+
# once we're done, clean up
|
112
|
+
@log.debug("Deleting job.")
|
113
|
+
opts[:job].delete
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_check
|
117
|
+
@log.debug("Waiting for check...")
|
118
|
+
job = @jobs.reserve
|
119
|
+
check = Check.new(YAML::load(job.body))
|
120
|
+
@log.info("Got check with id #{check.id}")
|
121
|
+
|
122
|
+
return job, check
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
class WorkerManagerOptions
|
8
|
+
def self.parse(args)
|
9
|
+
options = OpenStruct.new
|
10
|
+
opts = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: flapjack-worker-manager <command> [options]"
|
12
|
+
opts.separator " "
|
13
|
+
opts.separator " where <command> is one of:"
|
14
|
+
opts.separator " start start a worker"
|
15
|
+
opts.separator " stop stop all workers"
|
16
|
+
opts.separator " restart restart workers"
|
17
|
+
opts.separator " "
|
18
|
+
opts.separator " and [options] are:"
|
19
|
+
|
20
|
+
opts.on('-w', '--workers N', 'number of workers to spin up') do |workers|
|
21
|
+
options.workers = workers.to_i
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
opts.parse!(args)
|
27
|
+
rescue
|
28
|
+
puts e.message.capitalize + "\n\n"
|
29
|
+
puts opts
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
|
33
|
+
options.workers ||= 5
|
34
|
+
|
35
|
+
unless %w(start stop restart).include?(args[0])
|
36
|
+
puts opts
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
options
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
class Notifier
|
6
|
+
|
7
|
+
attr_reader :recipients, :log
|
8
|
+
|
9
|
+
def initialize(opts={})
|
10
|
+
@log = opts[:logger]
|
11
|
+
raise "you have to specify a logger" unless @log
|
12
|
+
@recipients = (opts[:recipients] || [])
|
13
|
+
|
14
|
+
@notifiers = []
|
15
|
+
if opts[:notifiers]
|
16
|
+
opts[:notifiers].each do |n|
|
17
|
+
@notifiers << n
|
18
|
+
@log.info("using the #{n.class.to_s.split("::").last} notifier")
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@log.warning("there are no notifiers")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def notify!(result)
|
26
|
+
@notifiers.each do |n|
|
27
|
+
@recipients.each do |recipient|
|
28
|
+
@log.info("Notifying #{recipient.name} via #{n.class} about check #{result.id}")
|
29
|
+
n.notify(:result => result, :who => recipient)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'net/smtp'
|
5
|
+
require 'mailfactory'
|
6
|
+
|
7
|
+
module Flapjack
|
8
|
+
module Notifiers
|
9
|
+
|
10
|
+
class Mailer
|
11
|
+
|
12
|
+
def notify(opts={})
|
13
|
+
raise unless (opts[:who] && opts[:result])
|
14
|
+
|
15
|
+
mail = MailFactory.new
|
16
|
+
mail.to = opts[:who].email
|
17
|
+
mail.from = "notifications@flapjack-project.com"
|
18
|
+
mail.subject = "Check: #{opts[:result].id}, Status: #{opts[:result].status}"
|
19
|
+
mail.text = <<-DESC
|
20
|
+
Check #{opts[:result].id} returned the status "#{opts[:result].status}".
|
21
|
+
|
22
|
+
Here was the output:
|
23
|
+
#{opts[:result].output}
|
24
|
+
|
25
|
+
You can respond to this issue at:
|
26
|
+
http://localhost:4000/issue/#{opts[:result].object_id * -1}
|
27
|
+
DESC
|
28
|
+
|
29
|
+
Net::SMTP.start('localhost') do |smtp|
|
30
|
+
smtp.sendmail(mail.to_s, mail.from, mail.to)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'xmpp4r-simple'
|
4
|
+
|
5
|
+
module Flapjack
|
6
|
+
module Notifiers
|
7
|
+
class Xmpp
|
8
|
+
|
9
|
+
def initialize(opts={})
|
10
|
+
|
11
|
+
@jid = opts[:jid]
|
12
|
+
@password = opts[:password]
|
13
|
+
unless @jid && @password
|
14
|
+
raise ArgumentError, "You have to provide a username and password"
|
15
|
+
end
|
16
|
+
@xmpp = Jabber::Simple.new(@jid, @password)
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def notify(opts={})
|
21
|
+
|
22
|
+
raise unless opts[:who] && opts[:result]
|
23
|
+
|
24
|
+
message = <<-DESC
|
25
|
+
Check #{opts[:result].id} returned the status "#{opts[:result].status}".
|
26
|
+
http://localhost:4000/checks/#{opts[:result].id}
|
27
|
+
DESC
|
28
|
+
|
29
|
+
@xmpp.deliver(opts[:who].jid, message)
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'daemons'
|
3
|
+
|
4
|
+
class OpenStruct
|
5
|
+
def to_h
|
6
|
+
@table
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Daemons
|
11
|
+
class PidFile
|
12
|
+
# we override this method so creating pid files is fork-safe
|
13
|
+
def filename
|
14
|
+
File.join(@dir, "#{@progname}#{Process.pid}.pid")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Representation of a check result, as it's popped off the beanstalk.
|
7
|
+
#
|
8
|
+
# Provides several convience methods for querying the status of a result.
|
9
|
+
#
|
10
|
+
# Convenience methods are used by the Notifier to determine whether a
|
11
|
+
# notification needs to be sent out.
|
12
|
+
class Result < OpenStruct
|
13
|
+
|
14
|
+
# Whether a check returns an ok status.
|
15
|
+
def ok?
|
16
|
+
self.retval == 0
|
17
|
+
end
|
18
|
+
|
19
|
+
# Whether a check has a warning status.
|
20
|
+
def warning?
|
21
|
+
self.retval == 1
|
22
|
+
end
|
23
|
+
|
24
|
+
# Whether a check has a critical status.
|
25
|
+
def critical?
|
26
|
+
self.retval == 2
|
27
|
+
end
|
28
|
+
|
29
|
+
# Human readable representation of the check's return value.
|
30
|
+
def status
|
31
|
+
case self.retval
|
32
|
+
when 0 ; "ok"
|
33
|
+
when 1 ; "warning"
|
34
|
+
when 2 ; "critical"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# The id of a check result.
|
39
|
+
def id
|
40
|
+
# openstruct won't respond, so we have to manually define it
|
41
|
+
@table[:id]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class Check < Result
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: auxesis-flapjack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.8
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lindsay Holmwood
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-26 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: daemons
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.0.10
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: beanstalk-client
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.2
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: log4r
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.0.5
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: xmpp4r-simple
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.8.8
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mailfactory
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.4.0
|
64
|
+
version:
|
65
|
+
description: Flapjack is highly scalable and distributed monitoring system. It understands the Nagios plugin format, and can easily be scaled from 1 server to 1000.
|
66
|
+
email: lindsay@holmwood.id.au
|
67
|
+
executables:
|
68
|
+
- flapjack-notifier
|
69
|
+
- flapjack-notifier-manager
|
70
|
+
- flapjack-stats
|
71
|
+
- flapjack-worker
|
72
|
+
- flapjack-worker-manager
|
73
|
+
- install-flapjack-systemwide
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files: []
|
77
|
+
|
78
|
+
files:
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- TODO.md
|
82
|
+
- bin/flapjack-notifier
|
83
|
+
- bin/flapjack-notifier-manager
|
84
|
+
- bin/flapjack-stats
|
85
|
+
- bin/flapjack-worker
|
86
|
+
- bin/flapjack-worker-manager
|
87
|
+
- bin/install-flapjack-systemwide
|
88
|
+
- etc/default/flapjack-notifier
|
89
|
+
- etc/default/flapjack-workers
|
90
|
+
- etc/flapjack/recipients.yaml
|
91
|
+
- etc/init.d/flapjack-notifier
|
92
|
+
- etc/init.d/flapjack-workers
|
93
|
+
- flapjack.gemspec
|
94
|
+
- lib/flapjack/cli/notifier.rb
|
95
|
+
- lib/flapjack/cli/notifier_manager.rb
|
96
|
+
- lib/flapjack/cli/worker.rb
|
97
|
+
- lib/flapjack/cli/worker_manager.rb
|
98
|
+
- lib/flapjack/notifier.rb
|
99
|
+
- lib/flapjack/notifiers/mailer.rb
|
100
|
+
- lib/flapjack/notifiers/xmpp.rb
|
101
|
+
- lib/flapjack/patches.rb
|
102
|
+
- lib/flapjack/result.rb
|
103
|
+
has_rdoc: false
|
104
|
+
homepage: http://flapjack-project.com
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: "0"
|
115
|
+
version:
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: "0"
|
121
|
+
version:
|
122
|
+
requirements: []
|
123
|
+
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.2.0
|
126
|
+
signing_key:
|
127
|
+
specification_version: 2
|
128
|
+
summary: a scalable and distributed monitoring system
|
129
|
+
test_files: []
|
130
|
+
|