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 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
+
@@ -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
+
@@ -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,10 @@
1
+ - :name: Jane Doe
2
+ :email: "jane@doe.com"
3
+ :phone: "+1 444 333 888"
4
+ :pager: "1444333888"
5
+ :jid: "jane@doe.com"
6
+ - :name: John Doe
7
+ :email: "john@doe.com"
8
+ :phone: "+1 483 401 501"
9
+ :pager: "1888777333"
10
+ :jid: "john@doe.com"
@@ -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
+