Question

I'm looking for a way to call a single Capistrano task to perform different things to different roles. Is Capistrano able to do this, or do I have write a specific task for each role?

Was it helpful?

Solution

The standard way to do this in Capistrano:

task :whatever, :roles => [:x, :y, :z] do
  x_tasks
  y_tasks
  z_tasks
end

task :x_tasks, :roles => :x do
  #...
end

task :y_tasks, :roles => :y do
  #...
end

task :z_tasks, :roles => :z do
  #...
end

So yes, you do need to write separate tasks, but you can call them from a parent task and they will filter appropriately.

OTHER TIPS

Actually no:

% cat capfile 
server 'localhost', :role2
task :task1, :roles=>:role1 do
  puts 'task1'
end
task :task2 do
  task1
end

% cap task2  
  * executing `task2'
  * executing `task1'
task1

The :roles param is passed further to run command etc but does not seem to affect whether the task is actually fired.

Sorry, didn't find the way to put a comment on comment so I've written it here.

You can also do

task :foo do
    run "command", :roles => :some_role
    upload "source", "destination", :roles => :another_role
end

Use namespacing: https://github.com/leehambley/capistrano-handbook/blob/master/index.markdown#namespacing-tasks

namespace :backup do

  task :default do
    web
    db
  end

  task :web, :roles => :web do
    puts "Backing Up Web Server"
  end

  task :db, :roles => :db do
    puts "Backing Up DB Server"
  end
end

these tasks show up in a cap -T as

backup:default 
backup:web
backup:db

There is a way, kind of. Check: http://weblog.rubyonrails.org/2006/8/30/capistrano-1-1-9-beta/ and you'll see that you can override the default roles using the ROLES environment variable.

I have a task defined as:

desc "A simple test to show we can ssh into all servers"
task :echo_hello, :roles => :test do
   run "echo 'hello, world!'"
end

The :test role is assigned to one server.

On the command line, I can run:

[james@fluffyninja bin]$ cap echo_hello ROLES=lots_of_servers

And the task will now run on the lots_of_servers role.

I have not verified that this works inside a ruby script by updating the ENV hash, but this is a good start.

Only for the record, this could be a solution using Capistrano 3:

desc "Do something specific for 3 different servers with 3 different roles"
task :do_something do
  on roles(:api_role), in: :sequence do
    # do something in api server
  end

  on roles(:app_role), in: :sequence do
    # do something in application server
  end

  on roles(:another_role), in: :sequence do
    # do something in another server
  end
end

The sever definition to perform "do_something" task in a application server would be something like:

server 'application.your.domain', user: 'deploy', roles: %w{app_role}

Then you can call the task (there are several ways to do it) and the task will execute specific instructions according to the "app_role".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top