cappy-monit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt ADDED
@@ -0,0 +1,13 @@
1
+ Manifest.txt
2
+ README.txt
3
+ Rakefile
4
+ lib/capistrano-monit
5
+ lib/capistrano-monit.rb
6
+ lib/capistrano-monit/monit_command_helper.rb
7
+ lib/capistrano-monit/monit_config_helper.rb
8
+ lib/capistrano-monit/recipes.rb
9
+ lib/capistrano-monit/templates
10
+ lib/capistrano-monit/templates/mongrel.erb
11
+ lib/capistrano-monit/templates/monit.erb
12
+ test/capistrano-monit_test.rb
13
+ test/monit_command_helper_test.rb
data/README.txt ADDED
@@ -0,0 +1,83 @@
1
+ = Capistrano Monit Tasks
2
+
3
+ This library extends Capistrano to configure and control a *monit* daemon running on application servers.
4
+ It replaces some of the standard tasks with monit versions and includes tasks and helpers to create monit configuration files.
5
+ See below for instructions on downloading and configuring monit itself.
6
+
7
+ == Quick Start for cappy-monit
8
+
9
+ This assumes you're creating a fresh application install, not migrating an app from
10
+ spinner/spawner/reaper. It also assumes you have setup monit as shown above.
11
+
12
+ Install the package via gems or .tgz / .zip and setup.rb.
13
+
14
+ Include it in your deploy.rb with:
15
+
16
+ require "capistrano-monit/recipes"
17
+
18
+ Place at least the following directives in your deploy recipe:
19
+
20
+ set :mongrel_address, "127.0.0.1"
21
+ set :mongrel_servers, 2
22
+ set :mongrel_environment, "production"
23
+ set :mongrel_port, 9000
24
+
25
+ Then run:
26
+
27
+ * cap cold_deploy
28
+
29
+ This sets up one mongrel listener on port 8000 by default. Make sure your database is setup
30
+ and point your webserver at the new listener.
31
+
32
+ Deployment will create a monit configuration file for the mongrel processes in the shared/ directory.
33
+ Monit should be automatically configured to include this file.
34
+
35
+ == Usage
36
+
37
+ Capistrano Monit uses the same configuration directives as the Railsmachine mongrel_cluster gem. This means that you have
38
+ to define the mongrel settings in your deployment recipe.
39
+
40
+ Coming soon.
41
+
42
+ == Getting and setting up monit
43
+
44
+ Monit is a single-server monitoring and alerting package with a clean, natural configuration language. It runs as
45
+ a daemon, which also responds as an HTTP server, to control processes and to display their status.
46
+
47
+ The latest version of monit lives at: http://www.tildeslash.com/monit/download
48
+ The monit manual is thorough and recommended reading: http://www.tildeslash.com/monit/doc/manual.php
49
+ There are no complicated dependencies. Many operating systems include monit in its default package repositories (Debian, FreeBSD, CentOS).
50
+
51
+ Here is what a minimal monitrc file might look like:
52
+
53
+ # poll every 2 minutes (required)
54
+ set daemon 120
55
+
56
+ # log to syslog
57
+ set logfile syslog facility log_daemon
58
+
59
+ # use the defined mail servers for alerts (required)
60
+ set mailserver mail.example.com, localhost
61
+
62
+ #
63
+ set alert alerts@example.com # send alerts to this email address
64
+
65
+ # run the http server (required) with the defined user:pass
66
+
67
+ set httpd port 2812 and
68
+ allow admin:admin
69
+
70
+ # setup basic system checks and alerts
71
+
72
+ check system app-server-1
73
+ if loadavg (1min) > 4 then alert
74
+ if loadavg (5min) > 2 then alert
75
+ if memory usage > 75% then alert
76
+ if cpu usage (user) > 70% then alert
77
+ if cpu usage (system) > 30% then alert
78
+ if cpu usage (wait) > 20% then alert
79
+
80
+
81
+ Place this file where you please (/etc/monit/monitrc for example). Running monit -c /etc/monit/monitrc should do the trick.
82
+ Some people prefer to run Monit directly from init. Please refer to the Monit manual for more information.
83
+
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require './lib/capistrano-monit'
4
+
5
+ # don't require hoe as a dependency to install this gem
6
+ class Hoe
7
+ def extra_deps
8
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
9
+ end
10
+ end
11
+
12
+ Hoe.new('cappy-monit', CapistranoMonitTasks::VERSION) do |p|
13
+ p.rubyforge_name = 'cappy-monit'
14
+ p.summary = 'Capistrano tasks for monitoring, controlling and configuring a remote monit instance.'
15
+ p.author = 'Joshua Sierles'
16
+ p.email = "joshua@diluvia.net"
17
+ p.url = "http://cappy-monit.rubyforge.org"
18
+ p.description = p.paragraphs_of('README.txt', 1..1).join("\n\n")
19
+ p.extra_deps = ["capistrano"]
20
+ end
@@ -0,0 +1,3 @@
1
+ class CapistranoMonitTasks
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,49 @@
1
+ begin
2
+ require 'capistrano'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'capistrano'
6
+ end
7
+
8
+ # This module creates Capistrano tasks for controlling processes monitored by monit
9
+ #
10
+ # Supported non-group commands are:
11
+ # * start, stop, restart, monitor, unmonitor
12
+ #
13
+ # Supported group commands:
14
+ # * start_group, stop_group, restart_group, monitor_group, unmonitor_group
15
+ #
16
+ # Providing 'all' as a non-group argument will affect all monitored services
17
+ #
18
+ # Usage examples:
19
+ #
20
+ # * <tt>monit.restart_group :mongrel_cluster</tt>
21
+ # * <tt>monit.restart 'lighttpd'</tt>
22
+ # * <tt>monit.stop ['mongrel-9000','mongrel-9001']</tt>
23
+ # * <tt>monit.unmonitor :all</tt>
24
+ ##
25
+ # The methods are available through monit.<method name> in your deploy.rb
26
+ #
27
+
28
+ module MonitCommandHelper
29
+ PROCESS_SIGNALS = %w(start stop restart monitor unmonitor)
30
+
31
+ PROCESS_SIGNALS.each do |command|
32
+ define_method(command) do |services|
33
+ if services.to_sym == :all
34
+ send(run_method, "monit #{command} all")
35
+ # TODO: confirm here whether the user really wants to restart ALL services
36
+ elsif services.is_a? Array
37
+ services.each {|serv| run "monit #{command} #{serv}" }
38
+ else
39
+ send(run_method, "monit #{command} #{services}")
40
+ end
41
+ end
42
+
43
+ define_method(command + "_group") do |serv|
44
+ send(run_method, "monit -g #{serv} #{command} all")
45
+ end
46
+ end
47
+ end
48
+
49
+ Capistrano.plugin :monit, MonitCommandHelper
@@ -0,0 +1,91 @@
1
+ begin
2
+ require 'capistrano'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'capistrano'
6
+ end
7
+
8
+ # This modules provides methods to create monitrc configuration files for various services
9
+ #
10
+ # The methods are available through monitrc.<method name> in your deploy.rb
11
+ #
12
+ # Currently you are required to manually modify your main monitrc file to include those generated by capistrano.
13
+ #
14
+ # An example include directive:
15
+ # * include "/home/myapp/config/monit/*.monitrc"
16
+ #
17
+ #
18
+ module MonitrcHelper
19
+ # Creates a monitrc file from a template, puts it on the server at the given
20
+ # path and sets file permissions to 0700.
21
+ #
22
+ # * template can be 'mongrel' or the name of a file or a string.
23
+ # 'mongrel' uses the standard mongrel templates provided with this package.
24
+ # See get_template below for a list of places searched for template files of your own.
25
+ #
26
+
27
+ def create(template, path, options = {})
28
+
29
+ template = template.to_s
30
+
31
+ options = add_default_options(options)
32
+
33
+ if template == 'mongrel'
34
+ config_data = mongrel_ports.collect {|port| render options.merge(:template => get_template(template), :port => port)}.join("\n\n")
35
+ else
36
+ config_data = render options.merge(:template => get_template(template))
37
+ end
38
+ put config_data, path, :mode => 0700
39
+
40
+ end
41
+
42
+ # Works out whether the given template is a file or string containing rhtml.
43
+ #
44
+ # Checks:
45
+ # * current directory
46
+ # * monitrc_templates path (defaults to templates/monit)
47
+ # * capistrano-monit-tasks-templates dir where cappy-monit is installed
48
+ # (the standard templates are here)
49
+ #
50
+ # If it can't find the file it assumes it's a one line string template and
51
+ # returns that
52
+ def get_template(template)
53
+ if template =~ /<%/ or template =~ /\n/
54
+ template
55
+ else
56
+ [ ".",
57
+ configuration.monitrc_template_path,
58
+ File.join(File.dirname(__FILE__), 'templates')
59
+ ].each do |dir|
60
+ if File.file?(File.join(dir, template))
61
+ return File.read(File.join(dir, template))
62
+ elsif File.file?(File.join(dir, template + ".erb"))
63
+ @file_template_full_path = File.join(dir, template + ".erb")
64
+ return File.read(File.join(dir, template + ".erb"))
65
+ end
66
+ end
67
+ end
68
+ template
69
+ end
70
+
71
+ protected
72
+ def add_default_options(options)
73
+ {:shared_path => configuration.shared_path,
74
+ :mongrel_pid_path => configuration.mongrel_pid_path,
75
+ :mongrel_path => configuration.mongrel_path,
76
+ :mongrel_user => configuration.mongrel_user,
77
+ :mongrel_group => configuration.mongrel_group,
78
+ :monitrc_path => configuration.monitrc_path,
79
+ :address => configuration.address,
80
+ :rails_env => configuration.rails_env,
81
+ :release_path => configuration.release_path,
82
+ :deploy_to => configuration.deploy_to
83
+ }.merge(options)
84
+ end
85
+
86
+ def mongrel_ports
87
+ (configuration.mongrel_port..configuration.mongrel_port + (configuration.mongrel_servers - 1)).to_a
88
+ end
89
+ end
90
+
91
+ Capistrano.plugin :monitrc, MonitrcHelper
@@ -0,0 +1,105 @@
1
+ require 'capistrano-monit/monit_command_helper'
2
+ require 'capistrano-monit/monit_config_helper'
3
+
4
+ Capistrano.configuration(:must_exist).load do
5
+
6
+ MONIT_SIGNALS = %w(status summary reload validate)
7
+
8
+ set :monit_http_port, 2812
9
+ set :monitrc_path, '/etc/monitrc'
10
+ set :mongrel_path, '/usr/local/bin/mongrel_rails'
11
+ set :mongrel_servers, 2
12
+ set :mongrel_port, 8000
13
+ set :config_type, 'mongrel'
14
+ set :address, "127.0.0.1"
15
+ set :cluster_group_name, Proc.new { "#{application}_mongrels"}
16
+ set :mongrel_pid_path, Proc.new { "#{shared_path}/log" }
17
+ set :mongrel_user, nil
18
+ set :mongrel_group, nil
19
+ set :mongrel_monitrc_path, Proc.new { "#{shared_path}/monit/#{config_type}.monitrc" }
20
+ set :monitrc_template_path, File.join('templates', 'monit')
21
+ set :use_sudo, true
22
+
23
+ desc <<-DESC
24
+ Create a monitrc file for the mongrel cluster and update the main monitrc. Obeys the :use_sudo directive (default is true).
25
+ DESC
26
+ task :configure_mongrel_cluster, :roles => :app do
27
+ run "mkdir -p #{shared_path}/monit"
28
+ monitrc.create 'mongrel', mongrel_monitrc_path
29
+ found_paths = capture("find /etc /usr/local/etc -name monitrc -o -name monit.conf 2>/dev/null || exit 0")
30
+ path = found_paths.split("\r\n").first
31
+ if path && path.length > 0
32
+ include_line = '"include '+mongrel_monitrc_path+'"'
33
+ command = "if ! sudo grep #{mongrel_monitrc_path} #{path} > /dev/null; then sudo sh -c 'echo #{include_line} >> #{path}'; fi"
34
+ run(command) do |channel, stream, data|
35
+ if data =~ /^Password:/
36
+ pass = readline("Sudo password:")
37
+ channel.send_data "#{pass}\n"
38
+ end
39
+ end
40
+
41
+ else
42
+ puts "Could not find a file named monitrc nor monit.conf in /etc nor /usr/local/etc. Please add this line to your monitrc file manually: \n"
43
+ puts "include #{mongrel_monitrc_path}"
44
+ end
45
+ monit_reload
46
+ end
47
+
48
+ desc <<-DESC
49
+ Start Mongrel processes on the app server using monit.
50
+ Obeys the :use_sudo directive (default is true).
51
+ Overrides equivalent task from the mongrel_cluster gem.
52
+ DESC
53
+ task :start_mongrel_cluster, :roles => :app do
54
+ monit.start_group cluster_group_name
55
+ end
56
+
57
+ desc <<-DESC
58
+ Restart the mongrel processes on the app server using monit.
59
+ Obeys the :use_sudo directive (default is true).
60
+ Overrides equivalent task from the mongrel_cluster gem.
61
+ DESC
62
+ task :restart_mongrel_cluster, :roles => :app do
63
+ monit.restart_group cluster_group_name
64
+ end
65
+
66
+ desc <<-DESC
67
+ Stop the mongrel processes on the app server using monit.
68
+ Obeys the :use_sudo directive (default is true).
69
+ Overrides equivalent task from the mongrel_cluster gem.
70
+ DESC
71
+ task :stop_mongrel_cluster, :roles => :app do
72
+ monit.stop_group cluster_group_name
73
+ end
74
+
75
+ desc <<-DESC
76
+ Restart the mongrel processes on the app servers - alias of :restart_mongrel_cluster
77
+ DESC
78
+ task :restart, :roles => :app do
79
+ restart_mongrel_cluster
80
+ end
81
+
82
+ desc <<-DESC
83
+ Start the Mongrel processes on the app servers - alias of :start_mongrel_cluster
84
+ DESC
85
+ task :spinner, :roles => :app do
86
+ configure_mongrel_cluster
87
+ start_mongrel_cluster
88
+ end
89
+
90
+ desc <<-DESC
91
+ Get the current status of the application server monit daemons.
92
+ DESC
93
+ task :monit_status, :roles => :app do
94
+ monit.status
95
+ end
96
+
97
+
98
+ MONIT_SIGNALS.each do |command|
99
+ desc "Run the monit '#{command}' on application servers"
100
+ task "monit_#{command}" do
101
+ send(run_method, "monit #{command}")
102
+ end
103
+ end
104
+
105
+ end
@@ -0,0 +1,11 @@
1
+ check process mongrel-<%= port %> with pidfile "<%= shared_path %>/log/mongrel.<%= port %>.pid"
2
+ start program = "<%= mongrel_path %> start -p <%= port %> -P <%= shared_path %>/log/mongrel.<%= port %>.pid -e <%= rails_env %> -a <%= address %> -c <%= deploy_to %>/current -d"
3
+ <% if mongrel_user and mongrel_group %>
4
+ as uid <%= mongrel_user %> and gid <%= mongrel_group %>
5
+ <% end %>
6
+ stop program = "<%= mongrel_path %> stop -p <%= shared_path %>/log/mongrel.<%= port %>.pid"
7
+ if mem > 200 Mb then alert
8
+ if cpu usage > 95% for 3 cycles then restart
9
+ if failed port <%= port %> protocol http with timeout 15 seconds then restart
10
+ if 2 restarts within 3 cycles then timeout
11
+ group <%= cluster_group_name %>
@@ -0,0 +1,14 @@
1
+ set daemon 120
2
+ set logfile syslog facility log_daemon
3
+ set mailserver mail.example.com, localhost
4
+ set alert alerts@example.com
5
+ set httpd port 2812 and
6
+ allow admin:pass
7
+
8
+ check system app-server
9
+ if loadavg (1min) > 4 then alert
10
+ if loadavg (5min) > 2 then alert
11
+ if memory usage > 75% then alert
12
+ if cpu usage (user) > 70% then alert
13
+ if cpu usage (system) > 30% then alert
14
+ if cpu usage (wait) > 20% then alert
@@ -0,0 +1,38 @@
1
+ $:.unshift File.dirname(__FILE__) + "/../lib"
2
+
3
+ require 'test/unit'
4
+ begin
5
+ require 'capistrano'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'capistrano'
9
+ end
10
+
11
+ class CapistranoRunitTasksConfigurationTest < Test::Unit::TestCase
12
+ class MockActor
13
+ attr_reader :tasks
14
+
15
+ def initialize(config)
16
+ end
17
+
18
+ def define_task(*args, &block)
19
+ (@tasks ||= []).push [args, block].flatten
20
+ end
21
+ end
22
+
23
+ def setup
24
+ @config = Capistrano::Configuration.new(MockActor)
25
+ file = File.dirname(__FILE__) + "/fixtures/monit_config.rb"
26
+ @config.load file
27
+ end
28
+
29
+ def test_should_include_capistrano_monit_tasks
30
+ assert task_names(@config.actor.tasks).include?(:configure_monit)
31
+ end
32
+
33
+ def task_names(tasks)
34
+ tasks.map { |task| task[0] }
35
+ end
36
+ end
37
+
38
+
@@ -0,0 +1,35 @@
1
+ $:.unshift File.dirname(__FILE__) + "/../lib/capistrano-monit", File.dirname(__FILE__)
2
+
3
+ require 'test/unit'
4
+ require 'test_helper'
5
+ require 'monit_command_helper'
6
+
7
+ class RunitRunnerHelperTest < Test::Unit::TestCase
8
+ include TestHelper
9
+
10
+ TEST_PROCESS_SIGNALS = %w(start stop restart monitor unmonitor)
11
+ TEST_MONIT_SIGNALS = %w(status summary reload validate)
12
+
13
+ def setup
14
+ @actor = TestActor.new(MockConfiguration.new)
15
+ end
16
+
17
+ def test_should_load_monit_runner_helper
18
+ assert Capistrano.const_get(:EXTENSIONS).include?(:monit)
19
+ end
20
+
21
+ def test_should_generate_correct_single_process_commands
22
+ TEST_PROCESS_SIGNALS.each_with_index do |signal, i|
23
+ @actor.monit.send(signal, "foo")
24
+ assert_equal "monit #{signal} foo", @actor.run_data[i]
25
+ end
26
+ end
27
+
28
+ def test_should_generate_correct_group_process_commands
29
+ TEST_PROCESS_SIGNALS.each_with_index do |signal, i|
30
+ @actor.monit.send(signal+"_group", "foo")
31
+ assert_equal "monit -g foo #{signal} all", @actor.run_data[i]
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'capistrano'
3
+
4
+ module TestHelper
5
+ class TestingConnectionFactory
6
+ def initialize(config)
7
+ end
8
+
9
+ def connect_to(server)
10
+ server
11
+ end
12
+ end
13
+
14
+ class TestActor < Capistrano::Actor
15
+ attr_reader :put_data, :run_data
16
+
17
+ def run(cmd, options={}, &block)
18
+ (@run_data ||= []) << cmd
19
+ end
20
+
21
+ def put(data, path, options={})
22
+ (@put_data ||= {})[path] = data
23
+ end
24
+
25
+ self.connection_factory = TestingConnectionFactory
26
+
27
+ def reset!
28
+ @put_data = {}
29
+ @run_data = []
30
+ end
31
+ end
32
+
33
+ class MockConfiguration
34
+ def initialize
35
+ @variables = {}
36
+ end
37
+
38
+ def set(variable, value = nil)
39
+ @variables[variable] = value
40
+ end
41
+
42
+ Role = Struct.new(:host, :options)
43
+
44
+ ROLES = {
45
+ :db => [ Role.new("01.example.com", :primary => true)],
46
+ :web => [ Role.new("01.example.com", {})],
47
+ :app => [ Role.new("01.example.com", {})]
48
+ }
49
+
50
+ def roles
51
+ ROLES
52
+ end
53
+
54
+ def method_missing(sym, *args, &block)
55
+ if @variables.has_key?(sym)
56
+ @variables[sym]
57
+ else
58
+ super
59
+ end
60
+ end
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: cappy-monit
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2007-03-28 00:00:00 +02:00
8
+ summary: Capistrano tasks for monitoring, controlling and configuring a remote monit instance.
9
+ require_paths:
10
+ - lib
11
+ email: joshua@diluvia.net
12
+ homepage: http://cappy-monit.rubyforge.org
13
+ rubyforge_project: cappy-monit
14
+ description: This library extends Capistrano to configure and control a *monit* daemon running on application servers. It replaces some of the standard tasks with monit versions and includes tasks and helpers to create monit configuration files. See below for instructions on downloading and configuring monit itself.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Joshua Sierles
31
+ files:
32
+ - Manifest.txt
33
+ - README.txt
34
+ - Rakefile
35
+ - lib/capistrano-monit
36
+ - lib/capistrano-monit.rb
37
+ - lib/capistrano-monit/monit_command_helper.rb
38
+ - lib/capistrano-monit/monit_config_helper.rb
39
+ - lib/capistrano-monit/recipes.rb
40
+ - lib/capistrano-monit/templates
41
+ - lib/capistrano-monit/templates/mongrel.erb
42
+ - lib/capistrano-monit/templates/monit.erb
43
+ - test/capistrano-monit_test.rb
44
+ - test/monit_command_helper_test.rb
45
+ test_files:
46
+ - test/test_helper.rb
47
+ rdoc_options: []
48
+
49
+ extra_rdoc_files: []
50
+
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ requirements: []
56
+
57
+ dependencies:
58
+ - !ruby/object:Gem::Dependency
59
+ name: capistrano
60
+ version_requirement:
61
+ version_requirements: !ruby/object:Gem::Version::Requirement
62
+ requirements:
63
+ - - ">"
64
+ - !ruby/object:Gem::Version
65
+ version: 0.0.0
66
+ version: