Initial version

This commit is contained in:
Gregory Colpart 2010-10-03 02:43:54 +02:00
commit 6de43a4ca4
6 changed files with 335 additions and 0 deletions

111
README Normal file
View file

@ -0,0 +1,111 @@
Evolistrano
~~~~~~~~~~~
Evolistrano is a small tool for source code deployment on several WWW servers.
It's more a "proof of concept" to show that an home-made shell script is often
better that generic tool like Capistrano (great tool) or Fredistrano.
Evolistrano has killer-features like deployment on several WWW servers
with *instant* deployment if you have a load-balancer like HAProxy,
incremental storage on WWW server to server multiples version of your code,
calculate available space before uploading, etc.
____ WWW server 0 (preprod & prod)
/ ___WWW server 1 (preprod & prod)
/ / __WWW server 2 (preprod & prod)
Dev server / / /
(SVN, SSH, --> Evolistrano -->--------
etc.) \ ___WWW static server 0
\___WWW static server 1
svn:// -> $subdocroot/{prod,preprod}/current
svn:// $staticfilesdir -> $subdocroot/static
INSTALLATION
------------
On dev server
~~~~~~~~~~~~~
* Download evolistrano on http://git.evolix.org
* Copy evolistrano/ where you want and secure rights
(for example, add "deploy" group, and authorize
only this group to access it => to allow deployment,
we just had the user on this group!)
* Generate an SSH key, for example:
ssh-keygen -f deploy.key
... and ajust rights because SSH is very strict:
chown root:deploy deploy.key*
chmod 640 deploy.key.*
* Read and configure evolistrano.conf file
* You have probably specific files which are not in repository
(for example conf file)... then centralize them here and
edit section "Deploy conf files" in evolistrano.sh
* You need also probably specific rights on you source code
(for example adding write permission)... then
edit section "UNIX rights" in evolistrano.sh
* If you need specific actions on WWW servers or whatever
(SQL updates, etc.)... just edit sectionS "ADD SPECIFIC ACTIONS"
On remote servers
~~~~~~~~~~~~~~~~~
* Add "deploy" et "deploy-preprod" users on your WWW servers
and "deploy" user on your static servers. Users should
be in www group for adding easily write permissions!
And add with authorization for new SSH key.
* Point DocumentRoot to $subdocroot/prod/current
on your WWW servers for production and to
$subdocrootpre/prod/current for preproduction
* Point DocumentRoot to $subdocroot/static
on your static servers
USAGE
-----
Deploy for preproduction:
% evolistrano.sh <SVN revision>
Deploy your static files:
% evolistrano.sh -S
Deploy for production:
% evolistrano.sh -P <SVN revision>
FAQ
---
Q: Can I have remote SVN?
A: Probably, but we don't test it. If you do, let us know if it works.
Q: Which language is used for Evolistrano?
A: Shell.
Q: What are the depends for Capistrano?
A: Shell, SVN client, SSH client, rsync.
Written for Linux, but you can use it on *BSD with some changes.
Q: Your tool is just 1% of Capistrano, why you do this crap?
A: Use Capistrano.
Q: Is your tool production-ready?
A: We use it on production environment, but you can't use it without read source code
to be sure it will do the job.
Q: Evolistrano lacks of foo feature.
A: Send us patch.

0
conf-preprod/.empty Normal file
View file

0
conf-prod/.empty Normal file
View file

51
evolistrano.conf Normal file
View file

@ -0,0 +1,51 @@
###################################
#### Evolistrano Configuration ####
###################################
# WWW list
wwwlist="www00.example.com www01.example.com www02.example.com"
# sub DocumentRoot (DocumentRoot will be $subdocroot/prod/current)
subdocroot="/srv/www"
# Exclude list for deploying
excludelist="--exclude global.ini --exclude database.ini --exclude config.ini"
# Static (CSS/JS/IMG/etc.) list
# TODO: Gerer Amazon S3/CloudFront
staticlist="static00.example.com static01.example.com"
# SSH key
sshkey="deploy.key"
# SSH port
sshport="22"
# logs
logdir="log"
# tmp dir
tmpdir="/var/tmp"
# Deploy SSH/RSYNC users
deployproduser="deploy"
deploypreproduser="deploy-preprod"
# Compute space before deply
calculspace="true"
# Stop HTTP service waiting last deploy
veryhighcritical="true"
# Use hardlinks ?
usehardlinks="true"
# SVN branch path for WWW code
# TODO: Git support
svnpath="file:////svn/project/branches/stable"
# Path for static files in repository
staticfilesdir="static"
# email address for notification (empty if no notification)
mailnotif=""

173
evolistrano.sh Executable file
View file

@ -0,0 +1,173 @@
#!/bin/sh
set -e
set -u
export LC_ALL=C
full_path=`echo $(dirname $(readlink -f $0))`
. $full_path/evolistrano.conf
tmp_dir=`mktemp -p $tmpdir -d`
dir_export=$tmp_dir/export
time_stamp=`date +%s`
usage() {
cat <<EOT
Usage: $0 [OPTION] REVNUM
Sans option : Mise en preproduction
-P : Mise en production
EOT
exit 1
}
read_confirm() {
read ok
if [ "$ok" != "y" ]; then
exit 1
fi
}
[ $# -lt 1 ] && usage
if [ $1 == "-P" ]; then
prod=1
shift
else
prod=0
fi
[ $# -lt 1 ] && usage
revnum=$1
if [ $prod -eq 1 ]; then
log_file=$logdir/prod.log
opname="PRODUCTION"
destdir="prod"
sshuser=$deployproduser
staticdestdir="prod/static"
confdir=$confproddir
else
log_file=$logdir/preprod.log
opname="preprod"
destdir="preprod"
sshuser=$deploypreproduser
staticdestdir="preprod/static"
confdir=$confpreproddir
fi
# Display infos about deployement
echo
svn info $svnpath -r $revnum
echo -n "Confirmer la mise en $opname de la révision $revnum ? [y/N] "
read_confirm
# Warning if it's not the last revision
last_commited_rev=`svn info $svnpath | grep ^Revision | sed 's/.*: \([0-9]\+\)$/\1/'`
if [ $revnum -ne $last_commited_rev ]; then
echo -n "Attention, la révision $revnum n'est pas la plus récente. Continuer ? [y/N] "
read_confirm
fi
tmpfile=`mktemp -p $tmpdir`
cat <<EOT >$tmpfile
Date : `date`
User : $LOGNAME
Revision : $revnum
EOT
# Send email notification
[ $prod -eq 1 ] && [ "$mailnotif" != "" ] && ( cat $tmpfile | mail -s "[Evolistrano] Mise en prod" $mailnotif )
cat $tmpfile >>$log_file
rm $tmpfile
#
umask 022
svn export -r $revnum -q $svnpath $dir_export
echo
echo "SVN export to $dir_export"
echo
#set +e
# Deploy on WWW servers
for remote in $wwwlist; do
# Be sure to have space for deploying
local_space=`du -sm $dir_export/ | sed 's/^\([0-9]\+\)\t.*$/\1/'`
remote_space=`ssh -p $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote df -lPm $subdocroot | grep ^/ | tr -s " " | cut -d" " -f4`
if [ $local_space -ge $remote_space ]; then echo "WARNING... $remote has only $remote_space Mo while you want upload $local_space Mo. Do you want stop ? [y/N]"; read_confirm; fi
echo "sending code on $remote"
if [ "$usehardlinks" = "true" ]; then
rsync -rlptq --link-dest=../current -e "ssh -p $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey" $dir_export/ --delete $excludelist $sshuser@$remote:$subdocroot/$destdir/$time_stamp
else
rsync -rlptq -e "ssh -p $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey" $dir_export/ --delete $excludelist $sshuser@$remote:$subdocroot/$destdir/$time_stamp
fi
# Deploy conf files => UNCOMMENT AND ADJUST LINES
#scp -q -P $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $full_path/conf-$destdir/foo-global.ini $sshuser@$remote:$subdocroot/$destdir/$time_stamp/config/config/foo/global.ini
#scp -q -P $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $full_path/conf-$destdir/foo-database.ini $sshuser@$remote:$subdocroot/$destdir/$time_stamp/config/config/foo/database.ini
#scp -q -P $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $full_path/conf-$destdir/bar-config.ini $sshuser@$remote:$subdocroot/$destdir/$time_stamp/config/config/bar/config.ini
# UNIX rights => ADJUST ALL RIGHTS, PARTICULARLY FOR ADDING WRITE PERMISSIONS
ssh -p $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote chmod -R g+rX,o+rX $subdocroot/$destdir/$time_stamp
#ssh -p $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote chmod -R g+w $subdocroot/$destdir/$time_stamp/cache
# ADD SPECIFIC ACTIONS ON WWW SERVERS
done
for remote in $staticlist; do
#TODO: calculer la taille de la destination (df $subdocroot) && pas de deploiement si cela depasse !!
# Be sure to have space for deploying
local_space=`du -sm $dir_export/www/static/ | sed 's/^\([0-9]\+\)\t.*$/\1/'`
remote_space=`ssh -p $sshport -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote df -lPm /var/www/$staticdestdir | grep ^/ | tr -s " " | cut -d" " -f4`
if [ $local_s -ge $remote_s ]; then echo "WARNING... $remote has only $remote_s Mo while you want upload $local_s Mo : stop deploy now with Ctrl+C"; read enter; fi
echo "sending static on $remote"
rsync -rlptq -e "ssh -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey" $dir_export/$staticfilesdir --delete $excludelist $sshuser@$remote:$subdocroot/static
ssh -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote chmod -R g+rX,o+rX $subdocroot/static
done
# Enable new code
last_frontal=`echo -n $wwwlist | sed 's/.* \+\([^ ]\+ *\)$/\1/'`
for remote in `echo -n $wwwlist | sed "s/$last_frontal//"`; do
if [ $prod -eq 1 ]; then
echo "stopping Apache on $remote"
ssh -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote sudo /etc/init.d/apache2 stop
fi
# Change symlink current to new code
ssh -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote "rm $subdocroot/$destdir/current && cd $subdocroot/$destdir && ln -s $time_stamp current"
if [ $prod -eq 1 ] && [ "$veryhighcritical" != "true" ]; then
echo "starting Apache on $remote"
sleep 3 && ssh -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote sudo /etc/init.d/apache2 start
fi
done
for remote in $last_frontal; do
ssh -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote "rm $subdocroot/$destdir/current && cd $subdocroot/$destdir && ln -s $time_stamp current"
done
if [ "$veryhighcritical" = "true" ]; then
for remote in `echo -n $wwwlist | sed "s/$last_frontal//"`; do
echo "starting Apache on $remote"
ssh -o UserKnownHostsFile=$full_path/known_hosts -i $full_path/$sshkey $sshuser@$remote sudo /etc/init.d/apache2 start
done
fi
# ADD SPECIFIC ACTIONS (SQL DEPLOYMENT, etc.)
rm -rf $tmp_dir

0
log/.empty Normal file
View file