Getting Capistrano destination hosts from Puppet

26 11 2011

If you’re using Capistrano to deploy code to web servers and Puppet to manage those servers, the DRY principle suggests that it may be a bad idea to hardcode your list of web servers in your Capistrano recipe — instead, you may want to dynamically fetch the list of web servers from Puppet prior to each deploy. Here’s one way of doing this.

Puppetmaster Configuration

First, you’ll need to turn on storeconfigs on your Puppetmaster. This allows Puppet to store all of its node information in a database (which enables us to access it for other purposes). Note that these instructions assume you have a MySQL database for your storeconfigs.

Next, create a script on your Puppetmaster called /usr/local/bin/list_nodes_by_class.rb. Fill in the database username, password, host and schema name used to access your storeconfigs in lines 4-7. Make sure the script is executable.

require 'mysql'


QUERY="select from hosts h join resources r on = r.host_id join resource_tags rt on = rt.resource_id join puppet_tags pt on rt.puppet_tag_id = where = 'class' and r.restype = 'Class' and r.title = '#{ARGV[0].gsub("'","")}' order by;"

res = my.query(QUERY)
res.each_hash { |row| puts row['name'] }

Capistrano Recipe Modification

Note that I’ll assume here that your Capistrano recipe uses the “web” role to determine where to deploy code to, and that the Puppet class you use to designate web servers is “role_webserver” — you may need to change these.

First, add the following task and helper function to your recipe:

task :set_roles_from_puppet, :roles => :puppetmaster do
 get_nodes_by_puppet_class('role_webserver').each {|s| role :web, s}

def get_nodes_by_puppet_class(classname)
 hosts = []
 run "/usr/local/bin/list_nodes_by_class.rb #{classname}", :pty => true do |ch, stream, out|
 out.split("\r\n").each { |host| hosts << host }

Next, go to wherever you’re defining your roles. Add a role for your Puppetmaster:

role :puppetmaster,  ""

Finally, delete your existing definition of the “web” role and replace it with the following:


Now, when you do a Capistrano deploy, the destination servers should be dynamically retrieved from the Puppet database.