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.
@@ -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