25

这是一个非常特定于Fabric的问题,但更有经验的 python 黑客可能能够回答这个问题,即使他们不了解 Fabric。

我试图在命令中指定不同的行为,具体取决于它运行的角色,即:

def restart():
    if (SERVERTYPE == "APACHE"):
        sudo("apache2ctl graceful",pty=True)
    elif (SERVERTYPE == "APE"):
        sudo("supervisorctl reload",pty=True)

我用这样的功能破解了这个:

def apache():
    global SERVERTYPE
    SERVERTYPE = "APACHE"
    env.hosts = ['xxx.xxx.com']

但这显然不是很优雅,我刚刚发现了角色,所以我的问题是:

如何确定当前实例属于哪个角色?

env.roledefs = {
    'apache': ['xxx.xxx.com'],
    'APE': ['yyy.xxx.com'],
}

谢谢!

4

5 回答 5

18

对于其他有这个问题的人,这是我的解决方案:

关键是找到 env.host_string。

这就是我使用一个命令重新启动不同类型服务器的方式:

env.roledefs = {
    'apache': ['xxx.xxx.com'],
    'APE': ['yyy.xxx.com']
}

def apache():
    env.roles = ['apache']

...

def restart():
    if env.host_string in env.roledefs['apache']:
        sudo("apache2ctl graceful", pty=True)
    elif env.host_string in env.roledefs['APE']:
        sudo ("supervisorctl reload", pty=True)

请享用!

于 2010-06-23T14:51:40.690 回答
12

我没有测试它,但可能会工作:

def _get_current_role():
    for role in env.roledefs.keys():
        if env.host_string in env.roledefs[role]:
            return role
    return None
于 2012-03-12T19:46:46.890 回答
6

env.roles将为您提供由 -R 标志指定或在脚本本身中硬编码的角色。@roles它不包含使用命令行或使用装饰器为每个任务指定的角色。目前没有办法获得这种信息。

Fabric 的下一个版本(可能是 1.9)将提供env.effective_roles您想要的属性 - 用于当前执行任务的角色。该代码已经合并到master中。

看看这个问题

于 2014-04-21T19:43:57.607 回答
5

更新:刚刚检查了源代码似乎早在 1.4.2 就已经可用了!

更新 2 :使用装饰器时这似乎不起作用@roles(在 1.5.3 中)!它仅在使用-R命令行标志指定角色时才有效。

对于结构 1.5.3,当前角色可直接在 `fabric.api.env.roles' 中使用。例如:

import fabric.api as fab

fab.env.roledefs['staging'] = ['bbs-evolution.ipsw.dt.ept.lu']
fab.env.roledefs['prod'] = ['bbs-arbiter.ipsw.dt.ept.lu']


@fab.task
def testrole():
    print fab.env.roles

控制台上的测试输出:

› fab -R staging testrole
[bbs-evolution.ipsw.dt.ept.lu] Executing task 'testrole'
['staging']

Done.

或者:

› fab -R staging,prod testrole
[bbs-evolution.ipsw.dt.ept.lu] Executing task 'testrole'
['staging', 'prod']
[bbs-arbiter.ipsw.dt.ept.lu] Executing task 'testrole'
['staging', 'prod']

Done.

有了这个,我们可以in在一个结构任务中做一个简单的测试:

@fab.task
def testrole():
    if 'prod' in fab.env.roles:
        do_production_stuff()
    elif 'staging' in fab.env.roles:
        do_staging_stuff()
    else:
        raise ValueError('No valid role specified!')
于 2013-07-18T13:01:19.653 回答
0

在Anaconda2 5.1.0下使用fabric 1.14.0 ...确认使用@roles装饰器时的问题...尤其是在@roles装饰器与多个​​参数一起使用的情况下,然后调用另一个没有@roles装饰器(或具有不同参数)的任务从第一个任务中。以我的经验,这可能会导致主机不匹配,这取决于我如何发现角色(即role = env.effective_roles[0])。

请注意,role = env.effective_roles[0]在简单的情况下确实可以很好地工作,例如(a)@roles只指定一个角色,并且(b)原始任务不调用另一个任务。

还要注意-R命令行上不覆盖@roles并且必须使用的情况task:roles=role1如何仅在单个主机上运行@roles-decorated 结构任务......还想知道如何将多个角色传递给名为...的参数roles...嗯,但我离题了。

也许有更好的方法,但文档@roles留下一个想要的。下一步可能是在这一点上通读源代码。

与此同时,我已经破解了以下解决方法......

from fabric.api import env
from fabric.decorators import roles
from fabric.decorators import task


def get_host_roles(env, of=None, die=False):
    """
    Get the role(s) for a host at run time
    :param env: Fabric env
    :param of: tuple/set/list
    :param die: boolean
    :return: tuple(host, roles) or tuple(host, role)
    """
    host = env.host
    def valid(role):
        return host in env.roledefs[role]:
    roles = set(filter(valid, env.roledefs.keys()))
    if of:
        roles = tuple(roles & set(of)) # set intersection
        if len(roles) == 1:
            return host, roles[0]
        elif die:
            e = 'Host "%s" is not in just one of the provided roles: %s!' \
                % (host, repr(roles))
            raise Exception(e)
    return host, roles


_roles = ('role1', 'role2')


@task
@roles(*_roles)
def do_something_with_roles():
    host, roles = get_host_roles(env)
    # roles is a tuple with all of the roles the host is in.


@task
@roles(*_roles)
def do_something_with_roles_diy():
    host, roles = get_host_roles(env, _roles)
    # `roles` is a tuple with the set intersection of `_roles` and the
    # host's actual roles... so you handle the situation!
    if 'role1' in roles:
        # do whatever
        pass


@task
@roles(*_roles)
def force_single_role():
    host, role = get_host_roles(env, _roles, True)
    # this usage raises an exception in the instance that the host is not
    # exclusively in either 'role1' or 'role2'.
    # roles is a string with the role for that host.

希望有帮助。

于 2018-04-06T14:04:43.690 回答