Hudson, Capistrano and SSH
Our corporate heritage is Rails and so we’ve standardized on Capistrano for all our deployment needs. Yes, even our Java deployments are Cap based (it’s actually pretty cool and one of these days I’ll write a post about it). We also use Hudson as our CI server. Actually, its the nerve center of all our build and deploy processes. It should be no problem then to do a bit of Continuous Deployment magic using Hudson and Capistrano.
You would think so. But you would be wrong.
You see, to execute Cap, you need to have Hudson spawn a shell process (I think it is actually a thread, but whatever). And that shell has only a minimal environment.
Why is that a problem? Well, Cap is based on ssh and once you have a number of machines to access you quickly move away from using passwords to public keys to negotiate sessions. These public keys are (on unix) stored in the user’s .ssh directory — of which the Hudson spawned shell has no idea about. This results in this sort of error:
+ cap deploy
* executing `deploy'
* executing `deploy:update'
** transaction: start
* executing `deploy:update_code'
updating the cached checkout on all servers
* executing "some command"
servers: ["monkey.goucher.ca"]
Password: stty: standard input: Invalid argument
stty: standard input: Invalid argument
stty: standard input: Invalid argument
Ugh-oh. No key means no access which means no deploy.
An hour later I did manage to figure out a nice, neat solution.
The trick is to tell Cap, not the shell, where the key you want to use is. In order to do this you need to add this somewhere in your Capfile
ssh_options[:keys] = %w(/hudson/.ssh/id_rsa)
Obviously, if you user is not ‘hudson’ you would change it to whatever it is. Likewise if you are using DSA rather than RSA for your key.
Now you can run your Cap tasks from within Hudson. And not have a busted build. 🙂