Skip to content

Commit

Permalink
Merge branch '1.1' into 1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
bitprophet committed Aug 31, 2011
2 parents 4353d6a + 5a58b37 commit b6b01ff
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
20 changes: 19 additions & 1 deletion docs/usage/execution.rst
Expand Up @@ -384,11 +384,29 @@ which is implemented similarly to the abovementioned ``hosts`` and ``roles``
per-task kwargs, in that it is stripped from the actual task invocation. This
example would have the same result as the global exclude above::

$ fab -R myrole mytask:exclude_hosts="host2;host5"
$ fab mytask:roles=myrole,exclude_hosts="host2;host5"

Note that the host list is semicolon-separated, just as with the ``hosts``
per-task argument.

Combining exclusions
~~~~~~~~~~~~~~~~~~~~

Host exclusion lists, like host lists themselves, are not merged together
across the different "levels" they can be declared in. For example, a global
``-x`` option will not affect a per-task host list set with a decorator or
keyword argument, nor will per-task ``exclude_hosts`` keyword arguments affect
a global ``-H`` list.

There is one minor exception to this rule, namely that CLI-level keyword
arguments (``mytask:exclude_hosts=x,y``) **will** be taken into account when
examining host lists set via ``@hosts`` or ``@roles``. Thus a task function
decorated with ``@hosts('host1', 'host2')`` executed as ``fab
taskname:exclude_hosts=host2`` will only run on ``host1``.

As with the host list merging, this functionality is currently limited (partly
to keep the implementation simple) and may be expanded in future releases.


.. _failures:

Expand Down
16 changes: 9 additions & 7 deletions fabric/main.py
Expand Up @@ -518,8 +518,9 @@ def parse_arguments(arguments):
for pair in _escape_split(',', argstr):
k, _, v = pair.partition('=')
if _:
# Catch, interpret host/hosts/role/roles/exclude_hosts kwargs
if k in ['host', 'hosts', 'role', 'roles','exclude_hosts']:
# Catch, interpret host/hosts/role/roles/exclude_hosts
# kwargs
if k in ['host', 'hosts', 'role', 'roles', 'exclude_hosts']:
if k == 'host':
hosts = [v.strip()]
elif k == 'hosts':
Expand Down Expand Up @@ -567,11 +568,12 @@ def _merge(hosts, roles, exclude=[]):
role_hosts += value

# Return deduped combo of hosts and role_hosts, preserving order within
# them (vs using set(), which may lose ordering).
# them (vs using set(), which may lose ordering) and skipping hosts to be
# excluded.
cleaned_hosts = _clean_hosts(list(hosts) + list(role_hosts))
all_hosts = []
for host in cleaned_hosts:
if host not in all_hosts:
if host not in all_hosts and host not in exclude:
all_hosts.append(host)
return all_hosts

Expand All @@ -594,9 +596,8 @@ def get_hosts(command, cli_hosts, cli_roles, cli_exclude_hosts):
# Decorator-specific hosts/roles go next
func_hosts = getattr(command, 'hosts', [])
func_roles = getattr(command, 'roles', [])
func_exclude_hosts = getattr(command, 'exclude_hosts', [])
if func_hosts or func_roles:
return _merge(func_hosts, func_roles, func_exclude_hosts)
return _merge(func_hosts, func_roles, cli_exclude_hosts)
# Finally, the env is checked (which might contain globally set lists from
# the CLI or from module-level code). This will be the empty list if these
# have not been set -- which is fine, this method should return an empty
Expand Down Expand Up @@ -646,7 +647,8 @@ def main():
for option in env_options:
state.env[option.dest] = getattr(options, option.dest)

# Handle --hosts, --roles, --exclude-hosts (comma separated string => list)
# Handle --hosts, --roles, --exclude-hosts (comma separated string =>
# list)
for key in ['hosts', 'roles', 'exclude_hosts']:
if key in state.env and isinstance(state.env[key], basestring):
state.env[key] = state.env[key].split(',')
Expand Down
21 changes: 19 additions & 2 deletions tests/test_main.py
Expand Up @@ -179,8 +179,7 @@ def command():
assert 'foo' not in get_hosts(command, [], [])


@patched_env({'hosts': [' foo ', 'bar '], 'roles': [],
'exclude_hosts':[]})
@patched_env({'hosts': [' foo ', 'bar '], 'roles': [], 'exclude_hosts': []})
def test_hosts_stripped_env_hosts():
"""
Make sure hosts defined in env.hosts are cleaned of extra spaces
Expand Down Expand Up @@ -231,6 +230,24 @@ def command():
eq_(command.roles, role_list)


#
# Host exclusion
#

def dummy(): pass

def test_get_hosts_excludes_cli_exclude_hosts_from_cli_hosts():
assert 'foo' not in get_hosts(dummy, ['foo', 'bar'], [], ['foo'])

def test_get_hosts_excludes_cli_exclude_hosts_from_decorator_hosts():
assert 'foo' not in get_hosts(hosts('foo', 'bar')(dummy), [], [], ['foo'])

@patched_env({'hosts': ['foo', 'bar'], 'exclude_hosts': ['foo']})
def test_get_hosts_excludes_global_exclude_hosts_from_global_hosts():
assert 'foo' not in get_hosts(dummy, [], [], [])



#
# Basic role behavior
#
Expand Down

0 comments on commit b6b01ff

Please sign in to comment.