Minor tweaks to v2 playbook iterator to support executor testing

This commit is contained in:
James Cammarata 2014-11-14 10:25:18 -06:00
parent 6030be3835
commit a1d990a673

View file

@ -31,37 +31,49 @@ class PlaybookState:
self._cur_play = 0 self._cur_play = 0
self._task_list = None self._task_list = None
self._cur_task_pos = 0 self._cur_task_pos = 0
self._done = False
def next(self): def next(self, peek=False):
''' '''
Determines and returns the next available task from the playbook, Determines and returns the next available task from the playbook,
advancing through the list of plays as it goes. advancing through the list of plays as it goes.
''' '''
task = None
# we save these locally so that we can peek at the next task
# without updating the internal state of the iterator
cur_play = self._cur_play
task_list = self._task_list
cur_task_pos = self._cur_task_pos
while True: while True:
# when we hit the end of the playbook entries list, we return # when we hit the end of the playbook entries list, we set a flag
# None to indicate we're there # and return None to indicate we're there
if self._cur_play > len(self._parent_iterator._playbook._entries) - 1: # FIXME: accessing the entries and parent iterator playbook members
# should be done through accessor functions
if self._done or cur_play > len(self._parent_iterator._playbook._entries) - 1:
self._done = True
return None return None
# initialize the task list by calling the .compile() method # initialize the task list by calling the .compile() method
# on the play, which will call compile() for all child objects # on the play, which will call compile() for all child objects
if self._task_list is None: if task_list is None:
self._task_list = self._parent_iterator._playbook._entries[self._cur_play].compile() task_list = self._parent_iterator._playbook._entries[cur_play].compile()
# if we've hit the end of this plays task list, move on to the next # if we've hit the end of this plays task list, move on to the next
# and reset the position values for the next iteration # and reset the position values for the next iteration
if self._cur_task_pos > len(self._task_list) - 1: if cur_task_pos > len(task_list) - 1:
self._cur_play += 1 cur_play += 1
self._task_list = None task_list = None
self._cur_task_pos = 0 cur_task_pos = 0
continue continue
else: else:
# FIXME: do tag/conditional evaluation here and advance # FIXME: do tag/conditional evaluation here and advance
# the task position if it should be skipped without # the task position if it should be skipped without
# returning a task # returning a task
task = self._task_list[self._cur_task_pos] task = task_list[cur_task_pos]
self._cur_task_pos += 1 cur_task_pos += 1
# Skip the task if it is the member of a role which has already # Skip the task if it is the member of a role which has already
# been run, unless the role allows multiple executions # been run, unless the role allows multiple executions
@ -71,6 +83,15 @@ class PlaybookState:
if task._role.has_run() and not task._role._metadata._allow_duplicates: if task._role.has_run() and not task._role._metadata._allow_duplicates:
continue continue
# Break out of the while loop now that we have our task
break
# If we're not just peeking at the next task, save the internal state
if not peek:
self._cur_play = cur_play
self._task_list = task_list
self._cur_task_pos = cur_task_pos
return task return task
class PlaybookIterator: class PlaybookIterator:
@ -84,14 +105,21 @@ class PlaybookIterator:
self._playbook = playbook self._playbook = playbook
self._log_manager = log_manager self._log_manager = log_manager
self._host_entries = dict() self._host_entries = dict()
self._first_host = None
# build the per-host dictionary of playbook states # build the per-host dictionary of playbook states
for host in inventory.get_hosts(): for host in inventory.get_hosts():
if self._first_host is None:
self._first_host = host
self._host_entries[host.get_name()] = PlaybookState(parent_iterator=self) self._host_entries[host.get_name()] = PlaybookState(parent_iterator=self)
def get_next_task_for_host(self, host): def get_next_task(self, peek=False):
''' returns the next task for host[0] '''
return self._host_entries[self._first_host.get_name()].next(peek=peek)
def get_next_task_for_host(self, host, peek=False):
''' fetch the next task for the given host ''' ''' fetch the next task for the given host '''
if host.get_name() not in self._host_entries: if host.get_name() not in self._host_entries:
raise AnsibleError("invalid host specified for playbook iteration") raise AnsibleError("invalid host specified for playbook iteration")
return self._host_entries[host.get_name()].next() return self._host_entries[host.get_name()].next(peek=peek)