Capistrano Prompt For Server Selection


At the time I was working on a project that had two application servers on AWS EC2 running behind an EC2 load balancer. For a reason I never uncovered when I would deploy to one of the application servers the application would become unavailable for a period of time even though the other application server was not interrupted. Therefore the process to deploy the project was to deploy to one instance at a time, modifying the Capistrano recipe at least once for every release. This got old pretty fast. What I wanted was to get prompted with a numbered list of servers upon deployment, enter the corresponding number and have Capistrano deploy to that server only. Then I could swap the servers out on the EC2 load balancer, and run it again this time picking the other server.

 The Solution

I looked at a few gems that appeared to provide the desired functionality by extending Capistrano, but none of them really seemed to fit well and I wasn’t interested in redesigning the project’s deployment scheme or adding a gem for such a simple task for that matter.

With no real desire to get fancy by querying AWS for the servers I decided I could accomplish my goal with not much more than a Hash for prompt and selection management. In fact I could probably reduce the complexity by using an Array. I made a compromise between automation, stability and minimal effort.

Here is what I added to the project’s config/deploy.rb

set :servers, {'1' => 'server1', '2' => 'server2'}

def get_server_choice
  return fetch(:server_choice) if exists?(:server_choice)
  puts "Please choose one of the following servers to deploy to..."
  fetch(:servers).each {|key, name| puts "#{key}: #{name}"}
  choice = Capistrano::CLI.ui.ask("Enter number (or Cancel): ")
  if choice != 'Cancel' && fetch(:servers).keys.include?(choice)
    set :server_choice, fetch(:servers)[choice]
    return fetch(:server_choice)
    raise "User cancelled deployment or entered an invalid server choice."

role(:app) do

role(:web) do

role(:db) do
  [get_server_choice, {:primary => true}]

Perhaps some refactoring could take place in the get_server_choice method. I initially tried using a Capistrano callback but experienced major breakdown as a result.

This solution could be expanded to query the AWS EC2 API to present the list of servers, for small setups (1-3 servers) this works pretty well. Once the project grew beyond just a few servers I found the application would survive when deploying to say 4 of 8 application servers. Originally I intended to automate the entire deployment process including release to both servers one at a time, no prompts at all. While this is certainly possible, it carries some complications that were not worth solving for the project.

 The Takeaway

Sometimes it does make sense to roll your own solution, I felt this was one of those scenarios. Building your own WYSIWYG is probably an awful idea, no…it is an awful idea. Always spend a few minutes looking for an existing solution. Just don’t be afraid to build your own when you feel that you can in a fraction of the time to integrate another solution.

Please comment and tell me what you think about this or any suggestions for refactor.


Now read this

Make ActiveAdmin and Mongoid Friends Rails 3.2

I am working on an app where I wanted to use ActiveAdmin. The interesting part is we are using Mongo for the database and chose Mongoid as the ORM. At this time ActiveAdmin is not natively ORM agnostic. I found this Github Repository... Continue →