Как узнать текущую роль в Python Fabric - PullRequest
23 голосов
/ 23 июня 2010

Это очень конкретный вопрос , но более опытные хакеры Python могут ответить на него, даже если они не знают Fabric.

Я пытаюсь указать другойповедение команды в зависимости от роли, для которой она выполняется, например:

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

Я взломал это с помощью таких функций:и я только что обнаружил роли, поэтому мой вопрос:

Как определить, какой роли принадлежит текущий экземпляр?

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

Спасибо!

Ответы [ 5 ]

18 голосов
/ 23 июня 2010

Для всех, кто когда-либо сталкивался с этим вопросом, вот мое решение:

Ключ находил 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)

наслаждаться!

12 голосов
/ 12 марта 2012

Я не проверял, но может работать:

def _get_current_role():
    for role in env.roledefs.keys():
        if env.host_string in env.roledefs[role]:
            return role
    return None
6 голосов
/ 21 апреля 2014

env.roles предоставит вам роли, указанные флагом -R или жестко закодированные в самом скрипте.Он не будет содержать роли, указанные для задачи, используя командную строку или @roles декоратор.В настоящее время нет способа получить такую ​​информацию.

В следующем выпуске Fabric (вероятно, 1.9) атрибут env.effective_roles будет предоставлен именно с тем, что вы хотите - ролями, используемыми для выполняемой в данный момент задачи.Код для этого уже объединен с мастером.

Посмотрите на эту проблему .

5 голосов
/ 18 июля 2013

Обновление : только что проверил исходный код и кажется , что это уже было доступно еще в 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!')
0 голосов
/ 06 апреля 2018

Использование матрицы 1.14.0 под Anaconda2 5.1.0 ... подтвердите проблему при использовании декоратора @roles ... особенно в том случае, если декоратор @roles используется с несколькими аргументами, а затем с другой задачей без @roles декоратор (или с другими аргументами) вызывается из первой задачи. По моему опыту, это может привести к бессмысленному несоответствию хостов, в зависимости от того, как я обнаружу роль (т.е. role = env.effective_roles[0]).

Обратите внимание, что role = env.effective_roles[0] хорошо работает в простых ситуациях, например, (a) @roles определяет только одну роль, и (b) исходная задача не вызывает другую задачу.

Обратите также внимание на ситуацию, когда -R в командной строке не переопределяет @roles и должен вместо этого использовать task:roles=role1: Как запустить задачу фабрики с @ ролями на одном хосте . ... также интересно, как передать несколько ролей аргументу с именем 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.

Надеюсь, это поможет.

...