auxesis-flapjack 0.3.8
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.
- 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
|
+
|