le1t0-deprec 2.1.6.001
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +444 -0
- data/COPYING +19 -0
- data/LICENSE +339 -0
- data/README +154 -0
- data/THANKS +17 -0
- data/bin/depify +139 -0
- data/docs/EXAMPLE-installing_tracks.txt +41 -0
- data/docs/README.nagios +22 -0
- data/docs/README.rails +17 -0
- data/docs/config_gen_explained.txt +39 -0
- data/docs/deprec-1.x/deprec-1.x.quickstart +50 -0
- data/docs/deprec-1.x/notes.txt +12 -0
- data/docs/old/deprec_banner.gif +0 -0
- data/docs/windows_linux.txt +350 -0
- data/docs/xen/traffic_monitoring_with_vnstat.txt +95 -0
- data/docs/xen/xen-tools-notes.txt +31 -0
- data/docs/xen/xen_on_hardy.txt +39 -0
- data/lib/deprec.rb +42 -0
- data/lib/deprec/capistrano_extensions.rb +446 -0
- data/lib/deprec/recipes.rb +7 -0
- data/lib/deprec/recipes/aoe.rb +79 -0
- data/lib/deprec/recipes/app/mongrel.rb +213 -0
- data/lib/deprec/recipes/app/passenger.rb +190 -0
- data/lib/deprec/recipes/ar_sendmail.rb +67 -0
- data/lib/deprec/recipes/aspell.rb +22 -0
- data/lib/deprec/recipes/canonical.rb +68 -0
- data/lib/deprec/recipes/cap.rb +39 -0
- data/lib/deprec/recipes/chef.rb +68 -0
- data/lib/deprec/recipes/collectd.rb +112 -0
- data/lib/deprec/recipes/db/couchdb.rb +107 -0
- data/lib/deprec/recipes/db/mysql.rb +194 -0
- data/lib/deprec/recipes/db/postgresql.rb +104 -0
- data/lib/deprec/recipes/db/sqlite.rb +37 -0
- data/lib/deprec/recipes/ddclient.rb +51 -0
- data/lib/deprec/recipes/deprec.rb +167 -0
- data/lib/deprec/recipes/deprecated.rb +71 -0
- data/lib/deprec/recipes/drbd.rb +137 -0
- data/lib/deprec/recipes/dummy.rb +22 -0
- data/lib/deprec/recipes/example.rb +115 -0
- data/lib/deprec/recipes/git.rb +97 -0
- data/lib/deprec/recipes/gitosis.rb.disabled +55 -0
- data/lib/deprec/recipes/glusterfs.rb +176 -0
- data/lib/deprec/recipes/god.rb +70 -0
- data/lib/deprec/recipes/haproxy.rb +115 -0
- data/lib/deprec/recipes/heartbeat.rb +138 -0
- data/lib/deprec/recipes/imagemagick/imagemagick_bin.rb +24 -0
- data/lib/deprec/recipes/imagemagick/imagemagick_src.rb +39 -0
- data/lib/deprec/recipes/integrity.rb +108 -0
- data/lib/deprec/recipes/iptables.rb +94 -0
- data/lib/deprec/recipes/java.rb +23 -0
- data/lib/deprec/recipes/keepalived.rb +78 -0
- data/lib/deprec/recipes/ldap.rb +52 -0
- data/lib/deprec/recipes/logrotate.rb +56 -0
- data/lib/deprec/recipes/lvm.rb +20 -0
- data/lib/deprec/recipes/memcache.rb +49 -0
- data/lib/deprec/recipes/mongodb.rb +94 -0
- data/lib/deprec/recipes/monit.rb +135 -0
- data/lib/deprec/recipes/mysql_proxy.rb +67 -0
- data/lib/deprec/recipes/nagios.rb +361 -0
- data/lib/deprec/recipes/network.rb +116 -0
- data/lib/deprec/recipes/ntp.rb +103 -0
- data/lib/deprec/recipes/php.rb +58 -0
- data/lib/deprec/recipes/postfix.rb +115 -0
- data/lib/deprec/recipes/profiles.rb +125 -0
- data/lib/deprec/recipes/raid/amcc_3ware.rb +21 -0
- data/lib/deprec/recipes/rails.rb +330 -0
- data/lib/deprec/recipes/redhat_cluster.rb +228 -0
- data/lib/deprec/recipes/redis.rb +90 -0
- data/lib/deprec/recipes/ruby/mri.rb +55 -0
- data/lib/deprec/recipes/ruby/ree.rb +40 -0
- data/lib/deprec/recipes/rvm.rb +32 -0
- data/lib/deprec/recipes/s3utils.rb +63 -0
- data/lib/deprec/recipes/sphinx/thinking_sphinx.rb +105 -0
- data/lib/deprec/recipes/sphinx/ultrasphinx.rb +86 -0
- data/lib/deprec/recipes/ssh.rb +147 -0
- data/lib/deprec/recipes/ssl.rb +56 -0
- data/lib/deprec/recipes/starling.rb +119 -0
- data/lib/deprec/recipes/svn.rb +171 -0
- data/lib/deprec/recipes/syslog.rb +63 -0
- data/lib/deprec/recipes/trac.rb.disabled +277 -0
- data/lib/deprec/recipes/tsung.rb +74 -0
- data/lib/deprec/recipes/ubuntu.rb +90 -0
- data/lib/deprec/recipes/users.rb +90 -0
- data/lib/deprec/recipes/utils.rb +58 -0
- data/lib/deprec/recipes/vnstat.rb +85 -0
- data/lib/deprec/recipes/web/apache.rb +143 -0
- data/lib/deprec/recipes/web/nginx.rb +172 -0
- data/lib/deprec/recipes/wordpress.rb.notworking +96 -0
- data/lib/deprec/recipes/wpmu.rb +103 -0
- data/lib/deprec/recipes/xen.rb +364 -0
- data/lib/deprec/recipes/xentools.rb +101 -0
- data/lib/deprec/recipes_minus_rails.rb +125 -0
- data/lib/deprec/templates/aoe/aoe-init +55 -0
- data/lib/deprec/templates/aoe/fence_aoemask +351 -0
- data/lib/deprec/templates/apache/namevirtualhosts.conf +5 -0
- data/lib/deprec/templates/apache/ports.conf.erb +5 -0
- data/lib/deprec/templates/apache/status.conf.erb +17 -0
- data/lib/deprec/templates/ar_sendmail/logrotate.conf.erb +9 -0
- data/lib/deprec/templates/ar_sendmail/monit.conf.erb +5 -0
- data/lib/deprec/templates/chef/chef.json.erb +1 -0
- data/lib/deprec/templates/chef/solo.rb +2 -0
- data/lib/deprec/templates/collectd/collectd-init.d +153 -0
- data/lib/deprec/templates/collectd/collectd.conf.erb +686 -0
- data/lib/deprec/templates/ddclient/ddclient.conf.erb +11 -0
- data/lib/deprec/templates/ddclient/ddclient.erb +15 -0
- data/lib/deprec/templates/deprec/caprc.erb +14 -0
- data/lib/deprec/templates/drbd/drbd.conf.erb +531 -0
- data/lib/deprec/templates/glusterfs/glusterfsd-init.erb +95 -0
- data/lib/deprec/templates/gnbd_client/cluster.conf.erb +21 -0
- data/lib/deprec/templates/gnbd_client/clvm-default.erb +3 -0
- data/lib/deprec/templates/gnbd_client/cman-default.erb +6 -0
- data/lib/deprec/templates/gnbd_client/gnbdimports.conf.erb +1 -0
- data/lib/deprec/templates/gnbd_server/cluster.conf.erb +20 -0
- data/lib/deprec/templates/gnbd_server/clvm-default.erb +3 -0
- data/lib/deprec/templates/gnbd_server/cman-default.erb +6 -0
- data/lib/deprec/templates/gnbd_server/gnbd-server-default.erb +1 -0
- data/lib/deprec/templates/gnbd_server/gnbdexports.conf.erb +1 -0
- data/lib/deprec/templates/god/god-conf.erb +2 -0
- data/lib/deprec/templates/god/god-init.erb +47 -0
- data/lib/deprec/templates/haproxy/haproxy-init.d +120 -0
- data/lib/deprec/templates/haproxy/haproxy.cfg.erb +31 -0
- data/lib/deprec/templates/heartbeat/authkeys.erb +2 -0
- data/lib/deprec/templates/heartbeat/ha.cf.erb +15 -0
- data/lib/deprec/templates/heartbeat/haresources.erb +1 -0
- data/lib/deprec/templates/integrity/apache_vhost.erb +4 -0
- data/lib/deprec/templates/integrity/config.ru.erb +21 -0
- data/lib/deprec/templates/integrity/config.yml.erb +43 -0
- data/lib/deprec/templates/iptables/firewall-default.erb +13 -0
- data/lib/deprec/templates/iptables/firewall-init.erb +171 -0
- data/lib/deprec/templates/keepalived/keepalived.conf.erb +18 -0
- data/lib/deprec/templates/logrotate/logrotate.conf.erb +32 -0
- data/lib/deprec/templates/mongodb/mongodb-init.d +88 -0
- data/lib/deprec/templates/mongrel/apache_vhost.conf.erb +148 -0
- data/lib/deprec/templates/mongrel/logrotate.conf.erb +11 -0
- data/lib/deprec/templates/mongrel/mongrel_cluster-init-script +54 -0
- data/lib/deprec/templates/mongrel/mongrel_cluster.yml.erb +10 -0
- data/lib/deprec/templates/mongrel/monit.conf.erb +17 -0
- data/lib/deprec/templates/mongrel/nginx_vhost.conf.erb +41 -0
- data/lib/deprec/templates/monit/monit-init-script +104 -0
- data/lib/deprec/templates/monit/monitrc.erb +250 -0
- data/lib/deprec/templates/monit/nothing.monitrc +0 -0
- data/lib/deprec/templates/mysql/create_databases.sql +20 -0
- data/lib/deprec/templates/mysql/database.yml.prod +6 -0
- data/lib/deprec/templates/mysql/database.yml.stage +6 -0
- data/lib/deprec/templates/mysql/my.cnf.erb +140 -0
- data/lib/deprec/templates/mysql/sphinx.conf.prod +542 -0
- data/lib/deprec/templates/mysql/sphinx.conf.stage +542 -0
- data/lib/deprec/templates/mysql_proxy/mysql-proxy-default.erb +4 -0
- data/lib/deprec/templates/nagios/README +32 -0
- data/lib/deprec/templates/nagios/cgi.cfg.erb +357 -0
- data/lib/deprec/templates/nagios/check_linux_free_memory.pl +118 -0
- data/lib/deprec/templates/nagios/check_mongrel_cluster.rb +82 -0
- data/lib/deprec/templates/nagios/htpasswd.users +1 -0
- data/lib/deprec/templates/nagios/mrtg.cfg +180 -0
- data/lib/deprec/templates/nagios/nagios.cfg.erb +1325 -0
- data/lib/deprec/templates/nagios/nrpe.cfg.erb +222 -0
- data/lib/deprec/templates/nagios/nrpe.xinetd.erb +16 -0
- data/lib/deprec/templates/nagios/objects/commands.cfg.erb +265 -0
- data/lib/deprec/templates/nagios/objects/contacts.cfg.erb +89 -0
- data/lib/deprec/templates/nagios/objects/hosts.cfg.erb +114 -0
- data/lib/deprec/templates/nagios/objects/localhost.cfg.erb +116 -0
- data/lib/deprec/templates/nagios/objects/services.cfg.erb +165 -0
- data/lib/deprec/templates/nagios/objects/timeperiods.cfg.erb +94 -0
- data/lib/deprec/templates/nagios/resource.cfg.erb +34 -0
- data/lib/deprec/templates/network/hostname.erb +1 -0
- data/lib/deprec/templates/network/hosts.erb +2 -0
- data/lib/deprec/templates/network/interfaces.erb +18 -0
- data/lib/deprec/templates/network/resolv.conf.erb +6 -0
- data/lib/deprec/templates/nginx/logrotate.conf.erb +13 -0
- data/lib/deprec/templates/nginx/mime.types.erb +70 -0
- data/lib/deprec/templates/nginx/nginx-init-script +62 -0
- data/lib/deprec/templates/nginx/nginx.conf.erb +125 -0
- data/lib/deprec/templates/nginx/nginx.logrotate.d +12 -0
- data/lib/deprec/templates/nginx/nothing.conf +1 -0
- data/lib/deprec/templates/nginx/rails_nginx_vhost.conf.erb +41 -0
- data/lib/deprec/templates/ntp/ntp.conf.erb +42 -0
- data/lib/deprec/templates/passenger/apache_vhost.erb +29 -0
- data/lib/deprec/templates/passenger/logrotate.conf.erb +12 -0
- data/lib/deprec/templates/passenger/passenger.conf.erb +21 -0
- data/lib/deprec/templates/passenger/passenger.load.erb +3 -0
- data/lib/deprec/templates/postfix/aliases.erb +3 -0
- data/lib/deprec/templates/postfix/dynamicmaps.cf.erb +8 -0
- data/lib/deprec/templates/postfix/main.cf.erb +36 -0
- data/lib/deprec/templates/postfix/master.cf.erb +77 -0
- data/lib/deprec/templates/redis/redis-conf.erb +132 -0
- data/lib/deprec/templates/redis/redis-init.erb +50 -0
- data/lib/deprec/templates/s3utils/s3cfg +35 -0
- data/lib/deprec/templates/s3utils/s3config.yml +3 -0
- data/lib/deprec/templates/sphinx/monit.conf.erb +5 -0
- data/lib/deprec/templates/ssh/ssh_config.erb +50 -0
- data/lib/deprec/templates/ssh/sshd_config.erb +78 -0
- data/lib/deprec/templates/ssl/make-ssl-cert +138 -0
- data/lib/deprec/templates/ssl/ssl-cert-snakeoil.key +15 -0
- data/lib/deprec/templates/ssl/ssl-cert-snakeoil.pem +19 -0
- data/lib/deprec/templates/starling/monit.conf.erb +14 -0
- data/lib/deprec/templates/starling/starling-init-script.erb +71 -0
- data/lib/deprec/templates/subversion/svn.apache.vhost.erb +43 -0
- data/lib/deprec/templates/syslog/syslog.conf.erb +71 -0
- data/lib/deprec/templates/syslog/syslogd.erb +13 -0
- data/lib/deprec/templates/trac/apache_vhost.conf.erb +24 -0
- data/lib/deprec/templates/trac/nginx_vhost.conf.erb +26 -0
- data/lib/deprec/templates/trac/trac.ini.erb +169 -0
- data/lib/deprec/templates/trac/trac_deprec.png +0 -0
- data/lib/deprec/templates/trac/tracd-init.erb +43 -0
- data/lib/deprec/templates/trac/users.htdigest.erb +0 -0
- data/lib/deprec/templates/tsung/tsung.xml.erb +47 -0
- data/lib/deprec/templates/vnstat/config.php +57 -0
- data/lib/deprec/templates/wordpress/apache2_wordpress_vhost.conf.erb +31 -0
- data/lib/deprec/templates/wordpress/wp-config.php.erb +31 -0
- data/lib/deprec/templates/wpmu/apache_vhost.conf.erb +13 -0
- data/lib/deprec/templates/xen/network-bridge-wrapper +3 -0
- data/lib/deprec/templates/xen/xend-config.sxp.erb +195 -0
- data/lib/deprec/templates/xen/xend-init.erb +57 -0
- data/lib/deprec/templates/xen/xendomains.erb +137 -0
- data/lib/deprec/templates/xentools/100-ubuntu-setup +26 -0
- data/lib/deprec/templates/xentools/15-disable-hwclock +40 -0
- data/lib/deprec/templates/xentools/30-disable-gettys +57 -0
- data/lib/deprec/templates/xentools/31-ubuntu-setup +32 -0
- data/lib/deprec/templates/xentools/40-setup-networking +145 -0
- data/lib/deprec/templates/xentools/98-custom +17 -0
- data/lib/deprec/templates/xentools/xen-tools.conf.erb +278 -0
- data/lib/deprec/templates/xentools/xm.tmpl.erb +138 -0
- data/lib/deprec_cmd_completion.sh +26 -0
- data/lib/deprec_minus_rails.rb +12 -0
- data/lib/vmbuilder_plugins/all.rb +20 -0
- data/lib/vmbuilder_plugins/apt.rb +93 -0
- data/lib/vmbuilder_plugins/emerge.rb +76 -0
- data/lib/vmbuilder_plugins/gem.rb +100 -0
- data/lib/vmbuilder_plugins/std.rb +203 -0
- metadata +304 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
# vnstat
|
2
|
+
|
3
|
+
# install vnstat
|
4
|
+
http://humdi.net/vnstat/vnstat-1.6.tar.gz
|
5
|
+
sudo apt-get install vnstat
|
6
|
+
|
7
|
+
# initialize it for a virtual interface
|
8
|
+
vnstat -u -i vif-apt
|
9
|
+
|
10
|
+
# generate images
|
11
|
+
http://humdi.net/vnstat/vnstati-beta3.tar.gz
|
12
|
+
apt-get install libgd2-noxpm-dev libgd2-noxpm
|
13
|
+
vnstati -s -i vif-apt -o /tmp/vnstat.png
|
14
|
+
|
15
|
+
# php web frontend
|
16
|
+
http://www.sqweek.com/sqweek/files/vnstat_php_frontend-1.3.tar.gz
|
17
|
+
|
18
|
+
|
19
|
+
# Steps for setting up vnstat on a new Xen dom0
|
20
|
+
|
21
|
+
1. Install vnstat on host
|
22
|
+
|
23
|
+
# Steps for adding a new server to vnstat monitoring
|
24
|
+
|
25
|
+
1. Add it to vnstat monitoring
|
26
|
+
|
27
|
+
vnstat -u -i web2-eth0
|
28
|
+
|
29
|
+
2.
|
30
|
+
|
31
|
+
|
32
|
+
#
|
33
|
+
# Add all eth interfaces
|
34
|
+
#
|
35
|
+
for x in `ls /proc/sys/net/ipv4/conf | grep eth | cut -f 1 -d' '`; do
|
36
|
+
vnstat -u -i $x
|
37
|
+
done
|
38
|
+
|
39
|
+
#!/bin/bash
|
40
|
+
#
|
41
|
+
# Dump vnstat data
|
42
|
+
#
|
43
|
+
dump_dir=/var/lib/vnstat_dumps
|
44
|
+
|
45
|
+
test -d $dump_dir || mkdir -p $dump_dir
|
46
|
+
|
47
|
+
for x in `ls /var/lib/vnstat/*-eth*`; do
|
48
|
+
vnstat --dumpdb -i `basename $x` > ${dump_dir}/vnstat_dump_`basename $x`
|
49
|
+
done
|
50
|
+
|
51
|
+
for x in eth0 eth1; do
|
52
|
+
vnstat --dumpdb -i $x > ${dump_dir}/vnstat_dump_`hostname`-$x
|
53
|
+
done
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
#!/bin/bash
|
58
|
+
#
|
59
|
+
# Pull vnstat metrics back from Xen dom0's
|
60
|
+
#
|
61
|
+
|
62
|
+
dump_dir=/var/lib/vnstat_dumps
|
63
|
+
|
64
|
+
test -d $dump_dir || mkdir -p $dump_dir
|
65
|
+
for x in sm03; do
|
66
|
+
rsync -avz ${x}:${dump_dir}/ /var/www/vnstat/dumps/
|
67
|
+
done
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
#
|
72
|
+
# Separate internal and external traffic on NAT'ed slices
|
73
|
+
#
|
74
|
+
|
75
|
+
The following in /etc/network/interfaces will allow us to monitor
|
76
|
+
internal and external traffic by reading separate interface counters
|
77
|
+
on the domU.
|
78
|
+
|
79
|
+
# First IP on internal network (for external traffic)
|
80
|
+
auto eth0
|
81
|
+
iface eth0 inet static
|
82
|
+
address 192.168.1.70
|
83
|
+
netmask 255.255.255.255
|
84
|
+
|
85
|
+
# Second IP on internal network (for internal traffic only)
|
86
|
+
auto eth1
|
87
|
+
iface eth1 inet static
|
88
|
+
address 192.168.1.71
|
89
|
+
netmask 255.255.255.0
|
90
|
+
|
91
|
+
# Route external traffic out eth0
|
92
|
+
up route add -net 192.168.1.1 netmask 255.255.255.255 dev eth0
|
93
|
+
up route add default gw 192.168.1.1
|
94
|
+
|
95
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# xen-tools : interesting bits
|
3
|
+
#
|
4
|
+
|
5
|
+
xt-install-image Install a new distribution.
|
6
|
+
xt-customize-image Run a collection of hook scripts to customise the freshly installed system.
|
7
|
+
xt-create-xen-config Create a Xen configuration file in so that xm can start the new domain.
|
8
|
+
|
9
|
+
|
10
|
+
# PARTITIONING
|
11
|
+
/etc/xen-tools/partitions.d/
|
12
|
+
--partition partition_scheme_file
|
13
|
+
|
14
|
+
# Automatic IP provisioning
|
15
|
+
--ip=auto /etc/xen-tools/ips.txt
|
16
|
+
|
17
|
+
# Config template
|
18
|
+
/etc/xen-tools/xm.tmpl
|
19
|
+
--template
|
20
|
+
|
21
|
+
# tar up first image and use for installation
|
22
|
+
xen-create-image --size=2Gb --swap=128Mb --dhcp \
|
23
|
+
--lvm=myvolumegroup --hostname=vm01.my.flat \
|
24
|
+
--install-method=tar --install-source=/path/to/tar.file.tar
|
25
|
+
|
26
|
+
# Roles
|
27
|
+
/etc/xen-tools/role.d
|
28
|
+
--role=filename -role-args
|
29
|
+
|
30
|
+
# skeleton dir
|
31
|
+
/etc/xen-tools/skel
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# Install xen on ubuntu hardy
|
3
|
+
#
|
4
|
+
# ref: http://www.howtoforge.com/ubuntu-8.04-server-install-xen-from-ubuntu-repositories
|
5
|
+
#
|
6
|
+
|
7
|
+
# Install Xen packages
|
8
|
+
# apt-get install ubuntu-xen-server
|
9
|
+
#
|
10
|
+
# Installs these:
|
11
|
+
#
|
12
|
+
# binutils binutils-static bridge-utils debootstrap libasound2 libconfig-inifiles-perl libcurl3 libdirectfb-1.0-0 libsdl1.2debian
|
13
|
+
# libsdl1.2debian-alsa libtext-template-perl libxen3 libxml2 linux-image-2.6.24-16-xen linux-image-xen
|
14
|
+
# linux-restricted-modules-2.6.24-16-xen linux-restricted-modules-common linux-restricted-modules-xen
|
15
|
+
# linux-ubuntu-modules-2.6.24-16-xen linux-xen nvidia-kernel-common python-dev python-xen-3.2 python2.5-dev ubuntu-xen-server
|
16
|
+
# xen-docs-3.2 xen-hypervisor-3.2 xen-tools xen-utils-3.2
|
17
|
+
|
18
|
+
# before/after 'uname -a'
|
19
|
+
#
|
20
|
+
# Linux bb 2.6.24-16-server #1 SMP Thu Apr 10 13:15:38 UTC 2008 x86_64 GNU/Linux
|
21
|
+
# Linux bb 2.6.24-16-xen #1 SMP Thu Apr 10 14:35:03 UTC 2008 x86_64 GNU/Linux
|
22
|
+
#
|
23
|
+
# Stop apparmor # XXX investigate why
|
24
|
+
# /etc/init.d/apparmor stop
|
25
|
+
# update-rc.d -f apparmor remove
|
26
|
+
|
27
|
+
# mkdir /home/xen
|
28
|
+
|
29
|
+
# edit /etc/xen-tools/xen-tools.cfg
|
30
|
+
|
31
|
+
# create image with xen-tools
|
32
|
+
# xen-create-image --hostname=x1 --size=2Gb --swap=256Mb --ide --ip=192.168.1.51 --memory=256Mb --install-method=debootstrap --dist=hardy
|
33
|
+
|
34
|
+
# update /etc/xen/<domain>.cfg
|
35
|
+
#
|
36
|
+
# disk = [
|
37
|
+
# 'tap:aio:/home/xen/domains/xen1.example.com/swap.img,hda1,w',
|
38
|
+
# 'tap:aio:/home/xen/domains/xen1.example.com/disk.img,hda2,w',
|
39
|
+
# ]
|
data/lib/deprec.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
unless Capistrano::Configuration.respond_to?(:instance)
|
2
|
+
abort "deprec2 requires Capistrano 2"
|
3
|
+
end
|
4
|
+
|
5
|
+
require "#{File.dirname(__FILE__)}/deprec/capistrano_extensions"
|
6
|
+
require "#{File.dirname(__FILE__)}/vmbuilder_plugins/all"
|
7
|
+
require "#{File.dirname(__FILE__)}/deprec/recipes"
|
8
|
+
|
9
|
+
# The below: Copyright 2009-2010 by le1t0@github. All rights reserved.
|
10
|
+
# add missing standard tasks to the various namespaces, so generic scripts won't break, the standard tasks are for now:
|
11
|
+
standard_tasks = [
|
12
|
+
:install,
|
13
|
+
:config_gen,
|
14
|
+
:config_project_gen,
|
15
|
+
:config_system_gen,
|
16
|
+
:config,
|
17
|
+
:config_project,
|
18
|
+
:config_system,
|
19
|
+
:start,
|
20
|
+
:stop,
|
21
|
+
:restart,
|
22
|
+
:reload,
|
23
|
+
:activate,
|
24
|
+
:deactivate,
|
25
|
+
:backup,
|
26
|
+
:restore,
|
27
|
+
:status
|
28
|
+
]
|
29
|
+
Capistrano::Configuration.instance.deprec.namespaces.keys.each do |ns_name|
|
30
|
+
ns = Capistrano::Configuration.instance.deprec.send(ns_name)
|
31
|
+
standard_tasks.each do |standard_task|
|
32
|
+
unless ns.respond_to?(standard_task)
|
33
|
+
Capistrano::Configuration.instance.namespace :deprec do
|
34
|
+
namespace ns_name do
|
35
|
+
task standard_task do
|
36
|
+
# nothing to be done here
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,446 @@
|
|
1
|
+
# Copyright 2006-2008 by Mike Bailey. All rights reserved.
|
2
|
+
require 'capistrano'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Deprec2
|
6
|
+
|
7
|
+
# Temporarily modify ROLES if HOSTS not set
|
8
|
+
# Capistrano's default behaviour is for HOSTS to override ROLES
|
9
|
+
def for_roles(roles)
|
10
|
+
old_roles = ENV['ROLES']
|
11
|
+
ENV['ROLES'] = roles.to_s unless ENV['HOSTS']
|
12
|
+
yield
|
13
|
+
ENV['ROLES'] = old_roles.to_s unless ENV['HOSTS']
|
14
|
+
end
|
15
|
+
|
16
|
+
# Temporarily ignore ROLES and HOSTS
|
17
|
+
def ignoring_roles_and_hosts
|
18
|
+
old_roles = ENV['ROLES']
|
19
|
+
old_hosts = ENV['HOSTS']
|
20
|
+
ENV['ROLES'] = nil
|
21
|
+
ENV['HOSTS'] = nil
|
22
|
+
yield
|
23
|
+
ENV['ROLES'] = old_roles
|
24
|
+
ENV['HOSTS'] = old_hosts
|
25
|
+
end
|
26
|
+
|
27
|
+
DEPREC_TEMPLATES_BASE = File.join(File.dirname(__FILE__), 'templates')
|
28
|
+
|
29
|
+
# Render template (usually a config file)
|
30
|
+
#
|
31
|
+
# Usually we render it to a file on the local filesystem.
|
32
|
+
# This way, we keep a copy of the config file under source control.
|
33
|
+
# We can make manual changes if required and push to new hosts.
|
34
|
+
#
|
35
|
+
# If the options hash contains :path then it's written to that path.
|
36
|
+
# If it contains :remote => true, the file will instead be written to remote targets
|
37
|
+
# If options[:path] and options[:remote] are missing, it just returns the rendered
|
38
|
+
# template as a string (good for debugging).
|
39
|
+
#
|
40
|
+
# XXX I would like to get rid of :render_template_to_file
|
41
|
+
# XXX Perhaps pass an option to this function to write to remote
|
42
|
+
#
|
43
|
+
def render_template(app, options={})
|
44
|
+
template = options[:template]
|
45
|
+
path = options[:path] || nil
|
46
|
+
remote = options[:remote] || false
|
47
|
+
mode = options[:mode] || 0755
|
48
|
+
owner = options[:owner] || nil
|
49
|
+
stage = exists?(:stage) ? fetch(:stage).to_s : ''
|
50
|
+
# replace this with a check for the file
|
51
|
+
if ! template
|
52
|
+
puts "render_template() requires a value for the template!"
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
|
56
|
+
# If local copies of deprec templates exist they will be used
|
57
|
+
# If you don't specify the location with the local_template_dir option
|
58
|
+
# it defaults to config/templates.
|
59
|
+
# e.g. config/templates/nginx/nginx.conf.erb
|
60
|
+
local_template = File.join(local_template_dir, app.to_s, template)
|
61
|
+
if File.exists?(local_template)
|
62
|
+
puts
|
63
|
+
puts "Using local template (#{local_template})"
|
64
|
+
template = ERB.new(IO.read(local_template), nil, '-')
|
65
|
+
else
|
66
|
+
template = ERB.new(IO.read(File.join(DEPREC_TEMPLATES_BASE, app.to_s, template)), nil, '-')
|
67
|
+
end
|
68
|
+
rendered_template = template.result(binding)
|
69
|
+
|
70
|
+
if remote
|
71
|
+
# render to remote machine
|
72
|
+
puts 'You need to specify a path to render the template to!' unless path
|
73
|
+
exit unless path
|
74
|
+
sudo "test -d #{File.dirname(path)} || #{sudo} mkdir -p #{File.dirname(path)}"
|
75
|
+
std.su_put rendered_template, path, '/tmp/', :mode => mode
|
76
|
+
sudo "chown #{owner} #{path}" if defined?(owner)
|
77
|
+
elsif path
|
78
|
+
# render to local file
|
79
|
+
full_path = File.join('config', stage, app.to_s, path)
|
80
|
+
path_dir = File.dirname(full_path)
|
81
|
+
if File.exists?(full_path)
|
82
|
+
if IO.read(full_path) == rendered_template
|
83
|
+
puts "[skip] File exists and is identical (#{full_path})."
|
84
|
+
return false
|
85
|
+
elsif overwrite?(full_path, rendered_template)
|
86
|
+
File.delete(full_path)
|
87
|
+
else
|
88
|
+
puts "[skip] Not overwriting #{full_path}"
|
89
|
+
return false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
FileUtils.mkdir_p "#{path_dir}" if ! File.directory?(path_dir)
|
93
|
+
# added line above to make windows compatible
|
94
|
+
# system "mkdir -p #{path_dir}" if ! File.directory?(path_dir)
|
95
|
+
File.open(full_path, 'w'){|f| f.write rendered_template }
|
96
|
+
puts "[done] #{full_path} written"
|
97
|
+
else
|
98
|
+
# render to string
|
99
|
+
return rendered_template
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def overwrite?(full_path, rendered_template)
|
104
|
+
if defined?(overwrite_all)
|
105
|
+
if overwrite_all == true
|
106
|
+
return true
|
107
|
+
else
|
108
|
+
return false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# XXX add :always and :never later - not sure how to set persistent value from here
|
113
|
+
# response = Capistrano::CLI.ui.ask "File exists. Overwrite? ([y]es, [n]o, [a]lways, n[e]ver)" do |q|
|
114
|
+
puts
|
115
|
+
response = Capistrano::CLI.ui.ask "File exists (#{full_path}).
|
116
|
+
Overwrite? ([y]es, [n]o, [d]iff)" do |q|
|
117
|
+
q.default = 'n'
|
118
|
+
end
|
119
|
+
|
120
|
+
case response
|
121
|
+
when 'y'
|
122
|
+
return true
|
123
|
+
when 'n'
|
124
|
+
return false
|
125
|
+
when 'd'
|
126
|
+
require 'tempfile'
|
127
|
+
tf = Tempfile.new("deprec_diff")
|
128
|
+
tf.puts(rendered_template)
|
129
|
+
tf.close
|
130
|
+
puts
|
131
|
+
puts "Running diff -u current_file new_file_if_you_overwrite"
|
132
|
+
puts
|
133
|
+
system "diff -u #{full_path} #{tf.path} | less"
|
134
|
+
puts
|
135
|
+
overwrite?(full_path, rendered_template)
|
136
|
+
# XXX add :always and :never later - not sure how to set persistent value from here
|
137
|
+
# when 'a'
|
138
|
+
# set :overwrite_all, true
|
139
|
+
# when 'e'
|
140
|
+
# set :overwrite_all, false
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
def render_template_to_file(template_name, destination_file_name, templates_dir = DEPREC_TEMPLATES_BASE)
|
146
|
+
template_name += '.conf' if File.extname(template_name) == '' # XXX this to be removed
|
147
|
+
|
148
|
+
file = File.join(templates_dir, template_name)
|
149
|
+
buffer = render :template => File.read(file)
|
150
|
+
|
151
|
+
temporary_location = "/tmp/#{template_name}"
|
152
|
+
put buffer, temporary_location
|
153
|
+
sudo "cp #{temporary_location} #{destination_file_name}"
|
154
|
+
delete temporary_location
|
155
|
+
end
|
156
|
+
|
157
|
+
# Copy configs to server(s). Note there is no :pull task. No changes should
|
158
|
+
# be made to configs on the servers so why would you need to pull them back?
|
159
|
+
def push_configs(app, files)
|
160
|
+
app = app.to_s
|
161
|
+
stage = exists?(:stage) ? fetch(:stage).to_s : ''
|
162
|
+
|
163
|
+
files.each do |file|
|
164
|
+
full_local_path = File.join('config', stage, app, file[:path])
|
165
|
+
if File.exists?(full_local_path)
|
166
|
+
# If the file path is relative we will prepend a path to this projects
|
167
|
+
# own config directory for this service.
|
168
|
+
if file[:path][0,1] != '/'
|
169
|
+
full_remote_path = File.join(deploy_to, app, file[:path])
|
170
|
+
else
|
171
|
+
full_remote_path = file[:path]
|
172
|
+
end
|
173
|
+
sudo "test -d #{File.dirname(full_remote_path)} || #{sudo} mkdir -p #{File.dirname(full_remote_path)}"
|
174
|
+
std.su_put File.read(full_local_path), full_remote_path, '/tmp/', :mode=>file[:mode]
|
175
|
+
sudo "chown #{file[:owner]} #{full_remote_path}"
|
176
|
+
else
|
177
|
+
# Render directly to remote host.
|
178
|
+
render_template(app, file.merge(:remote => true))
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def teardown_connections
|
184
|
+
sessions.keys.each do |server|
|
185
|
+
sessions[server].close
|
186
|
+
sessions.delete(server)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def append_to_file_if_missing(filename, value, options={})
|
191
|
+
# XXX sort out single quotes in 'value' - they'l break command!
|
192
|
+
# XXX if options[:requires_sudo] and :use_sudo then use sudo
|
193
|
+
sudo <<-END
|
194
|
+
sh -c '
|
195
|
+
grep -F "#{value}" #{filename} > /dev/null 2>&1 ||
|
196
|
+
echo "#{value}" >> #{filename}
|
197
|
+
'
|
198
|
+
END
|
199
|
+
end
|
200
|
+
|
201
|
+
def substitute_in_file(filename, old_value, new_value, sep_char='/')
|
202
|
+
sudo <<-END
|
203
|
+
sh -c "
|
204
|
+
perl -p -i -e 's#{sep_char}#{old_value}#{sep_char}#{new_value}#{sep_char}' #{filename}
|
205
|
+
"
|
206
|
+
END
|
207
|
+
end
|
208
|
+
|
209
|
+
# create new user account on target system
|
210
|
+
def useradd(user, options={})
|
211
|
+
options[:shell] ||= '/bin/bash' # new accounts on ubuntu 6.06.1 have been getting /bin/sh
|
212
|
+
switches = ''
|
213
|
+
switches += " --shell=#{options[:shell]} " if options[:shell]
|
214
|
+
switches += ' --create-home ' unless options[:homedir] == false
|
215
|
+
switches += " --gid #{options[:group]} " unless options[:group].nil?
|
216
|
+
invoke_command "grep '^#{user}:' /etc/passwd || #{sudo} /usr/sbin/useradd #{switches} #{user}",
|
217
|
+
:via => run_method
|
218
|
+
end
|
219
|
+
|
220
|
+
# create a new group on target system
|
221
|
+
def groupadd(group, options={})
|
222
|
+
via = options.delete(:via) || run_method
|
223
|
+
# XXX I don't like specifying the path to groupadd - need to sort out paths before long
|
224
|
+
invoke_command "grep '#{group}:' /etc/group || #{sudo} /usr/sbin/groupadd #{group}", :via => via
|
225
|
+
end
|
226
|
+
|
227
|
+
# add group to the list of groups this user belongs to
|
228
|
+
def add_user_to_group(user, group)
|
229
|
+
invoke_command "groups #{user} | grep ' #{group} ' || #{sudo} /usr/sbin/usermod -G #{group} -a #{user}",
|
230
|
+
:via => run_method
|
231
|
+
end
|
232
|
+
|
233
|
+
# create directory if it doesn't already exist
|
234
|
+
# set permissions and ownership
|
235
|
+
# XXX move mode, path and
|
236
|
+
def mkdir(path, options={})
|
237
|
+
via = options.delete(:via) || :run
|
238
|
+
# XXX need to make sudo commands wrap the whole command (sh -c ?)
|
239
|
+
# XXX removed the extra 'sudo' from after the '||' - need something else
|
240
|
+
invoke_command "test -d #{path} || #{sudo if via == :sudo} mkdir -p #{path}"
|
241
|
+
invoke_command "chmod #{sprintf("%3o",options[:mode]||0755)} #{path}", :via => via if options[:mode]
|
242
|
+
invoke_command "chown -R #{options[:owner]} #{path}", :via => via if options[:owner]
|
243
|
+
groupadd(options[:group], :via => via) if options[:group]
|
244
|
+
invoke_command "chgrp -R #{options[:group]} #{path}", :via => via if options[:group]
|
245
|
+
end
|
246
|
+
|
247
|
+
def create_src_dir
|
248
|
+
mkdir(src_dir, :mode => 0775, :group => group_src, :via => :sudo)
|
249
|
+
end
|
250
|
+
|
251
|
+
# download source package if we don't already have it
|
252
|
+
def download_src(src_package, src_dir)
|
253
|
+
set_package_defaults(src_package)
|
254
|
+
create_src_dir
|
255
|
+
# check if file exists and if we have an MD5 hash or bytecount to compare
|
256
|
+
# against if so, compare and decide if we need to download again
|
257
|
+
if defined?(src_package[:md5sum])
|
258
|
+
md5_clause = " && echo '#{src_package[:md5sum]}' | md5sum -c - "
|
259
|
+
end
|
260
|
+
case src_package[:download_method]
|
261
|
+
# when getting source with git
|
262
|
+
when :git
|
263
|
+
# ensure git is installed
|
264
|
+
apt.install( {:base => %w(git-core)}, :stable) #TODO fix this to test ubuntu version <hardy might need specific git version for full git submodules support
|
265
|
+
package_dir = File.join(src_dir, src_package[:dir])
|
266
|
+
run "if [ -d #{package_dir} ]; then cd #{package_dir} && #{sudo} git checkout master && #{sudo} git pull && #{sudo} git submodule init && #{sudo} git submodule update; else #{sudo} git clone #{src_package[:url]} #{package_dir} && cd #{package_dir} && #{sudo} git submodule init && #{sudo} git submodule update ; fi"
|
267
|
+
# Checkout the revision wanted if defined
|
268
|
+
if src_package[:version]
|
269
|
+
run "cd #{package_dir} && git branch | grep '#{src_package[:version]}$' && #{sudo} git branch -D '#{src_package[:version]}'; exit 0"
|
270
|
+
run "cd #{package_dir} && #{sudo} git checkout -b #{src_package[:version]} #{src_package[:version]}"
|
271
|
+
end
|
272
|
+
|
273
|
+
# when getting source with wget
|
274
|
+
when :http
|
275
|
+
# ensure wget is installed
|
276
|
+
apt.install( {:base => %w(wget)}, :stable )
|
277
|
+
# XXX replace with invoke_command
|
278
|
+
run "cd #{src_dir} && test -f #{src_package[:filename]} #{md5_clause} || #{sudo} wget --quiet --timestamping #{src_package[:url]}"
|
279
|
+
else
|
280
|
+
puts "DOWNLOAD SRC: Download method not recognised. src_package[:download_method]: #{src_package[:download_method]}"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# unpack src and make it writable by the group
|
285
|
+
def unpack_src(src_package, src_dir)
|
286
|
+
set_package_defaults(src_package)
|
287
|
+
package_dir = File.join(src_dir, src_package[:dir])
|
288
|
+
case src_package[:download_method]
|
289
|
+
# when unpacking git sources - nothing to do
|
290
|
+
when :git
|
291
|
+
puts "UNPACK SRC: nothing to do for git installs"
|
292
|
+
when :http
|
293
|
+
sudo <<-EOF
|
294
|
+
bash -c '
|
295
|
+
cd #{src_dir};
|
296
|
+
test -d #{package_dir}.old && rm -fr #{package_dir}.old;
|
297
|
+
test -d #{package_dir} && mv #{package_dir} #{package_dir}.old;
|
298
|
+
#{src_package[:unpack]}
|
299
|
+
'
|
300
|
+
EOF
|
301
|
+
else
|
302
|
+
puts "UNPACK SRC: Download method not recognised. src_package[:download_method]: #{src_package[:download_method]} "
|
303
|
+
end
|
304
|
+
sudo <<-EOF
|
305
|
+
bash -c '
|
306
|
+
cd #{src_dir};
|
307
|
+
chgrp -R #{group} #{package_dir};
|
308
|
+
chmod -R g+w #{package_dir};
|
309
|
+
'
|
310
|
+
EOF
|
311
|
+
end
|
312
|
+
|
313
|
+
def set_package_defaults(pkg)
|
314
|
+
pkg[:filename] ||= File.basename(pkg[:url])
|
315
|
+
pkg[:dir] ||= pkg[:filename].sub(/(\.tgz|\.tar\.gz)/,'')
|
316
|
+
pkg[:download_method] ||= :http
|
317
|
+
pkg[:unpack] ||= "tar zxf #{pkg[:filename]};"
|
318
|
+
pkg[:configure] ||= './configure ;'
|
319
|
+
pkg[:make] ||= 'make;'
|
320
|
+
pkg[:install] ||= 'make install;'
|
321
|
+
end
|
322
|
+
|
323
|
+
# install package from source
|
324
|
+
def install_from_src(src_package, src_dir)
|
325
|
+
set_package_defaults(src_package)
|
326
|
+
package_dir = File.join(src_dir, src_package[:dir])
|
327
|
+
unpack_src(src_package, src_dir)
|
328
|
+
apt.install( {:base => %w(build-essential)}, :stable )
|
329
|
+
sudo <<-SUDO
|
330
|
+
sh -c '
|
331
|
+
cd #{package_dir};
|
332
|
+
#{src_package[:configure]}
|
333
|
+
#{src_package[:make]}
|
334
|
+
#{src_package[:install]}
|
335
|
+
#{src_package[:post_install]}
|
336
|
+
'
|
337
|
+
SUDO
|
338
|
+
end
|
339
|
+
|
340
|
+
def read_database_yml
|
341
|
+
stage = exists?(:stage) ? fetch(:stage).to_s : ''
|
342
|
+
db_config = YAML.load_file(File.join('config', stage, 'database.yml'))
|
343
|
+
set :db_user, db_config[rails_env]["username"]
|
344
|
+
set :db_password, db_config[rails_env]["password"]
|
345
|
+
set :db_name, db_config[rails_env]["database"]
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
##
|
350
|
+
# Run a command and ask for input when input_query is seen.
|
351
|
+
# Sends the response back to the server.
|
352
|
+
#
|
353
|
+
# +input_query+ is a regular expression that defaults to /^Password/.
|
354
|
+
#
|
355
|
+
# Can be used where +run+ would otherwise be used.
|
356
|
+
#
|
357
|
+
# run_with_input 'ssh-keygen ...', /^Are you sure you want to overwrite\?/
|
358
|
+
|
359
|
+
def run_with_input(shell_command, input_query=/^Password/, response=nil)
|
360
|
+
handle_command_with_input(:run, shell_command, input_query, response)
|
361
|
+
end
|
362
|
+
|
363
|
+
##
|
364
|
+
# Run a command using sudo and ask for input when a regular expression is seen.
|
365
|
+
# Sends the response back to the server.
|
366
|
+
#
|
367
|
+
# See also +run_with_input+
|
368
|
+
#
|
369
|
+
# +input_query+ is a regular expression
|
370
|
+
|
371
|
+
def sudo_with_input(shell_command, input_query=/^Password/, response=nil)
|
372
|
+
handle_command_with_input(:sudo, shell_command, input_query, response)
|
373
|
+
end
|
374
|
+
|
375
|
+
def invoke_with_input(shell_command, input_query=/^Password/, response=nil)
|
376
|
+
handle_command_with_input(run_method, shell_command, input_query, response)
|
377
|
+
end
|
378
|
+
|
379
|
+
##
|
380
|
+
# Run a command using sudo and continuously pipe the results back to the console.
|
381
|
+
#
|
382
|
+
# Similar to the built-in +stream+, but for privileged users.
|
383
|
+
|
384
|
+
def sudo_stream(command)
|
385
|
+
sudo(command) do |ch, stream, out|
|
386
|
+
puts out if stream == :out
|
387
|
+
if stream == :err
|
388
|
+
puts "[err : #{ch[:host]}] #{out}"
|
389
|
+
break
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
# We don't need this. Put 'USER=root' on the command line instead.
|
395
|
+
#
|
396
|
+
# XXX Not working in deprec2
|
397
|
+
# ##
|
398
|
+
# # Run a command using the root account.
|
399
|
+
# #
|
400
|
+
# # Some linux distros/VPS providers only give you a root login when you install.
|
401
|
+
#
|
402
|
+
# def run_as_root(shell_command)
|
403
|
+
# std.connect_as_root do |tempuser|
|
404
|
+
# run shell_command
|
405
|
+
# end
|
406
|
+
# end
|
407
|
+
#
|
408
|
+
# ##
|
409
|
+
# # Run a task using root account.
|
410
|
+
# #
|
411
|
+
# # Some linux distros/VPS providers only give you a root login when you install.
|
412
|
+
# #
|
413
|
+
# # tempuser: contains the value replaced by 'root' for the duration of this call
|
414
|
+
#
|
415
|
+
# def as_root()
|
416
|
+
# std.connect_as_root do |tempuser|
|
417
|
+
# yield tempuser
|
418
|
+
# end
|
419
|
+
# end
|
420
|
+
|
421
|
+
private
|
422
|
+
|
423
|
+
##
|
424
|
+
# Does the actual capturing of the input and streaming of the output.
|
425
|
+
#
|
426
|
+
# local_run_method: run or sudo
|
427
|
+
# shell_command: The command to run
|
428
|
+
# input_query: A regular expression matching a request for input: /^Please enter your password/
|
429
|
+
|
430
|
+
def handle_command_with_input(local_run_method, shell_command, input_query, response=nil)
|
431
|
+
send(local_run_method, shell_command) do |channel, stream, data|
|
432
|
+
logger.info data, channel[:host]
|
433
|
+
if data =~ input_query
|
434
|
+
if response
|
435
|
+
channel.send_data "#{response}\n"
|
436
|
+
else
|
437
|
+
response = ::Capistrano::CLI.password_prompt "#{data}"
|
438
|
+
channel.send_data "#{response}\n"
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
end
|
445
|
+
|
446
|
+
Capistrano.plugin :deprec2, Deprec2
|