Posted by dave
Since the presentations section of the Shiny site is gone for now as we have a reshuffle over there and I haven’t got around to putting up a presentations section here yet, I thought I would add a quick post tonight to make the slides available from the various presentations I have given recently.
If you have any questions about any of these, please contact me.
Note: I would love to put these on SlideShare but it really seems to bork on Keynote PDF’s :(
Posted by dave
I have been doing some work for a company recently who wanted to deploy their rails application using capistrano but had a problem in that their remote servers were firewalled from their development network, which included their Subversion server.
The solution still seemed absolutely ripe for automation, it just meant we had to dive into writing our own capistrano task to basically do the following:
- Check out latest version of code from subversion (svn export)
- Zip exported source up into a file
- Transfer the zipped source to the deployment server(s)
- Unzip into the relevant releases folder on the deployment server(s)
So, I spent a few hours on Sunday morning tidying up what we did and making it a little more generic and I thought I would share it on here in case anyone else would find this useful.
The capistrano task is as follows:
desc "Export source from SVN, Upload it to an SFTP location, Download it to the release path"
task :export_svn_deploy, :roles => :app do
tmp_path = "/tmp" # A path to a *local* temporary directory
sftp_server = "your.sftp.server" # The SFTP/SSH server for storage of the zipped source
sftp_user = "sftp_user" # The username for the storage server
sftp_path = "deploy_tmp" # The remote path on the storage server
tmp_tgz = "exported_src.tar.gz" # Temporary file name for the zipped source
# Export from SVN, zip and upload to the remote storage server
system "svn export -q --force #{repository} #{tmp_path}/src/"
system "cd #{tmp_path}/src/ && tar czf #{tmp_path}/#{tmp_tgz} ./"
Net::SFTP.start(sftp_server, sftp_user) do |sftp|
sftp.put_file("#{tmp_path}/#{tmp_tgz}", "#{sftp_path}/#{tmp_tgz}")
end
system "rm -rf #{tmp_path}/src && rm -f #{tmp_path}/#{tmp_tgz}"
# On each server, scp the file from the remote location and unzip it to the release_path
run "mkdir #{release_path}"
run "scp -q #{sftp_user}@#{sftp_server}:#{sftp_path}/#{tmp_tgz} #{release_path}/#{tmp_tgz}"
run "cd #{release_path} && tar xzf #{tmp_tgz} && rm #{tmp_tgz}"
end
Notes
- The remote_path on the SFTP storage server must exist or the SFTP commands will fail.
- It is assumed that you are using ssh keys and no pass phrase to connect to the SFTP server from both the client machine and also all of the remote servers, this way both the Net::SFTP and the scp commands will not need passwords to be sent.
- The mkdir #{release_path} before the scp should not be needed if this is being used in a real deployment, let the regular capistrano tasks take care of that
- I chose to use Net::SFTP on the client to upload the file because this script was originally developed for a client using Windows and Net::SFTP works whereas shelling out to do an scp, wouldn’t. The rest of this cleaned up task however would need some modification to work on Windows as it stands as the tar commands would fail.
- This blog post needs less notes ;)
Next Steps
I am pretty sure that the best way to implement this would be as a custom source control plugin for capistrano so by doing:
set :scm, :svn_via_sftp
and have some extra options to specify SFTP server name and user account then this process could be completely seamless with a regular cap deploy.
I would be really interested to see if this is a common scenario, I suspect it will be with larger clients who do not want their SCC systems exposed to the web. Is anyone in this situation?