How to discover current role in Python Fabric

前端 未结 5 453
既然无缘
既然无缘 2021-02-02 10:24

This is a very Fabric specific question, but more experienced python hackers might be able to answer this, even if they don\'t know Fabric.

I am trying to specify differ

5条回答
  •  轮回少年
    2021-02-02 11:08

    Using fabric 1.14.0 under Anaconda2 5.1.0... confirm the issue when using the @roles decorator... especially in the case that the @roles decorator is used with multiple arguments and then another task without the @roles decorator (or with different arguments) is called from within the first task. In my experience, this can have the effect of nonsensically mismatching the hosts, depending on how I discover the role (i.e. role = env.effective_roles[0]).

    Note that role = env.effective_roles[0] does work well in simple situations, e.g. (a) @roles only specifies one role, and (b) the original task does not call another task.

    Note also the situation where -R on command line does not override @roles and must use task:roles=role1 instead: How to run a @roles-decorated fabric task on only a single host ... also wondering how to pass multiple roles to an argument named roles... hmmm, but I digress.

    Perhaps there is a better way, but documentation on @roles leaves one wanting. Next step is to probably read through the source code at this point.

    In the meantime, I've hacked up the following workaround...

    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.
    

    Hope that helps.

提交回复
热议问题