add the limit option, which can be used to further confine the patterns selected by "hosts:" in ansible-playbooks

to an additional pattern (a subset) specified on the command line.  For instance, a playbook could be reusable
and target "webservers" and "dbservers", but you want to test only in the stage environment, or a few boxes at a time.
This commit is contained in:
Michael DeHaan 2012-08-10 02:45:29 -04:00
parent 05a128c2be
commit 1c81ddf8d4
6 changed files with 38 additions and 8 deletions

View file

@ -28,6 +28,7 @@ Ansible Changes By Release
* make remote_md5 internal function work with non-bash shells
* allow user to be passed in via --extra-vars (regression)
* add ability to store the result of any command in a register (see examples/playbooks/register_logic.yml)
* add --limit option, which can be used to further confine the pattern given in ansible-playbooks
0.6 "Cabo" -- August 6, 2012

View file

@ -52,7 +52,7 @@ def main(args):
# create parser for CLI options
usage = "%prog playbook.yml"
parser = utils.base_parser(constants=C, usage=usage, connect_opts=True, runas_opts=True)
parser = utils.base_parser(constants=C, usage=usage, connect_opts=True, runas_opts=True, subset_opts=True)
parser.add_option('-e', '--extra-vars', dest="extra_vars", default=None,
help="set additional key=value variables from the CLI")
parser.add_option('-t', '--tags', dest='tags', default='all',
@ -102,6 +102,7 @@ def main(args):
extra_vars=extra_vars,
private_key_file=options.private_key_file,
only_tags=only_tags,
subset=options.subset,
)
try:

View file

@ -35,4 +35,5 @@ DEFAULT_SUDO_USER = os.environ.get('ANSIBLE_SUDO_USER','root')
DEFAULT_REMOTE_PORT = 22
DEFAULT_TRANSPORT = os.environ.get('ANSIBLE_TRANSPORT','paramiko')
DEFAULT_TRANSPORT_OPTS = ['local', 'paramiko', 'ssh']
DEFAULT_SUBSET = None

View file

@ -34,7 +34,7 @@ class Inventory(object):
Host inventory for ansible.
"""
__slots__ = [ 'host_list', 'groups', '_restriction', '_is_script',
__slots__ = [ 'host_list', 'groups', '_restriction', '_subset', '_is_script',
'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache' ]
def __init__(self, host_list=C.DEFAULT_HOST_LIST):
@ -55,6 +55,7 @@ class Inventory(object):
# a list of host(names) to contain current inquiries to
self._restriction = None
self._subset = None
# whether the inventory file is a script
self._is_script = False
@ -103,7 +104,9 @@ class Inventory(object):
inverted = False
for group in groups:
for host in group.get_hosts():
if self._match(group.name, pat) or pat == 'all' or self._match(host.name, pat):
if self._subset and host.name not in self._subset:
continue
if pat == 'all' or self._match(group.name, pat) or self._match(host.name, pat):
# must test explicitly for None because [] means no hosts allowed
if self._restriction==None or host.name in self._restriction:
if inverted:
@ -187,12 +190,28 @@ class Inventory(object):
def get_restriction(self):
return self._restriction
def restrict_to(self, restriction, append_missing=False):
""" Restrict list operations to the hosts given in restriction """
def restrict_to(self, restriction):
"""
Restrict list operations to the hosts given in restriction. This is used
to exclude failed hosts in main playbook code, don't use this for other
reasons.
"""
if type(restriction) != list:
restriction = [ restriction ]
self._restriction = restriction
def subset(self, subset_pattern):
"""
Limits inventory results to a subset of inventory that matches a given
pattern, such as to select a given geographic of numeric slice amongst
a previous 'hosts' selection that only select roles, or vice versa.
Corresponds to --limit parameter to ansible-playbook
"""
if subset_pattern is None:
self._subset = None
else:
self._subset = self.list_hosts(subset_pattern)
def lift_restriction(self):
""" Do not restrict list operations """

View file

@ -57,7 +57,8 @@ class PlayBook(object):
sudo = False,
sudo_user = C.DEFAULT_SUDO_USER,
extra_vars = None,
only_tags = None):
only_tags = None,
subset = C.DEFAULT_SUBSET):
"""
playbook: path to a playbook file
@ -104,7 +105,8 @@ class PlayBook(object):
self.private_key_file = private_key_file
self.only_tags = only_tags
self.inventory = ansible.inventory.Inventory(host_list)
self.inventory = ansible.inventory.Inventory(host_list)
self.inventory.subset(subset)
if not self.inventory._is_script:
self.global_vars.update(self.inventory.get_group_variables('all'))

View file

@ -336,7 +336,8 @@ def increment_debug(option, opt, value, parser):
global VERBOSITY
VERBOSITY += 1
def base_parser(constants=C, usage="", output_opts=False, runas_opts=False, async_opts=False, connect_opts=False):
def base_parser(constants=C, usage="", output_opts=False, runas_opts=False,
async_opts=False, connect_opts=False, subset_opts=False):
''' create an options parser for any ansible script '''
parser = SortedOptParser(usage, version=version("%prog"))
@ -357,6 +358,11 @@ def base_parser(constants=C, usage="", output_opts=False, runas_opts=False, asyn
parser.add_option('-M', '--module-path', dest='module_path',
help="specify path(s) to module library (default=%s)" % constants.DEFAULT_MODULE_PATH,
default=constants.DEFAULT_MODULE_PATH)
if subset_opts:
parser.add_option('-l', '--limit', default=constants.DEFAULT_SUBSET, dest='subset',
help='further limit selected hosts to an additional pattern')
parser.add_option('-T', '--timeout', default=constants.DEFAULT_TIMEOUT, type='int',
dest='timeout',
help="override the SSH timeout in seconds (default=%s)" % constants.DEFAULT_TIMEOUT)