Python Fabric任务能否调用其他任务并尊重它们的主机列表?

31 投票
4 回答
8161 浏览
提问于 2025-04-16 13:55

我有一个像下面这样的fabfile:

@hosts('host1')
def host1_deploy():
    """Some logic that is specific to deploying to host1"""

@hosts('host2')
def host2_deploy():
    """Some logic that is specific to deploying to host2"""

def deploy():
    """"Deploy to both hosts, each using its own logic"""
    host1_deploy()
    host2_deploy()

我想要做的是

fab deploy

并且希望它等同于

fab host1_deploy host2_deploy

换句话说,就是运行每一个子任务,并且每个子任务都使用它自己指定的主机列表。不过,这样做并不奏效。相反,deploy()这个任务想要有自己的一份主机列表,并且会把这个列表传递给所有的子任务。

有没有办法更新deploy()这个任务,让它按照我的想法工作,同时又不影响子任务,这样它们就可以单独运行?

4 个回答

1

可能有更好的处理方法,不过你可以把两个主机都传给deploy()函数,然后在host1_deploy()和host2_deploy()这两个函数里检查env.host的值:

def host1_deploy():
    if env.host in ['host1']:
         run(whatever1)

def host2_deploy():
    if env.host in ['host2']:
         run(whatever2)

@hosts('host1','host2')
def deploy():
    host1_deploy()
    host2_deploy()
3

这听起来有点无聊,但在Fabric 1.1.2版本下是有效的。

def host1_deploy():
    """Some logic that is specific to deploying to host1"""
    if env.host in ["host1"]:
        pass #this is only on host2

def host2_deploy():
    """Some logic that is specific to deploying to host2"""
    if env.host in ["host2"]:
        pass #this is only on host2

def deploy():
    """"Deploy to both hosts, each using its own logic"""
    host1_deploy()
    host2_deploy()

这是我的测试代码:

@task
@roles(["prod_web","prod_workers"])
def test_multi():
    test_multi_a()
    test_multi_b()

def test_multi_a():
    if env.host in env.roledefs["prod_web"]:
        run('uname -a')

def test_multi_b():
    if env.host in env.roledefs["prod_workers"]:
        run('uname -a')
31

从Fabric 1.3开始,execute这个助手功能可以用来做这个事情。你可以在这里找到相关的文档:智能执行任务的使用方法

下面是他们使用的一个例子:

from fabric.api import run, roles, execute

env.roledefs = {
    'db': ['db1', 'db2'],
    'web': ['web1', 'web2', 'web3'],
}

@roles('db')
def migrate():
    # Database stuff here.
    pass

@roles('web')
def update():
    # Code updates here.
   pass

然后可以从另一个任务deploy中运行migrateweb这两个任务:

def deploy():
    execute(migrate)
    execute(update)

这样做会遵循这些任务所设定的角色和主机列表。

撰写回答