capistrano-boss 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2009-2010 Andrew Carter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,164 @@
1
+ = capistrano-boss
2
+
3
+ Collection of extensions for managing Rails projects via Capistrano in production environments.
4
+
5
+ These recipes are extracted from two years of running Ruby on Rails projects in production environments.
6
+
7
+ ---
8
+
9
+ == Installation
10
+
11
+ Install the gem:
12
+
13
+ sudo gem install capistrano-boss
14
+
15
+
16
+ Capify a project:
17
+
18
+ rails test
19
+ cd test
20
+ capify .
21
+
22
+ Capbossify to add the extensions:
23
+
24
+ capbossify .
25
+
26
+ The Capfile will be extended to include the capistrano-boss recipes.
27
+
28
+ ---
29
+
30
+ == Usage
31
+
32
+ Once _capbossify_ has been used on a project, the recipes will be added to the list of available recipes.
33
+
34
+ ---
35
+
36
+ == Recipes
37
+
38
+ The capistrano-boss recipes are split into several namespaces.
39
+
40
+ === Deploy
41
+
42
+ One extra recipe is added for SSH key management:
43
+
44
+ cap deploy:authorized_keys # Upload authorized_keys file.
45
+
46
+ This task uploads an *authorized_keys* file to the cap user +.ssh/authorized_keys+ location. Keyfile is expected to be +authorized_keys+ or set the environment variable +keys+:
47
+
48
+ cap deploy:authorized_keys keys=my_auth_keys
49
+
50
+ === Apache
51
+
52
+ The set of apache recipes are for using the standard apachectl options as well as some convenience recipes for handling logs.
53
+
54
+ cap apache:graceful # Graceful Apache web service
55
+ cap apache:graceful_stop # Graceful-stop Apache web service
56
+ cap apache:log:fetch # Download Apache httpd logs
57
+ cap apache:log:tail # Tail Apache httpd logs
58
+ cap apache:log:watch # Watch Apache httpd logs
59
+ cap apache:restart # Restart Apache web service
60
+ cap apache:start # Start Apache web service
61
+ cap apache:stop # Stop Apache web service
62
+
63
+ By default, the variable +apache_logs+ is set to an array that includes the error and access log from the default location for Red Hat. Override with the location of the logs or to add custom logs.
64
+
65
+ The control tasks use +apachectl+ variable to determine the select the HTTP server control interface.
66
+
67
+ ===== apache:log:fetch
68
+
69
+ Copies log files to +./log/deploy/RAILS_ENV/TIMESTAMP/HOST-LOGFILENAME.log+.
70
+
71
+ ===== apache:log:tail
72
+
73
+ Tail last n lines of the log files by host. Set environment variable +lines+ to set number of lines.
74
+
75
+ cap apache:log:tail lines=50
76
+
77
+ ===== apache:log:watch
78
+
79
+ Running tail of all the log files with a host and timestamp for each line. Useful to watch all the logs in real-time.
80
+
81
+ === Passenger
82
+
83
+ Simple task to restart a Passenger managed application. This recipe is an alias for the +touch+ +tmp/restart.txt+ method. It makes other tasks that want to restart the app more readable.
84
+
85
+ cap passenger:restart # Restart Rails application
86
+
87
+ === Rails
88
+
89
+ The Rails set of recipes help with configuration and monitoring.
90
+
91
+ cap rails:about # About Rails environment
92
+ cap rails:config # Generate Rails configuration
93
+ cap rails:config:database # Create a database.yml file in shared con...
94
+ cap rails:deploy:config # Deploy Rails configuration files
95
+ cap rails:deploy:snapshot_database # Snapshot database.
96
+ cap rails:log:fetch # Download Rails application log
97
+ cap rails:log:tail # Tail Rails application log
98
+ cap rails:log:watch # Watch Rails application log
99
+
100
+ If the application is not rails, set the variable +rails_disable+ to true in the +./config/deploy.rb+ file to disable all the Rails recipes:
101
+
102
+ set :rails_disable, false
103
+
104
+ ===== rails:config
105
+
106
+ Meta recipe that runs all the config tasks. Useful when initializing a new environment (when using the capistrano-ext multistage extension for example). Creates a +SHARED_PATH/config+ directory for config files that don't change for each deploy.
107
+
108
+ ===== rails:config:database
109
+
110
+ Generate +SHARED_PATH/config/database.yml+ file. It will prompt for the database password if not provided. This method allows for writing the config file into a production environment without checking in the database password. Set +db_*+ variables to write the environment section in the database.yml file. Defaults are valid for MySQL with database default of +USER_RAILS_ENV+.
111
+
112
+ ===== rails:deploy:config
113
+
114
+ Symlink +SHARED_PATH/config/database.yml+ to +CURRENT_PATH/config/database.yml+. Used for deploys to utilize the shared database config.
115
+
116
+ ===== rails:deploy:snapshot_database
117
+
118
+ Run a MySQL dump to the location specified by environment variable +dbpath+. Default location is +SHARED_PATH/backup/db/DATABASE_TIMESTAMP.sql.gz+.
119
+
120
+ cap rails:deploy:snapshot_database dbpath=/var/backup/db
121
+
122
+ ===== rails:log:fetch
123
+
124
+ Copies RAILS_ENV.log file to +./log/deploy/RAILS_ENV/TIMESTAMP/HOST-RAILS_ENV.log+
125
+
126
+ ===== rails:log:tail
127
+
128
+ Tail last n lines of the log files by host. Set environment variable +lines+ to set number of lines.
129
+
130
+ cap rails:log:tail lines=50
131
+
132
+ ===== rails:log:watch
133
+
134
+ Running tail of all the log files with a host and timestamp for each line. Useful to watch all the logs in real-time.
135
+
136
+ === Subversion
137
+
138
+ Support for the subversion scm has been extended to include +branch+ and +tag+ variables. If either variable is set, the repository path is adjusted to take the tag or branch into account. The default is to use +trunk+. The repository should be the base URL without trunk/branches/tags. Also, it assumes a standard subversion layout:
139
+
140
+ project/
141
+ branches/
142
+ tags/
143
+ trunk/
144
+
145
+ Examples:
146
+
147
+ ==== trunk
148
+ set :repository, '/path/to/svn/root/project'
149
+ => Repository is /path/to/svn/root/project/trunk at runtime
150
+
151
+ ==== branch
152
+ set :repository, '/path/to/svn/root/project'
153
+ set :branch, 'mybranch'
154
+ => Repository is /path/to/svn/root/project/branches/mybranch
155
+
156
+ ==== tag
157
+ set :repository, '/path/to/svn/root/project'
158
+ set :tag, 'mytag'
159
+ => Repository is /path/to/svn/root/project/tags/mytag
160
+
161
+ == Copyright
162
+
163
+ Copyright (c) 2009-2010 Andrew Carter. See LICENSE for details.
164
+
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "capistrano-boss"
8
+ gem.summary = %Q{Capistrano extensions for configuring, provisioning, and management}
9
+ gem.description = %Q{Collection of capistrano extensions focused on configuration, provisioning, and management.}
10
+ gem.email = "ascarter@gmail.com"
11
+ gem.homepage = "http://github.com/ascarter/capistrano-boss"
12
+ gem.authors = ["Andrew Carter"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "capistrano-boss #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'fileutils'
5
+
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: #{File.basename($0)} [path]"
8
+
9
+ opts.on("-h", "--help", "Displays this help info") do
10
+ puts opts
11
+ exit 0
12
+ end
13
+
14
+ begin
15
+ opts.parse!(ARGV)
16
+ rescue OptionParser::ParseError => e
17
+ warn e.message
18
+ puts opts
19
+ exit 1
20
+ end
21
+ end
22
+
23
+ if ARGV.empty?
24
+ abort "Please specify the directory to capbossify, e.g. `#{File.basename($0)} .'"
25
+ elsif !File.exists?(ARGV.first)
26
+ abort "`#{ARGV.first}' does not exist."
27
+ elsif !File.directory?(ARGV.first)
28
+ abort "`#{ARGV.first}' is not a directory."
29
+ elsif ARGV.length > 1
30
+ abort "Too many arguments; please specify only the directory to capbossify."
31
+ end
32
+
33
+ base = ARGV.shift
34
+ capfile = File.join(base, "Capfile")
35
+ if !File.exists?(capfile)
36
+ abort "Please run capify on directory before using capbossify"
37
+ end
38
+
39
+ contents = File.readlines(capfile)
40
+ begin
41
+ capboss_require = "require 'capistrano-boss'\n"
42
+ contents.each { |line| raise Exception.exception("'#{capfile}' already capbossified") if line == capboss_require }
43
+ out = File.open(capfile, "w")
44
+ contents.each do |line|
45
+ out << line
46
+ if line =~ /^load \'deploy\' if respond_to\?\(\:namespace\)/
47
+ puts "[add] adding capistrano-boss require"
48
+ out << capboss_require
49
+ end
50
+ end
51
+ out.close
52
+ rescue Exception => ex
53
+ warn "[skip] #{ex.message}"
54
+ end
55
+
56
+ puts "[done] capbossified!"
@@ -0,0 +1,68 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{capistrano-boss}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andrew Carter"]
12
+ s.date = %q{2010-01-27}
13
+ s.default_executable = %q{capbossify}
14
+ s.description = %q{Collection of capistrano extensions focused on configuration, provisioning, and management.}
15
+ s.email = %q{ascarter@gmail.com}
16
+ s.executables = ["capbossify"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/capbossify",
29
+ "capistrano-boss.gemspec",
30
+ "lib/capistrano-boss.rb",
31
+ "lib/capistrano_boss/channel.rb",
32
+ "lib/capistrano_boss/database.rb",
33
+ "lib/capistrano_boss/database/mysql.rb",
34
+ "lib/capistrano_boss/extensions.rb",
35
+ "lib/capistrano_boss/extensions/subversion.rb",
36
+ "lib/capistrano_boss/log.rb",
37
+ "lib/recipes/apache.rb",
38
+ "lib/recipes/deploy.rb",
39
+ "lib/recipes/passenger.rb",
40
+ "lib/recipes/rails.rb",
41
+ "spec/capistrano-boss_spec.rb",
42
+ "spec/spec.opts",
43
+ "spec/spec_helper.rb"
44
+ ]
45
+ s.homepage = %q{http://github.com/ascarter/capistrano-boss}
46
+ s.rdoc_options = ["--charset=UTF-8"]
47
+ s.require_paths = ["lib"]
48
+ s.rubygems_version = %q{1.3.5}
49
+ s.summary = %q{Capistrano extensions for configuring, provisioning, and management}
50
+ s.test_files = [
51
+ "spec/capistrano-boss_spec.rb",
52
+ "spec/spec_helper.rb"
53
+ ]
54
+
55
+ if s.respond_to? :specification_version then
56
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
60
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
61
+ else
62
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
63
+ end
64
+ else
65
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
+ end
67
+ end
68
+
@@ -0,0 +1,21 @@
1
+ #require 'capistrano/recipes/deploy/scm/subversion'
2
+ require 'capistrano_boss/extensions'
3
+ require 'capistrano_boss/database'
4
+ require 'capistrano_boss/channel'
5
+ require 'capistrano_boss/log'
6
+
7
+ # Include extensions
8
+ include CapistranoBoss::Log, CapistranoBoss::Channel, CapistranoBoss::Database
9
+
10
+ Capistrano::Configuration.instance.load do
11
+ Dir[File.join(File.dirname(__FILE__), "recipes", "*.rb")].each { |plugin| load(plugin) }
12
+ end
13
+
14
+ module CapistranoBoss
15
+ # Standardized timestamp
16
+ # Example:
17
+ # 200912241432
18
+ def self.timestamp
19
+ Time.now.strftime("%Y%m%d%H%M")
20
+ end
21
+ end
@@ -0,0 +1,69 @@
1
+ module CapistranoBoss
2
+ module Channel
3
+ # Execute command using sudo and collect output in hash
4
+ # keyed by channel
5
+ def sudo_by_channel(command)
6
+ exec_by_channel(command, :sudo)
7
+ end
8
+
9
+ # Execute command using run and collect output in hash
10
+ # keyed by channel
11
+ def run_by_channel(command)
12
+ exec_by_channel(command, :run)
13
+ end
14
+
15
+ # Print channel output data to destination file stream
16
+ def print_channel(channel, data, file = $stdout)
17
+ file.puts
18
+ file.puts "--- #{channel[:host]} | #{Time.now.to_s} ---"
19
+ file.puts "#{data}"
20
+ file.puts
21
+ end
22
+
23
+ def print_buffered_channel(output, file = $stdout)
24
+ output.sort.each do |channel, data|
25
+ unless file == $stdout
26
+ file.puts "Method: #{context.to_s}"
27
+ file.puts "Command: #{command}"
28
+ end
29
+ file.puts
30
+ file.puts "--- #{channel} ---"
31
+ file.puts "#{data}"
32
+ file.puts
33
+ end
34
+ end
35
+
36
+ # Execute command on each channel and collect output in hash
37
+ # keyed by channel
38
+ #
39
+ # Execution contexts:
40
+ # run::
41
+ # Using run method
42
+ # sudo::
43
+ # Using sudo method
44
+ #
45
+ # Stream::
46
+ # Stream results back immediately (true)
47
+ # Buffer results and print on completion (false)
48
+ #
49
+ # File::
50
+ # Any valid stream object to capture output
51
+ def exec_by_channel(command, context = :run, stream = false, file = $stdout)
52
+ output = {}
53
+
54
+ # Run command on each channel and collect the results
55
+ send(context, command, :pty => true) do |channel, stream, data|
56
+ if stream
57
+ print_channel(channel, data, file)
58
+ else
59
+ key = channel[:host].to_s
60
+ output[key] = "" unless output.has_key?(key)
61
+ output[key] << data
62
+ end
63
+ break if stream == :err
64
+ end
65
+
66
+ print_buffered_channel(output, file) unless stream
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,53 @@
1
+ require 'capistrano_boss/database/mysql.rb'
2
+ # require 'capistrano_boss/database/sqlite.rb'
3
+ # require 'capistrano_boss/database/postgresql.rb'
4
+
5
+ require 'yaml'
6
+
7
+ module CapistranoBoss
8
+ module Database
9
+ # Load adapter module
10
+ def self.load_adapter(config)
11
+ case config['adapter']
12
+ when "mysql"
13
+ adapter = MySQL.new(config)
14
+ else
15
+ abort "Unsupported database adapter: #{config['adapter']}"
16
+ end
17
+
18
+ return adapter
19
+ end
20
+
21
+ # Load database.yml and return configuration for current Rails environment
22
+ def read_database_yml
23
+ database_yml = {}
24
+ run "cat #{current_path}/config/database.yml" do |channel, stream, data|
25
+ database_yml = YAML.load(data)
26
+ end
27
+
28
+ unless database_yml.has_key?(rails_env)
29
+ abort "Missing configuration for #{rails_env}"
30
+ end
31
+
32
+ # Return config for current environment
33
+ database_yml[rails_env]
34
+ end
35
+
36
+ # Run query and stream results back
37
+ def query(sql)
38
+ config = read_database_yml
39
+ adapter = CapistranoBoss::Database.load_adapter(config)
40
+ run "#{adapter.query(sql)}"
41
+ end
42
+
43
+ # Create a snapshot of database to remote path
44
+ def dump(db_path)
45
+ config = read_database_yml
46
+ adapter = CapistranoBoss::Database.load_adapter(config)
47
+ snapshot_file = "#{adapter.option(:database)}_#{CapistranoBoss.timestamp}.sql.gz"
48
+ run "mkdir -p #{db_path}; #{adapter.dump} | gzip > #{db_path}/#{snapshot_file}"
49
+ end
50
+
51
+ end
52
+ end
53
+
@@ -0,0 +1,54 @@
1
+ module CapistranoBoss
2
+ module Database
3
+ class MySQL
4
+ def initialize(options = {})
5
+ self.options = options
6
+ end
7
+
8
+ def options
9
+ @options
10
+ end
11
+
12
+ def option(key)
13
+ self.options[key.to_s]
14
+ end
15
+
16
+ def options=(options)
17
+ @options = options
18
+ end
19
+
20
+ def set(option, value)
21
+ self.options[option.to_s] = value
22
+ end
23
+
24
+ def query(sql)
25
+ command_line("mysql") << " -e \"#{sql}\""
26
+ end
27
+
28
+ def dump
29
+ command_line("mysqldump --no-create-db ")
30
+ end
31
+
32
+ private
33
+
34
+ def command_line(command)
35
+ args = []
36
+ args << "-u #{options['username']}" if options.has_key?('username')
37
+ args << "-p#{options['password']}" if options.has_key?('password')
38
+ args << "-h #{options['host']}" if options.has_key?('host')
39
+ args << "--default-character-set=#{options['encoding']}" if options.has_key?('encoding')
40
+ args << "-P #{options['port']}" if options.has_key?('port')
41
+ args << "-S #{options['socket']}" if options.has_key?('socket')
42
+ args << "--ssl-key=#{options['sslkey']}" if options.has_key?('sslkey')
43
+ args << "--ssl-cert=#{options['sslcert']}" if options.has_key?('sslcert')
44
+ args << "--ssl-capath=#{options['sslpath']}" if options.has_key?('sslpath')
45
+ args << "--ssl-cipher=#{options['sslcipher']}" if options.has_key?('sslcipher')
46
+ args << "--unbuffered" if options.has_key?('unbuffered')
47
+ args << "#{options['database']}" if options.has_key?('database')
48
+
49
+ "#{command} #{args.join(' ')}"
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,2 @@
1
+ require 'capistrano_boss/extensions/subversion'
2
+
@@ -0,0 +1,25 @@
1
+ require 'capistrano/recipes/deploy/scm/base'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module SCM
6
+ class Subversion < Base
7
+ # Returns working subversion repository path
8
+ # Defaults to trunk
9
+ # If variable :tag or :branch are set, path is adjusted
10
+ # Repository path should refer to root of standard svn layout
11
+ def repository
12
+ if variable(:svn_explicit_path)
13
+ variable(:repository)
14
+ elsif variable(:tag)
15
+ "#{variable(:repository)}/tags/#{variable(:tag)}"
16
+ elsif variable(:branch)
17
+ "#{variable(:repository)}/branches/#{variable(:branch)}"
18
+ else
19
+ "#{variable(:repository)}/trunk"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ module CapistranoBoss
2
+ module Log
3
+ def source_logs(input)
4
+ input.is_a?(Array) ? input : [ input ]
5
+ end
6
+
7
+ # Download log to destination/<timestamp>
8
+ def fetch_log(input, destination = ".")
9
+ target_dir = File.join(destination, rails_env, CapistranoBoss::timestamp)
10
+ FileUtils.mkdir_p(target_dir)
11
+ source_logs(input).each do |s|
12
+ download s, "#{target_dir}/$CAPISTRANO:HOST$-#{File.basename(s)}"
13
+ end
14
+ end
15
+
16
+ # Tail log and output by channel
17
+ def tail_log(input, context = :run)
18
+ nlines = ENV['lines'].nil? ? "10" : ENV['lines']
19
+ cmd = "tail -n #{nlines} #{source_logs(input).join(' ')}"
20
+ exec_by_channel(cmd, context)
21
+ end
22
+
23
+ # Watch log and stream by channel
24
+ def watch_log(input, context = :run)
25
+ cmd = "tail -f #{source_logs(input).join(' ')}"
26
+ exec_by_channel(cmd, context, true)
27
+ end
28
+
29
+ # Pretty print a stats hash.
30
+ # Expects::
31
+ # { "host" => { "key1" => value, "key2" => value } }
32
+ def dump_stats(stats)
33
+ stats.each do |host, values|
34
+ puts "-" * 40
35
+ puts "#{host}"
36
+ puts "-" * 40
37
+ values.sort.each {|k,v| puts " #{k} => #{v}" }
38
+ end
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,55 @@
1
+ namespace :apache do
2
+ set :apachectl, 'apachectl'
3
+ set :apachectl_options, '-k'
4
+ set :apache_logs, ['/var/log/httpd/error_log', '/var/log/httpd/access_log']
5
+
6
+ desc "Start Apache web service"
7
+ task :start, :roles => :app do
8
+ apachectl_cmd("start")
9
+ end
10
+
11
+ desc "Stop Apache web service"
12
+ task :stop, :roles => :app do
13
+ apachectl_cmd("stop")
14
+ end
15
+
16
+ desc "Restart Apache web service"
17
+ task :restart, :roles => :app do
18
+ apachectl_cmd("restart")
19
+ end
20
+
21
+ desc "Graceful Apache web service"
22
+ task :graceful, :roles => :app do
23
+ apachectl_cmd("graceful")
24
+ end
25
+
26
+ desc "Graceful-stop Apache web service"
27
+ task :graceful_stop, :roles => :app do
28
+ apachectl_cmd("graceful-stop")
29
+ end
30
+
31
+ namespace :log do
32
+ desc "Download Apache httpd logs"
33
+ task :fetch, :roles => :app do
34
+ dest = ENV['destination'] || File.join('log', 'deploy')
35
+ fetch_log(apache_log_files, dest)
36
+ end
37
+
38
+ desc "Tail Apache httpd logs"
39
+ task :tail, :roles => :app do
40
+ tail_log(apache_logs, :sudo)
41
+ end
42
+
43
+ desc "Watch Apache httpd logs"
44
+ task :watch, :roles => :app do
45
+ watch_log(apache_logs, :sudo)
46
+ end
47
+ end
48
+
49
+ # Helpers
50
+
51
+ def apachectl_cmd(action)
52
+ sudo "#{apachectl} #{apachectl_options} #{action}", :pty => true
53
+ end
54
+ end
55
+
@@ -0,0 +1,13 @@
1
+ namespace :deploy do
2
+ desc "Upload authorized_keys file. Specify file by setting keys=<path>"
3
+ task :authorized_keys do
4
+ keyfile = ENV['keys'] || "authorized_keys"
5
+ unless File.exist?(keyfile)
6
+ abort "Missing authorized_keys file at #{keyfile}"
7
+ end
8
+ run "mkdir -p -m 700 .ssh"
9
+ run "if [ -e .ssh/authorized_keys ]; then cp .ssh/authorized_keys .ssh/authorized_keys.#{CapistranoBoss.timestamp}; fi;"
10
+ put File.new(keyfile).read, ".ssh/authorized_keys", :mode => 0600
11
+ end
12
+ end
13
+
@@ -0,0 +1,6 @@
1
+ namespace :passenger do
2
+ desc "Restart Rails application"
3
+ task :restart, :roles => :app do
4
+ run "touch #{current_release}/tmp/restart.txt"
5
+ end
6
+ end
@@ -0,0 +1,93 @@
1
+ namespace :rails do
2
+ after "deploy:setup", "rails:config"
3
+ after "deploy:update_code", "rails:deploy:config"
4
+
5
+ desc "About Rails environment"
6
+ task :about do
7
+ run "RAILS_ENV=#{rails_env} #{current_path}/script/about "
8
+ end
9
+
10
+ namespace :config do
11
+ desc "Generate Rails configuration"
12
+ task :default, :roles => :app do
13
+ run "mkdir -p #{shared_path}/config"
14
+ rails::config::database unless disabled?(:database)
15
+ end
16
+
17
+ desc "Create a database.yml file in shared configuration"
18
+ task :database, :roles => :app do
19
+
20
+ # Set required fields
21
+ set(:db_adapter, "mysql") unless exists?(:db_adapter)
22
+ set(:db_username, user) unless exists?(:db_username)
23
+ set(:db_database, "#{user}_#{rails_env}") unless exists?(:db_database)
24
+ unless exists?(:db_password)
25
+ set(:db_password) { Capistrano::CLI.password_prompt("#{rails_env} #{db_adapter} password: ") }
26
+ end
27
+
28
+ # Create database config
29
+ db_config = {
30
+ "#{rails_env}" => {
31
+ "adapter" => db_adapter,
32
+ "database" => db_database,
33
+ "username" => db_username,
34
+ "password" => db_password
35
+ }
36
+ }
37
+
38
+ # Add any optional overrides
39
+ %w[host port socket encoding sslkey sslcert sslcapath sslcipher pool].each do |attribute|
40
+ varname = "db_#{attribute}".to_sym
41
+ if exists?(varname)
42
+ db_config["#{rails_env}"][attribute] = fetch(varname)
43
+ end
44
+ end
45
+
46
+ # Write config file to shared/config/database.yml
47
+ put(db_config.to_yaml, "#{shared_path}/config/database.yml")
48
+ end
49
+ end
50
+
51
+ namespace :deploy do
52
+ desc "Deploy Rails configuration files"
53
+ task :config, :roles => :app do
54
+ source = "#{shared_path}/config/database.yml"
55
+ dest = "#{release_path}/config/database.yml"
56
+ run "if [ -e \"#{source}\" ]; then cp #{source} #{dest}; fi"
57
+ end
58
+
59
+ desc "Snapshot database. Snapshot location specified by dbpath=<path>"
60
+ task :snapshot_database, :roles => :db do
61
+ db_path = ENV['dbpath'] || "#{shared_path}/backup/db"
62
+ dump(db_path)
63
+ end
64
+ end
65
+
66
+ namespace :log do
67
+ desc "Download Rails application log"
68
+ task :fetch, :roles => :app do
69
+ source = "#{shared_path}/log/#{rails_env}.log"
70
+ dest = ENV['destination'] || File.join('log', 'deploy')
71
+ fetch_log source, dest
72
+ end
73
+
74
+ desc "Tail Rails application log"
75
+ task :tail, :roles => :app do
76
+ tail_log "#{shared_path}/log/#{rails_env}.log"
77
+ end
78
+
79
+ desc "Watch Rails application log"
80
+ task :watch, :roles => :app do
81
+ watch_log "#{shared_path}/log/#{rails_env}.log"
82
+ end
83
+ end
84
+
85
+ #
86
+ # Helper methods
87
+ #
88
+
89
+ def disabled?(key)
90
+ exists?(:rails_disable) ? rails_disable.include?(key.to_sym) : false
91
+ end
92
+
93
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "CapistranoBoss" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'capistrano-boss'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-boss
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Carter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-27 00:00:00 -08:00
13
+ default_executable: capbossify
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ description: Collection of capistrano extensions focused on configuration, provisioning, and management.
26
+ email: ascarter@gmail.com
27
+ executables:
28
+ - capbossify
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - bin/capbossify
42
+ - capistrano-boss.gemspec
43
+ - lib/capistrano-boss.rb
44
+ - lib/capistrano_boss/channel.rb
45
+ - lib/capistrano_boss/database.rb
46
+ - lib/capistrano_boss/database/mysql.rb
47
+ - lib/capistrano_boss/extensions.rb
48
+ - lib/capistrano_boss/extensions/subversion.rb
49
+ - lib/capistrano_boss/log.rb
50
+ - lib/recipes/apache.rb
51
+ - lib/recipes/deploy.rb
52
+ - lib/recipes/passenger.rb
53
+ - lib/recipes/rails.rb
54
+ - spec/capistrano-boss_spec.rb
55
+ - spec/spec.opts
56
+ - spec/spec_helper.rb
57
+ has_rdoc: true
58
+ homepage: http://github.com/ascarter/capistrano-boss
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --charset=UTF-8
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.3.5
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Capistrano extensions for configuring, provisioning, and management
85
+ test_files:
86
+ - spec/capistrano-boss_spec.rb
87
+ - spec/spec_helper.rb