Search code examples
pythonfabric

How to run a @roles-decorated fabric task on only a single host


I have a task decorated with @roles that I would occasionally like to run on a single host (for canary-testing deploys).

from fabric.api import *

env.roledefs = {
    'web-workers': ['django@worker1', 'django@worker2'],
    'some-other-role': ['django@worker2'],
}

@task
@roles('web-workers')
def bogomips():
    run('uptime')

The docs for @roles states that:

...barring an override on the command line, my_func will be executed against the hosts listed [in the role]...

But I can't get the "override" functionality mentioned here to work... I've tried:

$ fab bogomips -H django@worker2
$ fab bogomips -R some-other-role

but it always executes on the entire role mentioned in the decorator...

What am I missing here? How can I override where a @roles-decorated task is run?


Solution

  • This is actually the intended behavior, according to the Execution model's Order of Precedence, and there's a slightly different syntax that you must use in this scenario.

    So here's the command that doesn't work:

    $ fab bogomips -R some-other-role # fabric ignores the -R values!
    

    And here's the version that DOES work:

    $ fab bogomips:roles=some-other-role
    

    Here's the issue: #308: @roles and @hosts decorators ignore command line options

    And the docs: http://docs.fabfile.org/en/1.0.0/usage/execution.html#order-of-precedence

    • Per-task, command-line host lists (fab mytask:host=host1) override absolutely everything else.
    • Per-task, decorator-specified host lists (@hosts('host1')) override the env variables.
    • Globally specified host lists set in the fabfile (env.hosts = ['host1']) can override such lists set on the command-line, but only if you’re not careful (or want them to.)
    • Globally specified host lists set on the command-line (--hosts=host1) will initialize the env variables, but that’s it.