Allows Capistrano roles to be defined as lazily evaluated blocks, the same way variables are. Contrived example:
role :web do
Resolv.getaddresses('www.example.com')
end
My purpose here is for the case where we know a role exists, and we know which roles apply to which tasks, but we don't necessarily know what servers those roles contain until runtime. Specifically, an EC2 cluster -- if load gets high, and the cluster automagically fires up another instance (server), it should be added to the appropriate roles.
Without this patch, that would mean checking in a new deploy.rb whenever you bring up a new server, or down an unused one.
A nice side effect is potential for DRY, in the case that any configuration data was already somewhere other than Capistrano. Or even within Capistrano:
# I only use :db for migrations, so I can just pick any app server
role :db do
servers = find_servers :roles => :app
master = servers.first
ServerDefinition.new(master.to_s, master.options.merge({:primary => true}))
end
Some rough documentation (or read the test cases):
Roles do stack as they always did:
role :huge, 'one'
role :huge, 'two' do
'three'
end
role :huge do
['four', 'five']
end
# :huge is now ['one','two','three','four','five']
Options are handled correctly:
role :db, 'slave.db.example.com'
role :db, :primary => true do
find_master
end
They can be overridden individually:
role :db, :random => :option, :primary => true do
['slave.db.example.com', {:primary => false, :other => :option}]
end
# 'slave.db.example.com' now has options :random => :option, :primary => :false, :other => :option
Or the block can override all options, wholesale, by returning one or more ServerDefinitions:
role :db, :option1 => :foo do
ServerDefinition.new 'special.exmaple.com', :option2 => :bar
end
# 'special.example.com now has options :option2 => :bar