Cómo descubrir el rol actual en Python Fabric


Esta es una pregunta muy específica de Fabric, pero los hackers de python más experimentados podrían ser capaces de responder a esto, incluso si no conocen Fabric.

Estoy tratando de especificar un comportamiento diferente en un comando dependiendo del rol para el que se esté ejecutando, es decir:

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

Estaba hackeando esto con funciones como esta:

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

Pero eso obviamente no es muy elegante y acabo de descubrir los roles, así que mi pregunta es:

¿Cómo puedo averiguar qué rol tiene una corriente instancia pertenece?

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

Gracias!

Author: rdrey, 2010-06-23

5 answers

Actualización: Acaba de el código fuente y parece que esto ya estaba disponible tan pronto como 1.4.2!

actualización 2 : Esto parece no para funcionar cuando se utiliza el decorador @roles (en 1.5.3)! Solo funciona cuando se especifican los roles usando el indicador de línea de comandos -R.

Para fabric 1.5.3 los roles actuales están directamente disponibles en `fabric.api.env.rol'. Por ejemplo:

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

Salida de prueba en el consola:

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

Done.

O:

› 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.

Con esto, podemos hacer una prueba simple in en una tarea fabric:

@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!')
 5
Author: exhuma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-18 13:18:10

Para todos los demás con esta pregunta, aquí está mi solución:

La clave fue encontrar env.host_string.

Así es como reinicio diferentes tipos de servidores con un comando:

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)

Disfrute!

 18
Author: rdrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-23 14:51:40

No lo probé, pero podría funcionar:

def _get_current_role():
    for role in env.roledefs.keys():
        if env.host_string in env.roledefs[role]:
            return role
    return None
 12
Author: semente,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-12 19:55:17

El env.roles le dará los roles especificados por la bandera-R o codificados en el propio script. No contendrá los roles especificados por tarea usando la línea de comandos o usando @roles decorator. Actualmente no hay forma de obtener este tipo de información.

La próxima versión de fabric (1.9 probablemente) proporcionará env.effective_roles atributo con exactamente lo que desea - los roles que se utilizan para la tarea actualmente ejecutada. El código para eso ya se ha fusionado en master.

Echa un vistazo en este número .

 6
Author: pbetkier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-21 19:43:57

Utilizando la tela 1.14.0 bajo Anaconda2 5.1.0... confirme el problema al usar el decorador @roles... especialmente en el caso de que el decorador @roles se use con múltiples argumentos y luego se llame a otra tarea sin el decorador @roles (o con diferentes argumentos) desde la primera tarea. En mi experiencia, esto puede tener el efecto de desajustar sin sentido a los anfitriones, dependiendo de cómo descubra el papel (es decir, role = env.effective_roles[0]).

Tenga en cuenta que role = env.effective_roles[0] funciona bien en situaciones, por ejemplo (a) @roles solo especifica un rol, y (b) la tarea original no llama a otra tarea.

Tenga en cuenta también la situación en la que -R en la línea de comandos no anula @roles y debe usar task:roles=role1 en su lugar: Cómo ejecutar una tarea @roles-decorated fabric en un solo host... también se pregunta cómo pasar múltiples roles a un argumento llamado roles... hmmm, pero estoy divagando.

Tal vez haya una mejor manera, pero la documentación sobre @roles deja a uno faltando. Siguiente paso es probablemente leer el código fuente en este punto.

Mientras tanto, he hackeado la siguiente solución...

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.

Espero que eso ayude.

 0
Author: Nick Jensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-06 14:04:43