capistrano-kitchen 0.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|