capistrano-kitchen 0.0.0.pre
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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.ruby-gemset.template +1 -0
- data/.ruby-version.template +1 -0
- data/.travis.yml +7 -0
- data/.yardopts +5 -0
- data/Gemfile +8 -0
- data/Guardfile +13 -0
- data/LICENSE.txt +46 -0
- data/Rakefile +14 -0
- data/capistrano-kitchen.gemspec +29 -0
- data/lib/capistrano-kitchen.rb +41 -0
- data/lib/capistrano_kitchen/dishes/aptitude/manage.rb +38 -0
- data/lib/capistrano_kitchen/dishes/bundler/hooks.rb +7 -0
- data/lib/capistrano_kitchen/dishes/bundler/install.rb +79 -0
- data/lib/capistrano_kitchen/dishes/git/hooks.rb +3 -0
- data/lib/capistrano_kitchen/dishes/git/install.rb +18 -0
- data/lib/capistrano_kitchen/dishes/java_7_oracle/hooks.rb +5 -0
- data/lib/capistrano_kitchen/dishes/java_7_oracle/install.rb +17 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/app.conf +66 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/hooks.rb +11 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/install.rb +176 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/manage.rb +1 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/mime.types.erb +79 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/nginx.conf +138 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/nginx_unicorn.god +47 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/nginx_unicorn.init +95 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/nginx_unicorn.logrotate +18 -0
- data/lib/capistrano_kitchen/dishes/nginx_unicorn/stub_status.conf +16 -0
- data/lib/capistrano_kitchen/dishes/nodejs/hooks.rb +4 -0
- data/lib/capistrano_kitchen/dishes/nodejs/install.rb +13 -0
- data/lib/capistrano_kitchen/dishes/provision/empty_roles.rb +60 -0
- data/lib/capistrano_kitchen/dishes/provision/manage.rb +49 -0
- data/lib/capistrano_kitchen/dishes/provision/task_once.rb +62 -0
- data/lib/capistrano_kitchen/dishes/ruby/hooks.rb +7 -0
- data/lib/capistrano_kitchen/dishes/ruby/install.rb +55 -0
- data/lib/capistrano_kitchen/dishes/teelogger/teelogger.rb +121 -0
- data/lib/capistrano_kitchen/dishes/unicorn/hooks.rb +9 -0
- data/lib/capistrano_kitchen/dishes/unicorn/install.rb +120 -0
- data/lib/capistrano_kitchen/dishes/unicorn/unicorn.god +71 -0
- data/lib/capistrano_kitchen/dishes/unicorn/unicorn.rb.erb +191 -0
- data/lib/capistrano_kitchen/recipes/aptitude.rb +1 -0
- data/lib/capistrano_kitchen/recipes/bundler.rb +1 -0
- data/lib/capistrano_kitchen/recipes/git.rb +1 -0
- data/lib/capistrano_kitchen/recipes/java_7_oracle.rb +1 -0
- data/lib/capistrano_kitchen/recipes/nginx_unicorn.rb +1 -0
- data/lib/capistrano_kitchen/recipes/nodejs.rb +1 -0
- data/lib/capistrano_kitchen/recipes/provision.rb +1 -0
- data/lib/capistrano_kitchen/recipes/ruby.rb +1 -0
- data/lib/capistrano_kitchen/recipes/teelogger.rb +1 -0
- data/lib/capistrano_kitchen/recipes/unicorn.rb +1 -0
- data/lib/capistrano_kitchen/recipes/utilities.rb +442 -0
- data/lib/capistrano_kitchen/version.rb +3 -0
- data/spec/capistrano_kitchen_spec.rb +5 -0
- data/spec/spec_helper.rb +21 -0
- metadata +200 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
|
3
|
+
### BEGIN INIT INFO
|
4
|
+
# Provides: nginx
|
5
|
+
# Required-Start: $local_fs $remote_fs $network $syslog
|
6
|
+
# Required-Stop: $local_fs $remote_fs $network $syslog
|
7
|
+
# Default-Start: 2 3 4 5
|
8
|
+
# Default-Stop: 0 1 6
|
9
|
+
# Short-Description: starts the nginx web server
|
10
|
+
# Description: starts nginx using start-stop-daemon
|
11
|
+
### END INIT INFO
|
12
|
+
|
13
|
+
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
14
|
+
DAEMON=<%=nginx_unicorn_sbin_file%>
|
15
|
+
DAEMON_OPTS="-c <%="#{nginx_unicorn_conf_dir}/nginx.conf"%>"
|
16
|
+
NAME=<%=nginx_unicorn_init_d%>
|
17
|
+
DESC=<%=nginx_unicorn_init_d%>
|
18
|
+
PID=<%=nginx_unicorn_pid_file%>
|
19
|
+
|
20
|
+
test -x $DAEMON || exit 0
|
21
|
+
|
22
|
+
# Include nginx defaults if available
|
23
|
+
if [ -f /etc/default/nginx ] ; then
|
24
|
+
. /etc/default/nginx
|
25
|
+
fi
|
26
|
+
|
27
|
+
set -e
|
28
|
+
|
29
|
+
. /lib/lsb/init-functions
|
30
|
+
|
31
|
+
test_nginx_config() {
|
32
|
+
if $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1
|
33
|
+
then
|
34
|
+
return 0
|
35
|
+
else
|
36
|
+
$DAEMON -t $DAEMON_OPTS
|
37
|
+
return $?
|
38
|
+
fi
|
39
|
+
}
|
40
|
+
|
41
|
+
case "$1" in
|
42
|
+
start)
|
43
|
+
echo -n "Starting $DESC: "
|
44
|
+
test_nginx_config
|
45
|
+
start-stop-daemon --start --quiet --pidfile $PID \
|
46
|
+
--exec $DAEMON -- $DAEMON_OPTS || true
|
47
|
+
echo "$NAME."
|
48
|
+
;;
|
49
|
+
stop)
|
50
|
+
echo -n "Stopping $DESC: "
|
51
|
+
start-stop-daemon --stop --quiet --pidfile $PID \
|
52
|
+
--exec $DAEMON || true
|
53
|
+
echo "$NAME."
|
54
|
+
;;
|
55
|
+
restart|force-reload)
|
56
|
+
echo -n "Restarting $DESC: "
|
57
|
+
start-stop-daemon --stop --quiet --pidfile \
|
58
|
+
$PID --exec $DAEMON || true
|
59
|
+
sleep 1
|
60
|
+
test_nginx_config
|
61
|
+
start-stop-daemon --start --quiet --pidfile \
|
62
|
+
$PID --exec $DAEMON -- $DAEMON_OPTS || true
|
63
|
+
echo "$NAME."
|
64
|
+
;;
|
65
|
+
reload)
|
66
|
+
echo -n "Reloading $DESC configuration: "
|
67
|
+
test_nginx_config
|
68
|
+
start-stop-daemon --stop --signal HUP --quiet --pidfile $PID \
|
69
|
+
--exec $DAEMON || true
|
70
|
+
echo "$NAME."
|
71
|
+
;;
|
72
|
+
reopen)
|
73
|
+
echo -n "Reopening $DESC log files: "
|
74
|
+
$DAEMON -s reopen || true
|
75
|
+
echo "$NAME."
|
76
|
+
;;
|
77
|
+
configtest)
|
78
|
+
echo -n "Testing $DESC configuration: "
|
79
|
+
if test_nginx_config
|
80
|
+
then
|
81
|
+
echo "$NAME."
|
82
|
+
else
|
83
|
+
exit $?
|
84
|
+
fi
|
85
|
+
;;
|
86
|
+
status)
|
87
|
+
status_of_proc -p $PID "$DAEMON" nginx && exit 0 || exit $?
|
88
|
+
;;
|
89
|
+
*)
|
90
|
+
echo "Usage: $NAME {start|stop|restart|reload|force-reload|reopen|status|configtest}" >&2
|
91
|
+
exit 1
|
92
|
+
;;
|
93
|
+
esac
|
94
|
+
|
95
|
+
exit 0
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<%=nginx_unicorn_log_dir%>/*.log {
|
2
|
+
daily
|
3
|
+
missingok
|
4
|
+
rotate 52
|
5
|
+
compress
|
6
|
+
delaycompress
|
7
|
+
notifempty
|
8
|
+
create 0640 www-data adm
|
9
|
+
sharedscripts
|
10
|
+
prerotate
|
11
|
+
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
|
12
|
+
run-parts /etc/logrotate.d/httpd-prerotate; \
|
13
|
+
fi; \
|
14
|
+
endscript
|
15
|
+
postrotate
|
16
|
+
[ ! -f /var/run/<%=nginx_unicorn_init_d%>.pid ] || kill -USR1 `cat /var/run/<%=nginx_unicorn_init_d%>.pid`
|
17
|
+
endscript
|
18
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
server {
|
2
|
+
listen 127.0.0.1:80;
|
3
|
+
server_name localhost;
|
4
|
+
|
5
|
+
location /nginx_status {
|
6
|
+
# copied from http://blog.kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/
|
7
|
+
# Generate stupid load to see the counters increase
|
8
|
+
# ab -n 1000 http://127.0.0.1/nginx_status
|
9
|
+
stub_status on;
|
10
|
+
access_log off;
|
11
|
+
allow 127.0.0.1;
|
12
|
+
deny all;
|
13
|
+
}
|
14
|
+
|
15
|
+
}
|
16
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# @author Donovan Bray <donnoman@donovanbray.com>
|
2
|
+
Capistrano::Configuration.instance(true).load do
|
3
|
+
|
4
|
+
namespace :nodejs do
|
5
|
+
|
6
|
+
desc "Install nodejs"
|
7
|
+
task :install, :except => {:no_release => true} do
|
8
|
+
utilities.apt_install "nodejs"
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Allows Tasks that have no servers to be skipped instead of raising a NoMatchingServersError
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
class Configuration
|
5
|
+
module Connections
|
6
|
+
def execute_on_servers(options={})
|
7
|
+
raise ArgumentError, "expected a block" unless block_given?
|
8
|
+
|
9
|
+
if task = current_task
|
10
|
+
servers = find_servers_for_task(task, options)
|
11
|
+
|
12
|
+
if servers.empty?
|
13
|
+
#raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
|
14
|
+
logger.info "skipping `#{task.fully_qualified_name}' because no servers matched"
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
if task.continue_on_error?
|
19
|
+
servers.delete_if { |s| has_failed?(s) }
|
20
|
+
return if servers.empty?
|
21
|
+
end
|
22
|
+
else
|
23
|
+
servers = find_servers(options)
|
24
|
+
raise Capistrano::NoMatchingServersError, "no servers found to match #{options.inspect}" if servers.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
servers = [servers.first] if options[:once]
|
28
|
+
logger.trace "servers: #{servers.map { |s| s.host }.inspect}"
|
29
|
+
|
30
|
+
max_hosts = (options[:max_hosts] || (task && task.max_hosts) || servers.size).to_i
|
31
|
+
is_subset = max_hosts < servers.size
|
32
|
+
|
33
|
+
# establish connections to those servers in groups of max_hosts, as necessary
|
34
|
+
servers.each_slice(max_hosts) do |servers_slice|
|
35
|
+
begin
|
36
|
+
establish_connections_to(servers_slice)
|
37
|
+
rescue ConnectionError => error
|
38
|
+
raise error unless task && task.continue_on_error?
|
39
|
+
error.hosts.each do |h|
|
40
|
+
servers_slice.delete(h)
|
41
|
+
failed!(h)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
yield servers_slice
|
47
|
+
rescue RemoteError => error
|
48
|
+
raise error unless task && task.continue_on_error?
|
49
|
+
error.hosts.each { |h| failed!(h) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# if dealing with a subset (e.g., :max_hosts is less than the
|
53
|
+
# number of servers available) teardown the subset of connections
|
54
|
+
# that were just made, so that we can make room for the next subset.
|
55
|
+
teardown_connections_to(servers_slice) if is_subset
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# @author Donovan Bray <donnoman@donovanbray.com>
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../utilities')
|
3
|
+
|
4
|
+
# Provisioning hooks into many of the scripts to give a single hook to install
|
5
|
+
# the requisite software.
|
6
|
+
#
|
7
|
+
# The provisioning process assumes capistrano has been overriden to support empty roles
|
8
|
+
#
|
9
|
+
# Supported tasks add a ' after "deploy:provision", "app:install" ' in their hooks.rb
|
10
|
+
# if you don't include ' require 'cap_recipes/tasks/provision' ' in your deploy.rb then the provision task
|
11
|
+
# is never fire, and all of the extra hooks are ignored.
|
12
|
+
#
|
13
|
+
# It's convenient to override the provision task in your deploy.rb to do something more meaningful as well.
|
14
|
+
#
|
15
|
+
# desc "Provision the servers"
|
16
|
+
# task :provision do
|
17
|
+
# utilities.apt_install "git-core telnet elinks netcat socat curl arping rsync nload wget locate strace"
|
18
|
+
# mysql.install_client_libs #needed to build mysql2 gem
|
19
|
+
# deploy.provision_bundler_dependencies
|
20
|
+
# end
|
21
|
+
|
22
|
+
Capistrano::Configuration.instance(true).load do
|
23
|
+
|
24
|
+
namespace :deploy do
|
25
|
+
|
26
|
+
# Init all base roles so they can be empty
|
27
|
+
roles[:web]
|
28
|
+
roles[:app]
|
29
|
+
roles[:db]
|
30
|
+
|
31
|
+
# This block allows us to add items to the very beginning of provisioning
|
32
|
+
# while allowing the consumer to freely override the deploy:provision task to add
|
33
|
+
# thier own non-framework items.
|
34
|
+
on :start, :only => "deploy:provision" do
|
35
|
+
deploy.provision_prerequisites
|
36
|
+
end
|
37
|
+
|
38
|
+
task :provision_prerequisites do
|
39
|
+
utilities.apt_update
|
40
|
+
utilities.apt_install_by_command('add-apt-repository')
|
41
|
+
end
|
42
|
+
|
43
|
+
task :provision do
|
44
|
+
logger.info "Provisioning Services"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Configuration
|
3
|
+
module Servers
|
4
|
+
# Identifies all servers that the given task should be executed on.
|
5
|
+
# The options hash accepts the same arguments as #find_servers, and any
|
6
|
+
# preexisting options there will take precedence over the options in
|
7
|
+
# the task.
|
8
|
+
def find_servers_for_task(task, options={})
|
9
|
+
find_servers(task.options.merge(options))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Attempts to find all defined servers that match the given criteria.
|
13
|
+
# The options hash may include a :hosts option (which should specify
|
14
|
+
# an array of host names or ServerDefinition instances), a :roles
|
15
|
+
# option (specifying an array of roles), an :only option (specifying
|
16
|
+
# a hash of key/value pairs that any matching server must match), and
|
17
|
+
# an :exception option (like :only, but the inverse).
|
18
|
+
#
|
19
|
+
# Additionally, if the HOSTS environment variable is set, it will take
|
20
|
+
# precedence over any other options. Similarly, the ROLES environment
|
21
|
+
# variable will take precedence over other options. If both HOSTS and
|
22
|
+
# ROLES are given, HOSTS wins.
|
23
|
+
#
|
24
|
+
# Yet additionally, if the HOSTFILTER environment variable is set, it
|
25
|
+
# will limit the result to hosts found in that (comma-separated) list.
|
26
|
+
#
|
27
|
+
# Usage:
|
28
|
+
#
|
29
|
+
# # return all known servers
|
30
|
+
# servers = find_servers
|
31
|
+
#
|
32
|
+
# # find all servers in the app role that are not exempted from
|
33
|
+
# # deployment
|
34
|
+
# servers = find_servers :roles => :app,
|
35
|
+
# :except => { :no_release => true }
|
36
|
+
#
|
37
|
+
# # returns the given hosts, translated to ServerDefinition objects
|
38
|
+
# servers = find_servers :hosts => "jamis@example.host.com"
|
39
|
+
def find_servers(options={})
|
40
|
+
hosts = server_list_from(ENV['HOSTS'] || options[:hosts])
|
41
|
+
|
42
|
+
if hosts.any?
|
43
|
+
filter_server_list(hosts.uniq)
|
44
|
+
else
|
45
|
+
roles = role_list_from(ENV['ROLES'] || options[:roles] || self.roles.keys)
|
46
|
+
only = options[:only] || {}
|
47
|
+
except = options[:except] || {}
|
48
|
+
|
49
|
+
servers = roles.inject([]) { |list, role| list.concat(self.roles[role]) }
|
50
|
+
servers = servers.select { |server| only.all? { |key,value| server.options[key] == value } }
|
51
|
+
servers = servers.reject { |server| except.any? { |key,value| server.options[key] == value } }
|
52
|
+
|
53
|
+
#allows you to add the option :once to a task ie: task :my_task, :roles => :app, :once => true do ...
|
54
|
+
servers = [servers.first] if options[:once] and servers.size > 1
|
55
|
+
logger.trace "servers: #{servers.map { |s| s.host }.inspect}"
|
56
|
+
|
57
|
+
filter_server_list(servers.uniq)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# @author Donovan Bray <donnoman@donovanbray.com>
|
2
|
+
Capistrano::Configuration.instance(true).load do
|
3
|
+
after "deploy:provision", "ruby:install"
|
4
|
+
after "ruby:install", "ruby:rubygems_source_fix"
|
5
|
+
after "ruby:install", "ruby:ruby_debugger"
|
6
|
+
after "deploy:setup", "ruby:ensure_trust_github"
|
7
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../utilities')
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance(true).load do
|
4
|
+
|
5
|
+
namespace :ruby do
|
6
|
+
|
7
|
+
set :ruby_ver_latest_type, "stable" # can be major.minor numbers ie: 1.8, 2.1 etc. or 'stable'
|
8
|
+
set(:ruby_ver_latest) { open("http://ftp.ruby-lang.org/pub/ruby/#{ruby_ver_latest_type}").read.scan(/href="(ruby-\d.\d.\d(-p\d+)?).tar.bz2/).map{|r| r[0]}.sort.reverse.first }
|
9
|
+
set(:ruby_ver) { utilities.suggest_version(:ruby_ver,ruby_ver_latest) }
|
10
|
+
|
11
|
+
# Ruby Versioning: ruby-MAJOR.MINOR.TEENY-pPATCHLEVEL
|
12
|
+
set(:ruby_major_minor) { ruby_ver.match(/ruby-(\d\.\d)/)[1]}
|
13
|
+
set(:ruby_src) { "http://cache.ruby-lang.org/pub/ruby/#{ruby_major_minor}/#{ruby_ver}.tar.bz2"}
|
14
|
+
|
15
|
+
set :base_ruby_path, '/usr'
|
16
|
+
set :ruby_debugger_support, false
|
17
|
+
set :ruby_rubygems_source_fix_support, false
|
18
|
+
set :ruby_ensure_trust_github, true
|
19
|
+
|
20
|
+
# New Concept ':except => {:no_ruby => true}' to allow all systems by default
|
21
|
+
# to have ruby installed to allow use of ruby gems like god on all systems
|
22
|
+
# regardless of whether they have releases deployed to them, they may have other things
|
23
|
+
# that we want god to watch on them.
|
24
|
+
|
25
|
+
desc "install ruby"
|
26
|
+
task :install, :except => {:no_ruby => true} do
|
27
|
+
utilities.apt_install %w[build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool]
|
28
|
+
sudo "mkdir -p /usr/local/src/"
|
29
|
+
run "#{sudo} rm -rf /usr/local/src/#{ruby_ver}" #make clean is not allowing a re-install #http://www.ruby-forum.com/topic/4409005
|
30
|
+
run "cd /usr/local/src && #{sudo} wget --tries=2 -c --progress=bar:force #{ruby_src} && #{sudo} bunzip2 --keep --force #{ruby_ver}.tar.bz2 && #{sudo} tar xvf #{ruby_ver}.tar"
|
31
|
+
run "cd /usr/local/src/#{ruby_ver} && #{sudo} ./configure --prefix=#{base_ruby_path} --enable-shared && #{sudo} make install"
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "add ruby debugger support"
|
35
|
+
task :ruby_debugger, :except => { :no_ruby => true } do
|
36
|
+
if ruby_debugger_support
|
37
|
+
utilities.gem_install("debugger-ruby_core_source -- --with-ruby-include=/usr/local/src/#{ruby_ver}")
|
38
|
+
utilities.gem_install("debugger-linecache -- --with-ruby-include=/usr/local/src/#{ruby_ver}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Remove legacy rubygems.org as gem source"
|
43
|
+
task :rubygems_source_fix, :except => { :no_ruby => true } do
|
44
|
+
if ruby_rubygems_source_fix_support
|
45
|
+
run "#{sudo} gem source -a http://production.s3.rubygems.org"
|
46
|
+
run "#{sudo} gem source -r http://rubygems.org/"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
task :ensure_trust_github, :except => { :no_ruby => true } do
|
51
|
+
utilities.run_with_input("ssh -i ~/.ssh/id_rsa git@github.com;true", /\?/, "yes\n") if ruby_ensure_trust_github
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
class TeeLogWriter
|
2
|
+
#use this to exit cap but still have a zero exit code
|
3
|
+
class NormalExit < Capistrano::Error; end
|
4
|
+
##
|
5
|
+
# This passes through the value and adds it to the redaction list
|
6
|
+
#
|
7
|
+
# set(:mysql_client_user) { TeeLogWriter.redact(database_user) }
|
8
|
+
#
|
9
|
+
# So your capistrano variable has the correct value, but it will be redacted from TeeLogWriters output.
|
10
|
+
def self.redact(secure_message)
|
11
|
+
self.redactions = (self.redactions + [secure_message].flatten).uniq
|
12
|
+
secure_message
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.redaction_replacement
|
16
|
+
@redaction_replacement ||= '######'
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.redaction_replacement=(replacement)
|
20
|
+
@redaction_replacement = replacement
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.redacted(message)
|
24
|
+
with_ensured_encoding(message) do |message|
|
25
|
+
redactions.inject(message) do |message,redaction|
|
26
|
+
message.gsub(redaction,redaction_replacement)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_redactions(message)
|
32
|
+
yield self.class.redacted(message)
|
33
|
+
end
|
34
|
+
|
35
|
+
def puts(message)
|
36
|
+
with_redactions(message) do |message|
|
37
|
+
STDOUT.puts message
|
38
|
+
file.puts "[#{log_timestamp}] #{message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def tty?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
|
49
|
+
def self.redactions
|
50
|
+
@redactions ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.redactions=(value)
|
54
|
+
@redactions = value
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.with_ensured_encoding(message)
|
58
|
+
yield message.respond_to?(:force_encoding) ? message.force_encoding("UTF-8") : message
|
59
|
+
end
|
60
|
+
|
61
|
+
def file
|
62
|
+
@file ||= File.open(File.join(logdir,"deploy.#{file_timestamp}.log"), "w")
|
63
|
+
end
|
64
|
+
|
65
|
+
def log_timestamp
|
66
|
+
Time.now.strftime("%Y-%m-%d %H:%M:%S%z")
|
67
|
+
end
|
68
|
+
|
69
|
+
def file_timestamp
|
70
|
+
Time.now.strftime("%Y%m%d-%H%M%S%z")
|
71
|
+
end
|
72
|
+
|
73
|
+
def caproot
|
74
|
+
@caproot ||= File.dirname(capfile)
|
75
|
+
end
|
76
|
+
|
77
|
+
def logdir
|
78
|
+
FileUtils.mkdir_p(File.join(caproot,'log')).first
|
79
|
+
end
|
80
|
+
|
81
|
+
def capfile
|
82
|
+
previous = nil
|
83
|
+
current = File.expand_path(Dir.pwd)
|
84
|
+
|
85
|
+
until !File.directory?(current) || current == previous
|
86
|
+
filename = File.join(current, 'Capfile')
|
87
|
+
return filename if File.file?(filename)
|
88
|
+
current, previous = File.expand_path("..", current), current
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
require 'capistrano/configuration'
|
95
|
+
|
96
|
+
module Capistrano
|
97
|
+
class CLI
|
98
|
+
module Execute
|
99
|
+
def handle_error(error) #:nodoc:
|
100
|
+
case error
|
101
|
+
when TeeLogWriter::NormalExit #used to force capistrano to end but without an error code.
|
102
|
+
exit 0
|
103
|
+
when Net::SSH::AuthenticationFailed
|
104
|
+
abort "authentication failed for `#{TeeLogWriter.redacted(error.message)}'"
|
105
|
+
when Capistrano::Error
|
106
|
+
abort(TeeLogWriter.redacted(error.message))
|
107
|
+
else
|
108
|
+
puts TeeLogWriter.redacted(error.message)
|
109
|
+
puts error.backtrace
|
110
|
+
exit 1
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
Capistrano::Configuration.instance(true).load do
|
119
|
+
#replace the running logger device with our own.
|
120
|
+
self.logger.instance_variable_set(:@device,TeeLogWriter.new)
|
121
|
+
end
|