god 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ == 1.0.0 / 2007-06-11
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
5
+
@@ -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
@@ -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.
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,13 @@
1
+ module God
2
+
3
+ class Base
4
+ def abort(msg)
5
+ Kernel.abort(msg)
6
+ end
7
+
8
+ def self.abort(msg)
9
+ Kernel.abort(msg)
10
+ end
11
+ end
12
+
13
+ end
@@ -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
@@ -0,0 +1,11 @@
1
+ module God
2
+ module Conditions
3
+
4
+ class Always < PollCondition
5
+ def test
6
+ false
7
+ end
8
+ end
9
+
10
+ end
11
+ end