Capistrano 2.5.0

Posted by Jamis on Friday, August 29

Capistrano 2.5 is now available, with several new additions and a fair helping of bug fixes and general improvements. To install it:

gem install capistrano

Here’s a rundown of what’s new:

parallel() helper

A common question by people learning Capistrano is “how can I tell what the current server is?” There still isn’t a good answer to this (since Capistrano executes each command against all active servers in parallel) but Cap 2.5 introduces the “parallel” helper that might just make the question moot.

An example is worth 1,000 words:

1
2
3
4
5
6
7
task :restart_everything do
  parallel do |session|
    session.when "in?(:app)", "/path/to/restart/mongrel"
    session.when "in?(:web)", "/path/to/restart/apache"
    session.when "in?(:db)", "/path/to/restart/mysql"
  end
end

When you execute that hypothetical :restart_everything task, the parallel helper compares all active servers against the conditions. All matching conditions for a server indicate which command(s) will be run against that server, and then all those commands (for all matching servers) are run in parallel. (In this case, the mongrels would be restarted on the app servers at the same that apache is being restarted on the web servers, and mysql is being restarted on the db servers.)

The only way to do something similar before 2.5 was to invoke 3 separate run commands, which would run the commands serially, instead of in parallel.

You can pass callback blocks to each condition, as well, to handle output specially for each case:

1
2
3
session.when "in?(:app)", "/path/to/restart/mongrel" do |channel, stream, data|
  # same format of callback as you would give to run() or sudo()
end

You can also specify a fallback condition, to be used when a server fails to match any of the conditions:

1
session.else "/execute/something/else"

Lastly, the string specifying the condition must evaluate to valid Ruby code. Inside it, you can access the in?() helper (to query whether the current server is included in the given role), as well as a “server” variable that you can use to match specific hosts by name:

1
session.when "server.host =~ /app/", "/command/to/execute"

This should allow some exciting new usage patterns to emerge. Please share what you come up with!

Chained gateways

Prior to 2.5, Capistrano was not easily able to accomodate servers that needed to be accessed via two or more gateway machines. In 2.5, the gateway variable can now be an array of hostnames, and the gateway will tunnel through all of them:

1
set :gateway, %w(jamis@gateway.host deeper.host final.host)

In that example, each server would be connected to via a triply-chained gateway, tunneling from the local server to the final host via gateway.host (using “jamis” as the username), then deeper.host, and then final.host.

“-s” and “-S” infer the types of their arguments

When you set a variable from the command-line (using -s or -S), the type of the value will now be inferred. This allows you to set booleans, integers, floating point values, and nil values from the command-line, as well as strings (the fallback if a type cannot be inferred).

deploy:rollback and mongrel

Prior to 2.5, deploy:rollback would fail with mongrel processes that were spawned via Rails’ script/process/spawner tool. This was because the mongrel processes were restarted after the bad revision was removed, resulting in mongrel dying because it’s current working directory was invalid.

In 2.5, the bad revision is not actually removed until after the restart happens.

Dry-run mode

Prior to 2.5 you could use the "-d" (--debug) switch to step through your recipes. In 2.5, this is expanded with the "-n" (--dry-run) switch, which will run the tasks straight through, but will not actually invoke any of the (remote) commands. (Local commands are still executed.)

Other changes and bug fixes

From the change-log:

  • Allow HOSTS spec to override even non-existent roles
  • Sort releases via “ls -xt” instead of “ls -x” to allow for custom release names
  • Add descriptions of -n and -d to the verbose help text
  • Rename deploy:rollback_code to deploy:rollback:code
  • Make sure a task only uses the last on_rollback block, once, on rollback
  • Add :shared_children variable to customize which subdirectories are created by deploy:setup
  • Allow filename globbing in copy_exclude setting for the copy strategy
  • Allow remote_cache strategy to use copy_exclude settings (requires rsync)
  • Make None SCM module work in Windows
  • Recognize mingw as a Windows platform
  • Fixed failing tests in Windows
  • Made :scm_auth_cache control whether password option is emitted in subversion module
  • Fixed timestamp bug in CVS module

Feedback

As ever, please report bugs via the Capistrano issue tracker. If you’d like to submit a patch, please make sure it applies cleanly on the latest version of the source code, and submit it either via the issue tracker above, via email, or via GitHub pull request.

Lastly, the Capistrano mailing list is a great place to ask and answer questions, and to swap tips and tricks. There is also an IRC channel you can use: #capistrano on irc.freenode.net. (The IRC channel requires a bit of patience, since your question might not be noticed right away.)

Thanks!

Comments

1 Glenn Gillen 29 Aug 2008
Once again nice work Jamis. I've not had a major issue with parallel vs serialized calls but I'm hopeful it will speed up a few of my tasks. The big one for me here though is :shared_children, should make life much easier when deploying things like RadiantCMS
2 John Topley 29 Aug 2008
Great work, Jamis! Capistrano is an awesome tool.
3 z.x.l 03 Sep 2008
thank you
4 Fernando 11 Sep 2008
Hi Jamis, thanks for all the great work. Hi (and thanks too) to anybody else reading that may help me. I have a doubt, I think you may be able to resolv. I use tasks for staging, such as # CALLING: cap production deploy task :testing do role :web, "10.0.0.253" role :app, "10.0.0.240" end And I overwrite part of deploy and web namespaces for i18n/customizacion namespace :deploy do [ :stop, :start, :restart ].each do |t| desc "#{t.to_s.capitalize} thin cluster" task t, :roles => :app, :except => { :no_release => true } do ...my_custom_cluster_restart... end end namespace :web do desc <<-desc> :web, :except => { :no_release => true } do ...almost standart code.... end But when I call: cap testing deploy:update I get * executing `testing' * executing `deploy:update' ** transaction: start * executing `deploy:update_code' * executing "svn export -q --username whatever --password ******** --no-auth-cache -r2165 svn://svn.myserver.es/prog /var/apps/prog/releases/20080911115040 && (echo 2165 > /var/apps/prog/releases/20080911115040/REVISION)" servers: ["10.0.0.253", "10.0.0.240"] <---!!!!!!!!!! ... It tries to deploy on the :app server (ok) but also in the :web (not ok!) I suposse there is something I am missing in the whole role definition thing, but, if there are a n App(backend/rails) and a Web(Frontend/nginx): Is it not more logical to deploy source to the app server and disable/enable access on teh web server? Thank you very much in advance.
5 Fernando 11 Sep 2008
Sorry for last comment, i thought it would keep format/newlines. code is well formatted here: http://pastie.org/270407 Question is: I suposse there is something I am missing in the whole role definition thing, but, if there are a n App(backend/rails) and a Web(Frontend/nginx): Is it not more logical to deploy source to the app server and disable/enable access on teh web server? Thank you very much in advance.
6 Telum 11 Sep 2008
Does this fix the git bug introduced after v2.2.0? $ cap deploy * executing `deploy' * executing `deploy:update' ** transaction: start * executing `deploy:update_code' fatal: '/gitrepo/project': unable to chdir or not a git archive [...] /usr/local/lib/ruby/gems/1.8/gems/capistrano-2.4.3/lib/capistrano/recipes/deploy/scm/git.rb:217:in `query_revision': Unable to resolve revision for 'HEAD' on repository '/gitrepo/project'. (RuntimeError)
7 Fernando 12 Sep 2008
I found my question (#4 and #5) was already answered by Jamis here: http://groups.google.com/group/capistrano/browse_thread/thread/9ca629d5ea9deb5f In case anybody gets here searching the same thing.
8 Pirkka 03 Oct 2008
I'm battling with the same problem as Telum. I'll report back if i find anything...
9 Andy Jeffries 05 Oct 2008
Telum/Pirkka, I've got so used to typing: cap _2.2_ deploy now, that it will feel completely weird when Jamis fixes this longstanding bug and I can just cap deploy again :-)
10 Walther H Diechmann 07 Oct 2008
Hi Jamis, cap'ing sure is enjoyment to the limit :) but - I recently offered a friend some space on my deployment server and we decided on using gitosis on this Linux box - and I added a user for him to use for deployment. I do the cold deploys with root and his ssh works flawless. Our repositories are in /home/git/repositories and when he tries to deploy - cap shokes on this directory, complaining that the project.git is not there! being this other user probably means that he has no access to the project.git - how to we set that up in the deploy.rb? thanx for a wonderful tool!
11 Tim 25 Oct 2008
I still get the same error as comment #6. Every friggin release the same thing happens (and is reported multiple times in the comments), but still no fix or any suggestion on good. Guess I have to keep using the slow copy deploy method to get around it. Least I don't have to use this piece of crap library for my personal projects. Just at work.. Ugghh.. Rails is the suck
12 Jamis 07 Nov 2008
@Tim, I've never even seen this error reported before on the mailing list, which is where errors should be reported. I don't really offer support via blog comments. :( I use git to deploy all the time, and have never had that problem. Please do post to the mailing list (http://groups.google.com/group/capistrano) with more info and I'll be happy to help troubleshoot.
13 Eric Kidd 08 Nov 2008
6, 8, 9 and 11: Try adding the following line to deploy.rb: set :branch, "master" I've also submitted a patch to Jamis.
14 Rod 10 Nov 2008
Not sure what it is about 2.5.0 that breaks things, but downgrading to 2.4.3 fixed the error... sudo gem install -v 2.4.3 capistrano
15 kelyar 12 Nov 2008
13 - thanks!
16 Bryce 12 Nov 2008
Same problem as #6, only I just upgraded to 2.5.1 from 2.5.0. running cap _2.5.0_ deploy solves it, so thanks to Andy for that hint. :)
17 Si 13 Nov 2008
Cheers Eric, that advice hit the spot
18 Tim Harper 13 Nov 2008
Just for clarification - the Tim on #11 is not me. Jamis, I have a fond appreciation for your ability to be tolerant when faced with meatheads. @Tim (#11) - a suggestion: 1) Find the problem. 2) Write a regression test that shows the breakage. (and, optionally fix the breakage) 3) Fork on github. Commit. Send a pull request. Jamis is awesome about accepting patches. 4) Feel good for having removed an obstacle out of your own way (for good), and for others.
:
: (optional)
: (optional)
: