god 0.1.0
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/History.txt +5 -0
- data/Manifest.txt +37 -0
- data/README.txt +42 -0
- data/Rakefile +28 -0
- data/bin/god +26 -0
- data/examples/gravatar.god +41 -0
- data/examples/local.god +60 -0
- data/lib/god.rb +35 -0
- data/lib/god/base.rb +13 -0
- data/lib/god/behavior.rb +67 -0
- data/lib/god/behaviors/clean_pid_file.rb +23 -0
- data/lib/god/condition.rb +48 -0
- data/lib/god/conditions/always.rb +11 -0
- data/lib/god/conditions/cpu_usage.rb +44 -0
- data/lib/god/conditions/memory_usage.rb +44 -0
- data/lib/god/conditions/process_not_running.rb +22 -0
- data/lib/god/conditions/timeline.rb +17 -0
- data/lib/god/errors.rb +12 -0
- data/lib/god/meddle.rb +54 -0
- data/lib/god/reporter.rb +25 -0
- data/lib/god/server.rb +28 -0
- data/lib/god/system/process.rb +56 -0
- data/lib/god/timer.rb +78 -0
- data/lib/god/watch.rb +151 -0
- data/test/configs/real.rb +64 -0
- data/test/helper.rb +93 -0
- data/test/suite.rb +6 -0
- data/test/test_behavior.rb +13 -0
- data/test/test_condition.rb +26 -0
- data/test/test_god.rb +15 -0
- data/test/test_meddle.rb +46 -0
- data/test/test_reporter.rb +18 -0
- data/test/test_server.rb +24 -0
- data/test/test_system_process.rb +42 -0
- data/test/test_timeline.rb +24 -0
- data/test/test_timer.rb +43 -0
- data/test/test_watch.rb +123 -0
- metadata +111 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/god
|
6
|
+
examples/gravatar.god
|
7
|
+
examples/local.god
|
8
|
+
lib/god.rb
|
9
|
+
lib/god/base.rb
|
10
|
+
lib/god/behavior.rb
|
11
|
+
lib/god/behaviors/clean_pid_file.rb
|
12
|
+
lib/god/condition.rb
|
13
|
+
lib/god/conditions/always.rb
|
14
|
+
lib/god/conditions/cpu_usage.rb
|
15
|
+
lib/god/conditions/memory_usage.rb
|
16
|
+
lib/god/conditions/process_not_running.rb
|
17
|
+
lib/god/conditions/timeline.rb
|
18
|
+
lib/god/errors.rb
|
19
|
+
lib/god/meddle.rb
|
20
|
+
lib/god/reporter.rb
|
21
|
+
lib/god/server.rb
|
22
|
+
lib/god/system/process.rb
|
23
|
+
lib/god/timer.rb
|
24
|
+
lib/god/watch.rb
|
25
|
+
test/configs/real.rb
|
26
|
+
test/helper.rb
|
27
|
+
test/suite.rb
|
28
|
+
test/test_behavior.rb
|
29
|
+
test/test_condition.rb
|
30
|
+
test/test_god.rb
|
31
|
+
test/test_meddle.rb
|
32
|
+
test/test_reporter.rb
|
33
|
+
test/test_server.rb
|
34
|
+
test/test_system_process.rb
|
35
|
+
test/test_timeline.rb
|
36
|
+
test/test_timer.rb
|
37
|
+
test/test_watch.rb
|
data/README.txt
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
god
|
2
|
+
by Tom Preston-Werner
|
3
|
+
http://god.rubyforge.org
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
God is an easy to configure, easy to extend monitoring framework written in Ruby.
|
8
|
+
|
9
|
+
Keeping your server processes and tasks running should be a simple part of your deployment process. God aims to be the simplest, most powerful monitoring application available.
|
10
|
+
|
11
|
+
== DOCUMENTATION:
|
12
|
+
|
13
|
+
See online documentation at http://god.rubyforge.org
|
14
|
+
|
15
|
+
== INSTALL:
|
16
|
+
|
17
|
+
$ sudo gem install god
|
18
|
+
|
19
|
+
== LICENSE:
|
20
|
+
|
21
|
+
(The MIT License)
|
22
|
+
|
23
|
+
Copyright (c) 2007 FIX
|
24
|
+
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
26
|
+
a copy of this software and associated documentation files (the
|
27
|
+
'Software'), to deal in the Software without restriction, including
|
28
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
29
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
30
|
+
permit persons to whom the Software is furnished to do so, subject to
|
31
|
+
the following conditions:
|
32
|
+
|
33
|
+
The above copyright notice and this permission notice shall be
|
34
|
+
included in all copies or substantial portions of the Software.
|
35
|
+
|
36
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
37
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
38
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
39
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
40
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
41
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
42
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/god.rb'
|
6
|
+
|
7
|
+
Hoe.new('god', God::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'god'
|
9
|
+
p.author = 'Tom Preston-Werner'
|
10
|
+
p.email = 'tom@rubyisawesome.com'
|
11
|
+
p.url = 'http://god.rubyforge.org/'
|
12
|
+
p.summary = 'Like monit, only awesome'
|
13
|
+
p.description = "God is an easy to configure, easy to extend monitoring framework written in Ruby."
|
14
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
+
p.extra_deps << ['daemons', '>=1.0.7']
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Open an irb session preloaded with this library"
|
19
|
+
task :console do
|
20
|
+
sh "irb -rubygems -r ./lib/god.rb"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Upload site to Rubyforge"
|
24
|
+
task :site do
|
25
|
+
sh "scp -r site/* mojombo@god.rubyforge.org:/var/www/gforge-projects/god"
|
26
|
+
end
|
27
|
+
|
28
|
+
# vim: syntax=Ruby
|
data/bin/god
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'daemons'
|
7
|
+
require 'optparse'
|
8
|
+
require 'god'
|
9
|
+
|
10
|
+
options = {}
|
11
|
+
OptionParser.new do |opts|
|
12
|
+
opts.banner = "Usage: god command [options]"
|
13
|
+
|
14
|
+
opts.on("-cCONFIG", "--config-file CONFIG", "Configuration file") do |x|
|
15
|
+
options[:config] = x
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
options[:config] = File.expand_path(options[:config]) if options[:config]
|
20
|
+
|
21
|
+
# p options
|
22
|
+
# p ARGV
|
23
|
+
|
24
|
+
Daemons.run_proc('god') do
|
25
|
+
load options[:config]
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# This is the actual config file used to keep the mongrels of
|
2
|
+
# gravatar.com running.
|
3
|
+
|
4
|
+
RAILS_ROOT = "/var/www/gravatar2/current"
|
5
|
+
|
6
|
+
God.meddle do |god|
|
7
|
+
%w{8200 8201 8202}.each do |port|
|
8
|
+
god.watch do |w|
|
9
|
+
w.name = "gravatar2-mongrel-#{port}"
|
10
|
+
w.interval = 30 # seconds
|
11
|
+
w.start = "mongrel_rails cluster::start --only #{port} -c #{RAILS_ROOT}"
|
12
|
+
w.stop = "mongrel_rails cluster::stop --only #{port} -c #{RAILS_ROOT}"
|
13
|
+
|
14
|
+
pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
|
15
|
+
|
16
|
+
w.behavior(:clean_pid_file) do |b|
|
17
|
+
b.pid_file = pid_file
|
18
|
+
end
|
19
|
+
|
20
|
+
w.start_if do |start|
|
21
|
+
start.condition(:process_not_running) do |c|
|
22
|
+
c.pid_file = pid_file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
w.restart_if do |restart|
|
27
|
+
restart.condition(:memory_usage) do |c|
|
28
|
+
c.pid_file = pid_file
|
29
|
+
c.above = (150 * 1024) # 150mb
|
30
|
+
c.times = [3, 5] # 3 out of 5 intervals
|
31
|
+
end
|
32
|
+
|
33
|
+
restart.condition(:cpu_usage) do |c|
|
34
|
+
c.pid_file = pid_file
|
35
|
+
c.above = 50 # percent
|
36
|
+
c.times = 5
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/examples/local.god
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# This example shows how you might keep a local development Rails server up
|
2
|
+
# and running on your Mac.
|
3
|
+
|
4
|
+
# Run with:
|
5
|
+
# god local.god
|
6
|
+
|
7
|
+
RAILS_ROOT = "/Users/tom/dev/powerset/querytopia"
|
8
|
+
|
9
|
+
God.meddle do |god|
|
10
|
+
god.interval = 5 # seconds
|
11
|
+
|
12
|
+
god.watch do |w|
|
13
|
+
w.name = "local-3000"
|
14
|
+
w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
|
15
|
+
w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
|
16
|
+
w.grace = 5
|
17
|
+
|
18
|
+
pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
|
19
|
+
|
20
|
+
# clean pid files before start if necessary
|
21
|
+
w.behavior(:clean_pid_file) do |b|
|
22
|
+
b.pid_file = pid_file
|
23
|
+
end
|
24
|
+
|
25
|
+
# start if process is not running
|
26
|
+
w.start_if do |start|
|
27
|
+
start.condition(:process_not_running) do |c|
|
28
|
+
c.pid_file = pid_file
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# restart if memory or cpu is too high
|
33
|
+
w.restart_if do |restart|
|
34
|
+
restart.condition(:memory_usage) do |c|
|
35
|
+
c.pid_file = pid_file
|
36
|
+
c.above = (50 * 1024) # 50mb
|
37
|
+
c.times = [3, 5]
|
38
|
+
end
|
39
|
+
|
40
|
+
restart.condition(:cpu_usage) do |c|
|
41
|
+
c.pid_file = pid_file
|
42
|
+
c.above = 10 # percent
|
43
|
+
c.times = [3, 5]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# clear old session files
|
49
|
+
god.watch do |w|
|
50
|
+
w.name = "local-session-cleanup"
|
51
|
+
w.cwd = File.join(RAILS_ROOT, 'tmp/sessions')
|
52
|
+
w.start = lambda do
|
53
|
+
Dir['ruby_sess.*'].select { |f| File.mtime(f) < Time.now - (7 * 24 * 60 * 60) }.each { |f| File.delete(f) }
|
54
|
+
end
|
55
|
+
|
56
|
+
w.start_if do |start|
|
57
|
+
start.condition(:always)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/god.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
|
2
|
+
|
3
|
+
# internal requires
|
4
|
+
require 'god/base'
|
5
|
+
require 'god/errors'
|
6
|
+
|
7
|
+
require 'god/system/process'
|
8
|
+
|
9
|
+
require 'god/behavior'
|
10
|
+
require 'god/behaviors/clean_pid_file'
|
11
|
+
|
12
|
+
require 'god/condition'
|
13
|
+
require 'god/conditions/timeline'
|
14
|
+
require 'god/conditions/process_not_running'
|
15
|
+
require 'god/conditions/memory_usage'
|
16
|
+
require 'god/conditions/cpu_usage'
|
17
|
+
require 'god/conditions/always'
|
18
|
+
|
19
|
+
require 'god/reporter'
|
20
|
+
require 'god/server'
|
21
|
+
require 'god/timer'
|
22
|
+
|
23
|
+
require 'god/watch'
|
24
|
+
require 'god/meddle'
|
25
|
+
|
26
|
+
module God
|
27
|
+
VERSION = '0.1.0'
|
28
|
+
|
29
|
+
def self.meddle(options = {})
|
30
|
+
m = Meddle.new(options)
|
31
|
+
yield m
|
32
|
+
m.monitor
|
33
|
+
m.timer.join
|
34
|
+
end
|
35
|
+
end
|
data/lib/god/base.rb
ADDED
data/lib/god/behavior.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module God
|
2
|
+
|
3
|
+
class Behavior < Base
|
4
|
+
# Generate a Behavior of the given kind. The proper class if found by camel casing the
|
5
|
+
# kind (which is given as an underscored symbol).
|
6
|
+
# +kind+ is the underscored symbol representing the class (e.g. foo_bar for God::Behaviors::FooBar)
|
7
|
+
def self.generate(kind)
|
8
|
+
sym = kind.to_s.capitalize.gsub(/_(.)/){$1.upcase}.intern
|
9
|
+
God::Behaviors.const_get(sym).new
|
10
|
+
rescue NameError
|
11
|
+
raise NoSuchBehaviorError.new("No Behavior found with the class name God::Behaviors::#{sym}")
|
12
|
+
end
|
13
|
+
|
14
|
+
# Override this method in your Behaviors (optional)
|
15
|
+
#
|
16
|
+
# Called once after the Condition has been sent to the block and attributes have been
|
17
|
+
# set. Do any post-processing on attributes here
|
18
|
+
def prepare
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
# Override this method in your Behaviors (optional)
|
23
|
+
#
|
24
|
+
# Called once during evaluation of the config file. Return true if valid, false otherwise
|
25
|
+
#
|
26
|
+
# A convenience method 'complain' is available that will print out a message and return false,
|
27
|
+
# making it easy to report multiple validation errors:
|
28
|
+
#
|
29
|
+
# def valid?
|
30
|
+
# valid = true
|
31
|
+
# valid &= complain("You must specify the 'pid_file' attribute for :memory_usage") if self.pid_file.nil?
|
32
|
+
# valid &= complain("You must specify the 'above' attribute for :memory_usage") if self.above.nil?
|
33
|
+
# valid
|
34
|
+
# end
|
35
|
+
def valid?
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
#######
|
40
|
+
|
41
|
+
def before_start
|
42
|
+
end
|
43
|
+
|
44
|
+
def after_start
|
45
|
+
end
|
46
|
+
|
47
|
+
def before_restart
|
48
|
+
end
|
49
|
+
|
50
|
+
def after_restart
|
51
|
+
end
|
52
|
+
|
53
|
+
def before_stop
|
54
|
+
end
|
55
|
+
|
56
|
+
def after_stop
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def complain(text)
|
62
|
+
puts text
|
63
|
+
false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module God
|
2
|
+
module Behaviors
|
3
|
+
|
4
|
+
class CleanPidFile < Behavior
|
5
|
+
attr_accessor :pid_file
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
self.pid_file = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def valid?
|
12
|
+
valid = true
|
13
|
+
valid &= complain("You must specify the 'pid_file' attribute for :clean_pid_file") if self.pid_file.nil?
|
14
|
+
valid
|
15
|
+
end
|
16
|
+
|
17
|
+
def before_start
|
18
|
+
File.delete(self.pid_file) rescue nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module God
|
2
|
+
|
3
|
+
class Condition < Behavior
|
4
|
+
# Generate a Condition of the given kind. The proper class if found by camel casing the
|
5
|
+
# kind (which is given as an underscored symbol).
|
6
|
+
# +kind+ is the underscored symbol representing the class (e.g. foo_bar for God::Conditions::FooBar)
|
7
|
+
def self.generate(kind)
|
8
|
+
sym = kind.to_s.capitalize.gsub(/_(.)/){$1.upcase}.intern
|
9
|
+
cond = God::Conditions.const_get(sym).new
|
10
|
+
|
11
|
+
unless cond.kind_of?(PollCondition) || cond.kind_of?(EventCondition)
|
12
|
+
abort "Condition '#{cond.class.name}' must subclass either God::PollCondition or God::EventCondition"
|
13
|
+
end
|
14
|
+
|
15
|
+
cond
|
16
|
+
rescue NameError
|
17
|
+
raise NoSuchConditionError.new("No Condition found with the class name God::Conditions::#{sym}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class PollCondition < Condition
|
22
|
+
# all poll conditions can specify a poll interval
|
23
|
+
attr_accessor :interval
|
24
|
+
|
25
|
+
# Override this method in your Conditions (optional)
|
26
|
+
def before
|
27
|
+
end
|
28
|
+
|
29
|
+
# Override this method in your Conditions (mandatory)
|
30
|
+
#
|
31
|
+
# Return true if the test passes (everything is ok)
|
32
|
+
# Return false otherwise
|
33
|
+
def test
|
34
|
+
raise AbstractMethodNotOverriddenError.new("Condition#test must be overridden in subclasses")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Override this method in your Conditions (optional)
|
38
|
+
def after
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class EventCondition < Condition
|
43
|
+
def register
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|