monokal
monokal

Reputation: 71

@task(hosts=[...]) yields Context but -H yields Connection?

Python 3.8.2, Fabric 2.5.0, Paramiko 2.7.2, Invoke 1.4.1

Hello,

I have a fabfile which needs to handle hosts passed at the command-line (using -H) and hosts defined in the fabfile if -H was not passed. Here's an example of the issue I'm facing:

target_group = None

@task
def prod(c):
    _env_handler(c, "prod")

def _env_handler(c, env_name):
    global target_group

    if not hasattr(c, 'host'):
        target_group = Group("somehost1.tld", "somehost2.tld")

@task(hosts=target_group)
def test(c):
    print(c)

If I run fab prod test:

<Context: <Config: {'run': {'asynch ...

If I run fab -H 1,2 test:

<Connection host=1>
<Connection host=2>

So, passing hosts using the @task(hosts=[...] decorator produces a c Context object, and using -H produces a c Connection object.

I know using a task (prod(c)) to wrap environment logic may be questionable...but is there a way to ensure the task (test(c)) always receives a Connection object...or am I fundamentally misunderstanding something?

Thanks.

Edit: I've also tried directly passing a hosts list (e.g. @task(hosts=["somehost1.tld", "somehost2.tld"])) with the same result.

Edit: Here's the current workaround, but it's obviously not ideal if you have a lot of tasks:

@task
def test(c):
    if not hasattr(c, 'host'):
        for c in target_group:
            test(c)
    else:
        logging.info(f"Targeting {c.host}")

Upvotes: 2

Views: 211

Answers (1)

monokal
monokal

Reputation: 71

Workaround using a custom task decorator:

def _task_handler(func):
    @task
    @functools.wraps(func)
    def wrapper(c):
        if not hasattr(c, 'host'):
            for c in target_group:
                func(c)
        else:
            func(c)

    return wrapper

Upvotes: 1

Related Questions