fabric.api.env.roles not updated when using @roles #938

Closed
exhuma opened this Issue Jul 18, 2013 · 1 comment

Projects

None yet

2 participants

@exhuma
exhuma commented Jul 18, 2013

See also the following SO answer: http://stackoverflow.com/a/17724207/160665

When using the @roles decorator, fabric.api.env.roles does not reflect this choice. This could cause issues when running a nested task which uses env.roles. A practical example from my case (leaving out the non-essential stuff):

import fabric.api as fab

fab.env.roledefs.update({
    'prod': '1.2.3.4',
    'staging': '2.3.4.5'
})

@fab.task
@fab.roles('staging')
def stage():
    # ... snip ...
    fab.execute(deploy)
    # ... snip ...


@fab.task
@fab.roles('prod')
def prod():
    # ... snip ...
    fab.execute(deploy)
    # ... snip ...


@fab.task
def deploy():
    print fab.env.roles
    if 'prod' in fab.env.roles:
        apache_vhostname = 'migrate.tld.foo.bar'
    elif 'staging' in fab.env.roles:
        apache_vhostname = 'migrate-rc.tld.foo.bar'
    else:
        raise ValueError('Can only deploy on roles "prod" and "staging". '
                        'You told me to deploy on {0!r}'.format(fab.env.roles))
    # ... snip ...

As illustrative purpose, running this fabfile gives me:

/tmp› fab prod
[1] Executing task 'prod'
[]
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/fabric/main.py", line 736, in main
    *args, **kwargs
File "/usr/local/lib/python2.7/dist-packages/fabric/tasks.py", line 314, in execute
    multiprocessing
File "/usr/local/lib/python2.7/dist-packages/fabric/tasks.py", line 211, in _execute
    return task.run(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/fabric/tasks.py", line 121, in run
    return self.wrapped(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/fabric/decorators.py", line 51, in inner_decorator
    return func(*args, **kwargs)
File "/tmp/fabfile.py", line 20, in prod
    fab.execute(deploy)
File "/usr/local/lib/python2.7/dist-packages/fabric/tasks.py", line 347, in execute
    results['<local-only>'] = task.run(*args, **new_kwargs)
File "/usr/local/lib/python2.7/dist-packages/fabric/tasks.py", line 121, in run
    return self.wrapped(*args, **kwargs)
File "/tmp/fabfile.py", line 33, in deploy
    'You told me to deploy on {0!r}'.format(fab.env.roles))
ValueError: Can only deploy on roles "prod" and "staging". You told me to deploy on []

But I expected:

/tmp› fab prod
[1] Executing task 'prod'
['prod']
@pbetkier
Contributor

Calling fab.execute(deploy) would result in deploy task being executed in a fresh context, without any roles defined. The role you defined using @roles decorator would not be in effect. That's probably not what you want, so you should be calling deploy() directly. In the current version of fabric you cannot investigate the roles in use though.

Now, my PR introduces a new env var called effective_roles which contains the roles that are in effect in the currently executed task. Once it gets merged, you will be able to do this:

@fab.task
@fab.roles('prod')
def prod():
    # ... snip ...
    deploy()
    # ... snip ...

@fab.task
def deploy():
    print fab.env.effective_roles
    # ... snip ...

Actually, deploy doesn't necessarily have to be decorated as @fab.task, unless you also plan to call it directly from the command line.

@bitprophet bitprophet closed this in #1112 Apr 15, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment