mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Adds the 'serial' keyword to a playbook which controls how many hosts can be running through a playbook at a single time.
The default is 0, which means all hosts. If set to 1, each host would run a playbook all the way through before moving on the next host. Fact gathering is still parallel, regardless of the serial setting.
This commit is contained in:
parent
e13c33bb86
commit
898d7676f7
4 changed files with 62 additions and 23 deletions
|
@ -40,6 +40,7 @@ Ansible Changes By Release
|
||||||
* add pattern= as a paramter to the service module
|
* add pattern= as a paramter to the service module
|
||||||
* various fixes to mysql & postresql modules
|
* various fixes to mysql & postresql modules
|
||||||
* adds 'delegate_to' for a task, which can be used to signal outage windows and load balancers on behalf of hosts
|
* adds 'delegate_to' for a task, which can be used to signal outage windows and load balancers on behalf of hosts
|
||||||
|
* adds 'serial' to playbook, allowing you to specify how many hosts can be processing a playbook at one time (default 0=all)
|
||||||
|
|
||||||
0.6 "Cabo" -- August 6, 2012
|
0.6 "Cabo" -- August 6, 2012
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Inventory(object):
|
||||||
Host inventory for ansible.
|
Host inventory for ansible.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = [ 'host_list', 'groups', '_restriction', '_subset', '_is_script',
|
__slots__ = [ 'host_list', 'groups', '_restriction', '_also_restriction', '_subset', '_is_script',
|
||||||
'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache' ]
|
'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache' ]
|
||||||
|
|
||||||
def __init__(self, host_list=C.DEFAULT_HOST_LIST):
|
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
|
# a list of host(names) to contain current inquiries to
|
||||||
self._restriction = None
|
self._restriction = None
|
||||||
|
self._also_restriction = None
|
||||||
self._subset = None
|
self._subset = None
|
||||||
|
|
||||||
# whether the inventory file is a script
|
# whether the inventory file is a script
|
||||||
|
@ -122,6 +123,8 @@ class Inventory(object):
|
||||||
# exclude hosts mentioned in any restriction (ex: failed hosts)
|
# exclude hosts mentioned in any restriction (ex: failed hosts)
|
||||||
if self._restriction is not None:
|
if self._restriction is not None:
|
||||||
hosts = [ h for h in hosts if h.name in self._restriction ]
|
hosts = [ h for h in hosts if h.name in self._restriction ]
|
||||||
|
if self._also_restriction is not None:
|
||||||
|
hosts = [ h for h in hosts if h.name in self._also_restriction ]
|
||||||
|
|
||||||
return sorted(hosts, key=lambda x: x.name)
|
return sorted(hosts, key=lambda x: x.name)
|
||||||
|
|
||||||
|
@ -281,6 +284,7 @@ class Inventory(object):
|
||||||
def list_groups(self):
|
def list_groups(self):
|
||||||
return sorted([ g.name for g in self.groups ], key=lambda x: x.name)
|
return sorted([ g.name for g in self.groups ], key=lambda x: x.name)
|
||||||
|
|
||||||
|
# TODO: remove this function
|
||||||
def get_restriction(self):
|
def get_restriction(self):
|
||||||
return self._restriction
|
return self._restriction
|
||||||
|
|
||||||
|
@ -294,6 +298,15 @@ class Inventory(object):
|
||||||
restriction = [ restriction ]
|
restriction = [ restriction ]
|
||||||
self._restriction = restriction
|
self._restriction = restriction
|
||||||
|
|
||||||
|
def also_restrict_to(self, restriction):
|
||||||
|
"""
|
||||||
|
Works like restict_to but offers an additional restriction. Playbooks use this
|
||||||
|
to implement serial behavior.
|
||||||
|
"""
|
||||||
|
if type(restriction) != list:
|
||||||
|
restriction = [ restriction ]
|
||||||
|
self._also_restriction = restriction
|
||||||
|
|
||||||
def subset(self, subset_pattern):
|
def subset(self, subset_pattern):
|
||||||
"""
|
"""
|
||||||
Limits inventory results to a subset of inventory that matches a given
|
Limits inventory results to a subset of inventory that matches a given
|
||||||
|
@ -308,8 +321,11 @@ class Inventory(object):
|
||||||
|
|
||||||
def lift_restriction(self):
|
def lift_restriction(self):
|
||||||
""" Do not restrict list operations """
|
""" Do not restrict list operations """
|
||||||
|
|
||||||
self._restriction = None
|
self._restriction = None
|
||||||
|
|
||||||
|
def lift_also_restriction(self):
|
||||||
|
""" Clears the also restriction """
|
||||||
|
self._also_restriction = None
|
||||||
|
|
||||||
def is_file(self):
|
def is_file(self):
|
||||||
""" did inventory come from a file? """
|
""" did inventory come from a file? """
|
||||||
|
|
|
@ -150,8 +150,8 @@ class PlayBook(object):
|
||||||
# loop through all patterns and run them
|
# loop through all patterns and run them
|
||||||
self.callbacks.on_start()
|
self.callbacks.on_start()
|
||||||
for play_ds in self.playbook:
|
for play_ds in self.playbook:
|
||||||
self._run_play(Play(self,play_ds))
|
play = Play(self,play_ds)
|
||||||
|
self._run_play(play)
|
||||||
# summarize the results
|
# summarize the results
|
||||||
results = {}
|
results = {}
|
||||||
for host in self.stats.processed.keys():
|
for host in self.stats.processed.keys():
|
||||||
|
@ -301,22 +301,43 @@ class PlayBook(object):
|
||||||
self._do_setup_step(play)
|
self._do_setup_step(play)
|
||||||
|
|
||||||
# now with that data, handle contentional variable file imports!
|
# now with that data, handle contentional variable file imports!
|
||||||
play.update_vars_files(self.inventory.list_hosts(play.hosts))
|
|
||||||
|
|
||||||
for task in play.tasks():
|
all_hosts = self.inventory.list_hosts(play.hosts)
|
||||||
# only run the task if the requested tags match
|
play.update_vars_files(all_hosts)
|
||||||
should_run = False
|
|
||||||
for x in self.only_tags:
|
serialized_batch = []
|
||||||
for y in task.tags:
|
if play.serial <= 0:
|
||||||
if (x==y):
|
serialized_batch = [all_hosts]
|
||||||
should_run = True
|
else:
|
||||||
break
|
# do N forks all the way through before moving to next
|
||||||
if should_run:
|
while len(all_hosts) > 0:
|
||||||
self._run_task(play, task, False)
|
play_hosts = []
|
||||||
|
for x in range(1, play.serial):
|
||||||
|
if len(all_hosts) > 0:
|
||||||
|
play_hosts.append(all_hosts.pop())
|
||||||
|
serialized_batch.append(play_hosts)
|
||||||
|
|
||||||
|
for on_hosts in serialized_batch:
|
||||||
|
|
||||||
|
self.inventory.also_restrict_to(on_hosts)
|
||||||
|
|
||||||
|
for task in play.tasks():
|
||||||
|
# only run the task if the requested tags match
|
||||||
|
should_run = False
|
||||||
|
for x in self.only_tags:
|
||||||
|
for y in task.tags:
|
||||||
|
if (x==y):
|
||||||
|
should_run = True
|
||||||
|
break
|
||||||
|
if should_run:
|
||||||
|
self._run_task(play, task, False)
|
||||||
|
|
||||||
|
# run notify actions
|
||||||
|
for handler in play.handlers():
|
||||||
|
if len(handler.notified_by) > 0:
|
||||||
|
self.inventory.restrict_to(handler.notified_by)
|
||||||
|
self._run_task(play, handler, True)
|
||||||
|
self.inventory.lift_restriction()
|
||||||
|
|
||||||
|
self.inventory.lift_also_restriction()
|
||||||
|
|
||||||
# run notify actions
|
|
||||||
for handler in play.handlers():
|
|
||||||
if len(handler.notified_by) > 0:
|
|
||||||
self.inventory.restrict_to(handler.notified_by)
|
|
||||||
self._run_task(play, handler, True)
|
|
||||||
self.inventory.lift_restriction()
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Play(object):
|
||||||
'hosts', 'name', 'vars', 'vars_prompt', 'vars_files',
|
'hosts', 'name', 'vars', 'vars_prompt', 'vars_files',
|
||||||
'handlers', 'remote_user', 'remote_port',
|
'handlers', 'remote_user', 'remote_port',
|
||||||
'sudo', 'sudo_user', 'transport', 'playbook',
|
'sudo', 'sudo_user', 'transport', 'playbook',
|
||||||
'tags', 'gather_facts', '_ds', '_handlers', '_tasks'
|
'tags', 'gather_facts', 'serial', '_ds', '_handlers', '_tasks'
|
||||||
]
|
]
|
||||||
|
|
||||||
# to catch typos and so forth -- these are userland names
|
# to catch typos and so forth -- these are userland names
|
||||||
|
@ -37,7 +37,7 @@ class Play(object):
|
||||||
VALID_KEYS = [
|
VALID_KEYS = [
|
||||||
'hosts', 'name', 'vars', 'vars_prompt', 'vars_files',
|
'hosts', 'name', 'vars', 'vars_prompt', 'vars_files',
|
||||||
'tasks', 'handlers', 'user', 'port', 'include',
|
'tasks', 'handlers', 'user', 'port', 'include',
|
||||||
'sudo', 'sudo_user', 'connection', 'tags', 'gather_facts'
|
'sudo', 'sudo_user', 'connection', 'tags', 'gather_facts', 'serial'
|
||||||
]
|
]
|
||||||
|
|
||||||
# *************************************************
|
# *************************************************
|
||||||
|
@ -75,6 +75,7 @@ class Play(object):
|
||||||
self.transport = ds.get('connection', self.playbook.transport)
|
self.transport = ds.get('connection', self.playbook.transport)
|
||||||
self.tags = ds.get('tags', None)
|
self.tags = ds.get('tags', None)
|
||||||
self.gather_facts = ds.get('gather_facts', True)
|
self.gather_facts = ds.get('gather_facts', True)
|
||||||
|
self.serial = ds.get('serial', 0)
|
||||||
|
|
||||||
self._update_vars_files_for_host(None)
|
self._update_vars_files_for_host(None)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue