Python fabric任务是否可以执行其他任务并尊重decorator,例如运行一次?

Python fabric任务是否可以执行其他任务并尊重decorator,例如运行一次?,python,fabric,Python,Fabric,有没有一种方法可以让结构中的执行来尊重装饰者(除了主机、主机、角色、角色和排除(主机--请参阅)之外,或者其他方法来完成类似的事情?下面是一个用例: 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():

有没有一种方法可以让结构中的
执行
来尊重装饰者(除了
主机
主机
角色
角色
排除(主机
--请参阅)之外,或者其他方法来完成类似的事情?下面是一个用例:

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
如果我从命令行运行以下一系列任务,这很好:

> fab setup_environment provision change_to_primary add_user
但由于我总是运行
change_to_primary
add_user
作为资源调配的一部分,我想修改
provision
,这样我就可以运行
fab setup_environment provision
并执行
set_primary
add_user
,如下所示:

@task
def provision():
    # ... do some stuff on each host here, e.g. install mongodb
    execute(change_to_primary)
    execute(add_user)

但是,与命令行用法不同,它会多次执行
change_to_primary
(不会运行一次)。有什么方法可以实现这一点吗?

一种方法是使用
角色
装饰器在具有
mongo
角色的所有节点上执行任务,并通过检查节点是否实际上是主节点来开始任务:

@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()
另一种方法是首先构建原色列表,然后使用
hosts
参数执行
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()

希望这能有所帮助。

谢谢您的回复,很抱歉我直到现在才看到它!