Reputation: 2302
Is there a way for execute
in fabric to respect a decorator (other than host
, hosts
, role
, roles
and exclude_hosts
--- see here), or another way to accomplish something like that)? Here is a use case:
from fabric.api import task, execute, run, runs_once
@task
def setup_environment():
# ... set up env.hosts, env.roledefs, env.use_ssh_config, etc.
@task
def provision():
# ... do some stuff on each host here, e.g. install mongodb
@task
def is_primary():
return run('mongo --quiet --eval "db.isMaster().ismaster"') == 'true'
@task
@runs_once
def change_to_primary():
env.hosts = []
for host, result in execute(is_primary, roles=('mongo',)).iteritems():
if result:
env.hosts.append(host)
@task
def add_user():
# ... do something here that needs to be done on primary
This is fine if I run the following sequence of tasks from the command line:
> fab setup_environment provision change_to_primary add_user
But since I always run change_to_primary
and add_user
as part of provisioning, I would like to modify provision
so that I can run fab setup_environment provision
and have set_primary
and add_user
be executed, something like this:
@task
def provision():
# ... do some stuff on each host here, e.g. install mongodb
execute(change_to_primary)
execute(add_user)
However, this executes change_to_primary
many times (does not run once), unlike the command line usage. Is there a way to accomplish this?
Upvotes: 0
Views: 1050
Reputation: 1564
One way would be to execute the task on all nodes with the mongo
role using the roles
decorator, and begin the task by checking if the node is actually a primary:
@task
def provision():
execute(stuff_to_do_on_all_hosts)
execute(stuff_to_do_on_mongo_primaries)
@task
def stuff_to_do_on_all_hosts():
do_stuff()
@task
@roles('mongo')
def stuff_to_do_on_mongo_primaries():
if not is_primary():
return
add_user()
do_other_stuff()
Another way would be to first build the list of primaries, then use the hosts
parameter to execute
:
@task
def provision():
# ... do some stuff on each host here, e.g. install mongodb
execute(stuff_to_do_on_all_hosts)
# build list of mongo primaries
primaries = [host for host, result in execute(is_primary, roles=('mongo',)).iteritems() if result]
# run task only on those hosts
execute(stuff_to_do_on_mongo_primaries, hosts=primaries)
@task
def stuff_to_do_on_all_hosts():
do_stuff()
@task
def stuff_to_do_on_mongo_primaries():
add_user()
do_other_stuff()
Hope this helps.
Upvotes: 1