代码之家  ›  专栏  ›  技术社区  ›  rdrey

如何发现当前在python结构中的角色

  •  23
  • rdrey  · 技术社区  · 14 年前

    这是一个非常 Fabric 具体的问题,但更有经验的python黑客可能能够回答这个问题,即使他们不知道结构。

    我试图根据命令运行的角色来指定命令中的不同行为,即:

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

    谢谢!

    5 回复  |  直到 6 年前
        1
  •  5
  •   exhuma    11 年前

    更新 刚刚检查过 the source code 而且它 似乎 早在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!')
    
        2
  •  18
  •   rdrey    14 年前

    对于每个有过这个问题的人来说,我的解决方案是:

    关键是找到env.host_字符串。

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

    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)
    

    享受!

        3
  •  12
  •   semente event_jr    12 年前

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

    def _get_current_role():
        for role in env.roledefs.keys():
            if env.host_string in env.roledefs[role]:
                return role
        return None
    
        4
  •  6
  •   pbetkier    10 年前

    这个 env.roles 将为您提供-r标志指定的角色或在脚本本身中硬编码的角色。它不包含使用命令行或使用的每个任务指定的角色 @roles 装饰者。目前无法获取此类信息。

    下一个版本的织物(可能是1.9)将提供 env.effective_roles 属性完全符合您的需要-当前执行的任务所使用的角色。其代码已合并到主控形状中。

    看一看 this issue .

        5
  •  0
  •   Nick Jensen    6 年前

    使用织物1.14.0在水蟒2 5.1.0下…使用时确认问题 @roles 装饰者…尤其是在这种情况下 @角色 decorator与多个参数一起使用,然后与另一个没有 @角色 从第一个任务中调用decorator(或使用不同的参数)。根据我的经验,这可能会产生无意义地不匹配主机的效果,这取决于我如何发现角色(即 role = env.effective_roles[0] )

    注意 角色=环境有效角色[0] 在简单情况下是否工作良好,例如(a) @角色 仅指定一个角色,(b)原始任务不调用其他任务。

    还要注意以下情况: -R 在命令行上不重写 @角色 并且必须使用 task:roles=role1 而是: How to run a @roles-decorated fabric task on only a single host …还想知道如何将多个角色传递给名为 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.
    

    希望有帮助。