Ткань ОКР.roledefs не действует так, как ожидалось

на сайт ткани этот пример приведен:

from fabric.api import env

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

насколько я могу судить из документации, эта настройка должна дать ключу env dict " foo "значение" bar "при выполнении на хостах "www1", "www2", "www3". Я не могу получить это поведение, хотя 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.

Я неправильно поняла цель этого? Как я могу сделать так, чтобы один сервер видел другое значение для ключа, а затем другой без особых проблем?

Я использую ткань 1.10.0

4 ответов


меня это тоже смутило. Оказывается, что будет возможно получить доступ к ним в Fabric 1.11: https://github.com/fabric/fabric/issues/1276


две проблемы, во-первых, версия используемой ткани старше определений на основе словаря, поэтому она интерпретирует ключи как имена хостов. Это может быть исправлено путем обновления до >= ткань 1.10.0. Во-вторых, параметры, определенные здесь, не заполняют env автоматически, но если вы используете задачу для установки ролей, можно установить их следующим образом:

@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

просто ответ на это:

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']

Если вы хотите, чтобы дополнительные ключи 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

затем украсьте любую задачу, для которой вы хотите применить ключи roledef:

@apply_role
def mytask():
    ...