Fabric env.roledefs 未按预期工作

10 投票
4 回答
1895 浏览
提问于 2025-04-21 08:47

fabric网站上,有一个这样的例子:

from fabric.api import env

env.roledefs = {
    'web': {
        'hosts': ['www1', 'www2', 'www3'],
        'foo': 'bar'
    },
    'dns': {
        'hosts': ['ns1', 'ns2'],
        'foo': 'baz'
    }
}

根据我从文档中了解到的,这个设置应该让环境字典中的键'foo'在执行时在主机'www1'、'www2'和'www3'上都有'bar'这个值。不过我没有得到这样的结果,尽管fabric确实能正确识别主机。这里有一个fabfile的例子:

env.foo = 'WRONG'
@task()
def set_role():
    env.roles.append('web')

@task()
def print_foo():
    print env.foo

这个例子中的命令:

fab set_role print_foo

意外的输出结果:

[www1] Executing task 'print_foo'
WRONG
[www2] Executing task 'print_foo'
WRONG
[www3] Executing task 'print_foo'
WRONG

Done.

我是不是误解了这个的目的?我该如何让一台服务器看到一个键的不同值,而另一台服务器看到另一个值,而不需要太多麻烦呢?

我使用的是fabric 1.10.0

4 个回答

0

如果你想让某个任务的额外角色定义(roledef)键自动设置在env里,你可以使用一个装饰器。下面是我正在使用的装饰器:

from functools import wraps

def apply_role(f):
    "Decorator to apply keys in effective roledef to current env."
    @wraps(f)
    def wrapper(*args, **kwargs):
        if env.effective_roles:
            for k, v in env.roledefs[env.effective_roles[0]].items():
                if k in env and isinstance(env[k], list) and isinstance(v, list):
                    env[k].extend(v)
                elif k in env and isinstance(env[k], list):
                    env[k].append(v)
                else:
                    env[k] = v
        return f(*args, **kwargs)
    return wrapper

接着,你可以给任何想要应用角色定义键的任务加上这个装饰器:

@apply_role
def mytask():
    ...
1

这只是对这个问题的一个回答:

env.roledefs = {
    'prod': {
        'hosts':['server1','server2'],
        'path':'/opt/prod'
        },
    'stag': {
        'hosts':['server3','server4'],
        'path':'/opt/stag'
        }
}

@roles('prod')
def runa():
    role = env.effective_roles[0]
    print env.roledefs[role]['path']
3

这里有两个问题。首先,使用的fabric版本比基于字典的定义要旧,所以它把键当成了主机名来解释。要解决这个问题,可以升级到fabric 1.10.0或更高版本。其次,这里定义的设置不会自动填充到环境变量中,但如果你使用一个任务来设置角色,可能可以像这样设置:

@task
def set_role(role_name):
    env.roles.append(role_name)
    for k, v in env.roledefs[role_name].iteritems():
        if k == 'hosts':
            continue
        env[k] = v

调用时使用:

fab set_role:dns do_my_task
2

我也对此感到困惑。结果发现,在Fabric 1.11中,可以访问这些内容了:

https://github.com/fabric/fabric/issues/1276

撰写回答