def test_play_iterator(self): #import epdb; epdb.st() fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all gather_facts: false roles: - test_role pre_tasks: - debug: msg="this is a pre_task" tasks: - debug: msg="this is a regular task" - block: - debug: msg="this is a block task" - block: - debug: msg="this is a sub-block in a block" rescue: - debug: msg="this is a rescue task" - block: - debug: msg="this is a sub-block in a rescue" always: - debug: msg="this is an always task" - block: - debug: msg="this is a sub-block in an always" post_tasks: - debug: msg="this is a post_task" """, '/etc/ansible/roles/test_role/tasks/main.yml': """ - debug: msg="this is a role task" """, }) mock_var_manager = MagicMock() mock_var_manager._fact_cache = dict() mock_var_manager.get_vars.return_value = dict() p = Playbook.load('test_play.yml', loader=fake_loader, variable_manager=mock_var_manager) hosts = [] for i in range(0, 10): host = MagicMock() host.name = host.get_name.return_value = 'host%02d' % i hosts.append(host) mock_var_manager._fact_cache['host00'] = dict() inventory = MagicMock() inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], play_context=play_context, variable_manager=mock_var_manager, all_vars=dict(), ) # lookup up an original task target_task = p._entries[0].tasks[0].block[0] task_copy = target_task.copy(exclude_block=True) found_task = itr.get_original_task(hosts[0], task_copy) self.assertEqual(target_task, found_task) bad_task = Task() found_task = itr.get_original_task(hosts[0], bad_task) self.assertIsNone(found_task) # pre task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # role task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertIsNotNone(task._role) # regular play task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertIsNone(task._role) # block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a block task")) # sub-block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a block")) # mark the host failed itr.mark_host_failed(hosts[0]) # block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a rescue task")) # sub-block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a rescue")) # block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is an always task")) # sub-block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in an always")) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # post task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # end of iteration (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNone(task) # host 0 shouldn't be in the failed hosts, as the error # was handled by a rescue block failed_hosts = itr.get_failed_hosts() self.assertNotIn(hosts[0], failed_hosts)
def run(self, play): ''' Iterates over the roles/tasks in a play, using the given (or default) strategy for queueing tasks. The default is the linear strategy, which operates like classic Ansible by keeping all hosts in lock-step with a given task (meaning no hosts move on to the next task until all hosts are done with the current task). ''' if not self._callbacks_loaded: self.load_callbacks() all_vars = self._variable_manager.get_vars(loader=self._loader, play=play) templar = Templar(loader=self._loader, variables=all_vars) new_play = play.copy() new_play.post_validate(templar) new_play.handlers = new_play.compile_roles_handlers() + new_play.handlers self.hostvars = HostVars( inventory=self._inventory, variable_manager=self._variable_manager, loader=self._loader, ) # Fork # of forks, # of hosts or serial, whichever is lowest num_hosts = len(self._inventory.get_hosts(new_play.hosts, ignore_restrictions=True)) max_serial = 0 if new_play.serial: # the play has not been post_validated here, so we may need # to convert the scalar value to a list at this point serial_items = new_play.serial if not isinstance(serial_items, list): serial_items = [serial_items] max_serial = max([pct_to_int(x, num_hosts) for x in serial_items]) contenders = [self._options.forks, max_serial, num_hosts] contenders = [v for v in contenders if v is not None and v > 0] self._initialize_processes(min(contenders)) play_context = PlayContext(new_play, self._options, self.passwords, self._connection_lockfile.fileno()) for callback_plugin in self._callback_plugins: if hasattr(callback_plugin, 'set_play_context'): callback_plugin.set_play_context(play_context) self.send_callback('v2_playbook_on_play_start', new_play) # initialize the shared dictionary containing the notified handlers self._initialize_notified_handlers(new_play) # load the specified strategy (or the default linear one) strategy = strategy_loader.get(new_play.strategy, self) if strategy is None: raise AnsibleError("Invalid play strategy specified: %s" % new_play.strategy, obj=play._ds) # build the iterator iterator = PlayIterator( inventory=self._inventory, play=new_play, play_context=play_context, variable_manager=self._variable_manager, all_vars=all_vars, start_at_done = self._start_at_done, ) # Because the TQM may survive multiple play runs, we start by marking # any hosts as failed in the iterator here which may have been marked # as failed in previous runs. Then we clear the internal list of failed # hosts so we know what failed this round. for host_name in self._failed_hosts.keys(): host = self._inventory.get_host(host_name) iterator.mark_host_failed(host) self.clear_failed_hosts() # during initialization, the PlayContext will clear the start_at_task # field to signal that a matching task was found, so check that here # and remember it so we don't try to skip tasks on future plays if getattr(self._options, 'start_at_task', None) is not None and play_context.start_at_task is None: self._start_at_done = True # and run the play using the strategy and cleanup on way out play_return = strategy.run(iterator, play_context) # now re-save the hosts that failed from the iterator to our internal list for host_name in iterator.get_failed_hosts(): self._failed_hosts[host_name] = True strategy.cleanup() self._cleanup_processes() return play_return
def test_play_iterator_nested_blocks(self): fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all gather_facts: false tasks: - block: - block: - block: - block: - block: - debug: msg="this is the first task" - ping: rescue: - block: - block: - block: - block: - debug: msg="this is the rescue task" always: - block: - block: - block: - block: - debug: msg="this is the always task" """, }) mock_var_manager = MagicMock() mock_var_manager._fact_cache = dict() mock_var_manager.get_vars.return_value = dict() p = Playbook.load('test_play.yml', loader=fake_loader, variable_manager=mock_var_manager) hosts = [] for i in range(0, 10): host = MagicMock() host.name = host.get_name.return_value = 'host%02d' % i hosts.append(host) inventory = MagicMock() inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], play_context=play_context, variable_manager=mock_var_manager, all_vars=dict(), ) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') self.assertEqual(task.args, dict(_raw_params='flush_handlers')) # get the first task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg='this is the first task')) # fail the host itr.mark_host_failed(hosts[0]) # get the resuce task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg='this is the rescue task')) # get the always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg='this is the always task')) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') self.assertEqual(task.args, dict(_raw_params='flush_handlers')) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') self.assertEqual(task.args, dict(_raw_params='flush_handlers')) # end of iteration (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNone(task)
def test_play_iterator_nested_blocks(self): fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all gather_facts: false tasks: - block: - block: - block: - block: - block: - debug: msg="this is the first task" - ping: rescue: - block: - block: - block: - block: - debug: msg="this is the rescue task" always: - block: - block: - block: - block: - debug: msg="this is the always task" """, }) mock_var_manager = MagicMock() mock_var_manager._fact_cache = dict() mock_var_manager.get_vars.return_value = dict() p = Playbook.load('test_play.yml', loader=fake_loader, variable_manager=mock_var_manager) hosts = [] for i in range(0, 10): host = MagicMock() host.name = host.get_name.return_value = 'host%02d' % i hosts.append(host) inventory = MagicMock() inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], play_context=play_context, variable_manager=mock_var_manager, all_vars=dict(), ) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') self.assertEqual(task.args, dict(_raw_params='flush_handlers')) # get the first task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg='this is the first task')) # fail the host itr.mark_host_failed(hosts[0]) # get the resuce task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg='this is the rescue task')) # get the always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg='this is the always task')) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') self.assertEqual(task.args, dict(_raw_params='flush_handlers')) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') self.assertEqual(task.args, dict(_raw_params='flush_handlers')) # end of iteration (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNone(task)
def test_play_iterator(self): # import epdb; epdb.st() fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all gather_facts: false roles: - test_role pre_tasks: - debug: msg="this is a pre_task" tasks: - debug: msg="this is a regular task" - block: - debug: msg="this is a block task" - block: - debug: msg="this is a sub-block in a block" rescue: - debug: msg="this is a rescue task" - block: - debug: msg="this is a sub-block in a rescue" always: - debug: msg="this is an always task" - block: - debug: msg="this is a sub-block in an always" post_tasks: - debug: msg="this is a post_task" """, '/etc/ansible/roles/test_role/tasks/main.yml': """ - name: role task debug: msg="this is a role task" - block: - name: role block task debug: msg="inside block in role" always: - name: role always task debug: msg="always task in block in role" - include: foo.yml - name: role task after include debug: msg="after include in role" - block: - name: starting role nested block 1 debug: - block: - name: role nested block 1 task 1 debug: - name: role nested block 1 task 2 debug: - name: role nested block 1 task 3 debug: - name: end of role nested block 1 debug: - name: starting role nested block 2 debug: - block: - name: role nested block 2 task 1 debug: - name: role nested block 2 task 2 debug: - name: role nested block 2 task 3 debug: - name: end of role nested block 2 debug: """, '/etc/ansible/roles/test_role/tasks/foo.yml': """ - name: role included task debug: msg="this is task in an include from a role" """ }) mock_var_manager = MagicMock() mock_var_manager._fact_cache = dict() mock_var_manager.get_vars.return_value = dict() p = Playbook.load('test_play.yml', loader=fake_loader, variable_manager=mock_var_manager) hosts = [] for i in range(0, 10): host = MagicMock() host.name = host.get_name.return_value = 'host%02d' % i hosts.append(host) mock_var_manager._fact_cache['host00'] = dict() inventory = MagicMock() inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], play_context=play_context, variable_manager=mock_var_manager, all_vars=dict(), ) # pre task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # role task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.name, "role task") self.assertIsNotNone(task._role) # role block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role block task") self.assertIsNotNone(task._role) # role block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role always task") self.assertIsNotNone(task._role) # role include task # (host_state, task) = itr.get_next_task_for_host(hosts[0]) # self.assertIsNotNone(task) # self.assertEqual(task.action, 'debug') # self.assertEqual(task.name, "role included task") # self.assertIsNotNone(task._role) # role task after include (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role task after include") self.assertIsNotNone(task._role) # role nested block tasks (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "starting role nested block 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 1 task 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 1 task 2") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 1 task 3") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "end of role nested block 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "starting role nested block 2") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 2 task 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 2 task 2") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 2 task 3") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "end of role nested block 2") self.assertIsNotNone(task._role) # regular play task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertIsNone(task._role) # block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a block task")) # sub-block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a block")) # mark the host failed itr.mark_host_failed(hosts[0]) # block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a rescue task")) # sub-block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a rescue")) # block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is an always task")) # sub-block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in an always")) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # post task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # end of iteration (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNone(task) # host 0 shouldn't be in the failed hosts, as the error # was handled by a rescue block failed_hosts = itr.get_failed_hosts() self.assertNotIn(hosts[0], failed_hosts)
def run(self, play): ''' Iterates over the roles/tasks in a play, using the given (or default) strategy for queueing tasks. The default is the linear strategy, which operates like classic Ansible by keeping all hosts in lock-step with a given task (meaning no hosts move on to the next task until all hosts are done with the current task). ''' if not self._callbacks_loaded: self.load_callbacks() all_vars = self._variable_manager.get_vars(play=play) warn_if_reserved(all_vars) templar = Templar(loader=self._loader, variables=all_vars) new_play = play.copy() new_play.post_validate(templar) new_play.handlers = new_play.compile_roles_handlers() + new_play.handlers self.hostvars = HostVars( inventory=self._inventory, variable_manager=self._variable_manager, loader=self._loader, ) play_context = PlayContext(new_play, self.passwords, self._connection_lockfile.fileno()) if (self._stdout_callback and hasattr(self._stdout_callback, 'set_play_context')): self._stdout_callback.set_play_context(play_context) for callback_plugin in self._callback_plugins: if hasattr(callback_plugin, 'set_play_context'): callback_plugin.set_play_context(play_context) self.send_callback('v2_playbook_on_play_start', new_play) # build the iterator iterator = PlayIterator( inventory=self._inventory, play=new_play, play_context=play_context, variable_manager=self._variable_manager, all_vars=all_vars, start_at_done=self._start_at_done, ) # adjust to # of workers to configured forks or size of batch, whatever is lower self._initialize_processes(min(self._forks, iterator.batch_size)) # load the specified strategy (or the default linear one) strategy = strategy_loader.get(new_play.strategy, self) if strategy is None: raise AnsibleError("Invalid play strategy specified: %s" % new_play.strategy, obj=play._ds) # Because the TQM may survive multiple play runs, we start by marking # any hosts as failed in the iterator here which may have been marked # as failed in previous runs. Then we clear the internal list of failed # hosts so we know what failed this round. for host_name in self._failed_hosts.keys(): host = self._inventory.get_host(host_name) iterator.mark_host_failed(host) self.clear_failed_hosts() # during initialization, the PlayContext will clear the start_at_task # field to signal that a matching task was found, so check that here # and remember it so we don't try to skip tasks on future plays if context.CLIARGS.get('start_at_task') is not None and play_context.start_at_task is None: self._start_at_done = True # and run the play using the strategy and cleanup on way out play_return = strategy.run(iterator, play_context) # now re-save the hosts that failed from the iterator to our internal list for host_name in iterator.get_failed_hosts(): self._failed_hosts[host_name] = True strategy.cleanup() self._cleanup_processes() return play_return
def run(self, play): ''' Iterates over the roles/tasks in a play, using the given (or default) strategy for queueing tasks. The default is the linear strategy, which operates like classic Ansible by keeping all hosts in lock-step with a given task (meaning no hosts move on to the next task until all hosts are done with the current task). ''' if not self._callbacks_loaded: self.load_callbacks() all_vars = self._variable_manager.get_vars(loader=self._loader, play=play) warn_if_reserved(all_vars) templar = Templar(loader=self._loader, variables=all_vars) new_play = play.copy() new_play.post_validate(templar) new_play.handlers = new_play.compile_roles_handlers() + new_play.handlers self.hostvars = HostVars( inventory=self._inventory, variable_manager=self._variable_manager, loader=self._loader, ) # Fork # of forks, # of hosts or serial, whichever is lowest num_hosts = len(self._inventory.get_hosts(new_play.hosts, ignore_restrictions=True)) max_serial = 0 if new_play.serial: # the play has not been post_validated here, so we may need # to convert the scalar value to a list at this point serial_items = new_play.serial if not isinstance(serial_items, list): serial_items = [serial_items] max_serial = max([pct_to_int(x, num_hosts) for x in serial_items]) contenders = [self._options.forks, max_serial, num_hosts] contenders = [v for v in contenders if v is not None and v > 0] self._initialize_processes(min(contenders)) play_context = PlayContext(new_play, self._options, self.passwords, self._connection_lockfile.fileno()) for callback_plugin in self._callback_plugins: if hasattr(callback_plugin, 'set_play_context'): callback_plugin.set_play_context(play_context) self.send_callback('v2_playbook_on_play_start', new_play) # initialize the shared dictionary containing the notified handlers self._initialize_notified_handlers(new_play) # load the specified strategy (or the default linear one) strategy = strategy_loader.get(new_play.strategy, self) if strategy is None: raise AnsibleError("Invalid play strategy specified: %s" % new_play.strategy, obj=play._ds) # build the iterator iterator = PlayIterator( inventory=self._inventory, play=new_play, play_context=play_context, variable_manager=self._variable_manager, all_vars=all_vars, start_at_done = self._start_at_done, ) # Because the TQM may survive multiple play runs, we start by marking # any hosts as failed in the iterator here which may have been marked # as failed in previous runs. Then we clear the internal list of failed # hosts so we know what failed this round. for host_name in self._failed_hosts.keys(): host = self._inventory.get_host(host_name) iterator.mark_host_failed(host) self.clear_failed_hosts() # during initialization, the PlayContext will clear the start_at_task # field to signal that a matching task was found, so check that here # and remember it so we don't try to skip tasks on future plays if getattr(self._options, 'start_at_task', None) is not None and play_context.start_at_task is None: self._start_at_done = True # and run the play using the strategy and cleanup on way out play_return = strategy.run(iterator, play_context) # now re-save the hosts that failed from the iterator to our internal list for host_name in iterator.get_failed_hosts(): self._failed_hosts[host_name] = True strategy.cleanup() self._cleanup_processes() return play_return
def test_noop(self): fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all gather_facts: no tasks: - block: - block: - name: task1 debug: msg='task1' failed_when: inventory_hostname == 'host01' - name: task2 debug: msg='task2' rescue: - name: rescue1 debug: msg='rescue1' - name: rescue2 debug: msg='rescue2' """, }) mock_var_manager = MagicMock() mock_var_manager._fact_cache = dict() mock_var_manager.get_vars.return_value = dict() p = Playbook.load('test_play.yml', loader=fake_loader, variable_manager=mock_var_manager) inventory = MagicMock() inventory.hosts = {} hosts = [] for i in range(0, 2): host = MagicMock() host.name = host.get_name.return_value = 'host%02d' % i hosts.append(host) inventory.hosts[host.name] = host inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts mock_var_manager._fact_cache['host00'] = dict() play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], play_context=play_context, variable_manager=mock_var_manager, all_vars=dict(), ) tqm = TaskQueueManager( inventory=inventory, variable_manager=mock_var_manager, loader=fake_loader, passwords=None, forks=5, ) tqm._initialize_processes(3) strategy = StrategyModule(tqm) strategy._hosts_cache = [h.name for h in hosts] strategy._hosts_cache_all = [h.name for h in hosts] # implicit meta: flush_handlers hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNotNone(host1_task) self.assertIsNotNone(host2_task) self.assertEqual(host1_task.action, 'meta') self.assertEqual(host2_task.action, 'meta') # debug: task1, debug: task1 hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNotNone(host1_task) self.assertIsNotNone(host2_task) self.assertEqual(host1_task.action, 'debug') self.assertEqual(host2_task.action, 'debug') self.assertEqual(host1_task.name, 'task1') self.assertEqual(host2_task.name, 'task1') # mark the second host failed itr.mark_host_failed(hosts[1]) # debug: task2, meta: noop hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNotNone(host1_task) self.assertIsNotNone(host2_task) self.assertEqual(host1_task.action, 'debug') self.assertEqual(host2_task.action, 'meta') self.assertEqual(host1_task.name, 'task2') self.assertEqual(host2_task.name, '') # meta: noop, debug: rescue1 hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNotNone(host1_task) self.assertIsNotNone(host2_task) self.assertEqual(host1_task.action, 'meta') self.assertEqual(host2_task.action, 'debug') self.assertEqual(host1_task.name, '') self.assertEqual(host2_task.name, 'rescue1') # meta: noop, debug: rescue2 hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNotNone(host1_task) self.assertIsNotNone(host2_task) self.assertEqual(host1_task.action, 'meta') self.assertEqual(host2_task.action, 'debug') self.assertEqual(host1_task.name, '') self.assertEqual(host2_task.name, 'rescue2') # implicit meta: flush_handlers hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNotNone(host1_task) self.assertIsNotNone(host2_task) self.assertEqual(host1_task.action, 'meta') self.assertEqual(host2_task.action, 'meta') # implicit meta: flush_handlers hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNotNone(host1_task) self.assertIsNotNone(host2_task) self.assertEqual(host1_task.action, 'meta') self.assertEqual(host2_task.action, 'meta') # end of iteration hosts_left = strategy.get_hosts_left(itr) hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr) host1_task = hosts_tasks[0][1] host2_task = hosts_tasks[1][1] self.assertIsNone(host1_task) self.assertIsNone(host2_task)
def test_play_iterator(self): # import epdb; epdb.st() fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all gather_facts: false roles: - test_role pre_tasks: - debug: msg="this is a pre_task" tasks: - debug: msg="this is a regular task" - block: - debug: msg="this is a block task" - block: - debug: msg="this is a sub-block in a block" rescue: - debug: msg="this is a rescue task" - block: - debug: msg="this is a sub-block in a rescue" always: - debug: msg="this is an always task" - block: - debug: msg="this is a sub-block in an always" post_tasks: - debug: msg="this is a post_task" """, '/etc/ansible/roles/test_role/tasks/main.yml': """ - name: role task debug: msg="this is a role task" - block: - name: role block task debug: msg="inside block in role" always: - name: role always task debug: msg="always task in block in role" - include: foo.yml - name: role task after include debug: msg="after include in role" - block: - name: starting role nested block 1 debug: - block: - name: role nested block 1 task 1 debug: - name: role nested block 1 task 2 debug: - name: role nested block 1 task 3 debug: - name: end of role nested block 1 debug: - name: starting role nested block 2 debug: - block: - name: role nested block 2 task 1 debug: - name: role nested block 2 task 2 debug: - name: role nested block 2 task 3 debug: - name: end of role nested block 2 debug: """, '/etc/ansible/roles/test_role/tasks/foo.yml': """ - name: role included task debug: msg="this is task in an include from a role" """ }) mock_var_manager = MagicMock() mock_var_manager._fact_cache = dict() mock_var_manager.get_vars.return_value = dict() p = Playbook.load('test_play.yml', loader=fake_loader, variable_manager=mock_var_manager) hosts = [] for i in range(0, 10): host = MagicMock() host.name = host.get_name.return_value = 'host%02d' % i hosts.append(host) mock_var_manager._fact_cache['host00'] = dict() inventory = MagicMock() inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], play_context=play_context, variable_manager=mock_var_manager, all_vars=dict(), ) # pre task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # role task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.name, "role task") self.assertIsNotNone(task._role) # role block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role block task") self.assertIsNotNone(task._role) # role block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role always task") self.assertIsNotNone(task._role) # role include task # (host_state, task) = itr.get_next_task_for_host(hosts[0]) # self.assertIsNotNone(task) # self.assertEqual(task.action, 'debug') # self.assertEqual(task.name, "role included task") # self.assertIsNotNone(task._role) # role task after include (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role task after include") self.assertIsNotNone(task._role) # role nested block tasks (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "starting role nested block 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 1 task 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 1 task 2") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 1 task 3") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "end of role nested block 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "starting role nested block 2") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 2 task 1") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 2 task 2") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "role nested block 2 task 3") self.assertIsNotNone(task._role) (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.name, "end of role nested block 2") self.assertIsNotNone(task._role) # regular play task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertIsNone(task._role) # block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a block task")) # sub-block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a block")) # mark the host failed itr.mark_host_failed(hosts[0]) # block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a rescue task")) # sub-block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a rescue")) # block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is an always task")) # sub-block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in an always")) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # post task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # end of iteration (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNone(task) # host 0 shouldn't be in the failed hosts, as the error # was handled by a rescue block failed_hosts = itr.get_failed_hosts() self.assertNotIn(hosts[0], failed_hosts)
def test_play_iterator(self): #import epdb; epdb.st() fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all gather_facts: false roles: - test_role pre_tasks: - debug: msg="this is a pre_task" tasks: - debug: msg="this is a regular task" - block: - debug: msg="this is a block task" - block: - debug: msg="this is a sub-block in a block" rescue: - debug: msg="this is a rescue task" - block: - debug: msg="this is a sub-block in a rescue" always: - debug: msg="this is an always task" - block: - debug: msg="this is a sub-block in an always" post_tasks: - debug: msg="this is a post_task" """, '/etc/ansible/roles/test_role/tasks/main.yml': """ - debug: msg="this is a role task" """, }) mock_var_manager = MagicMock() mock_var_manager._fact_cache = dict() mock_var_manager.get_vars.return_value = dict() p = Playbook.load('test_play.yml', loader=fake_loader, variable_manager=mock_var_manager) hosts = [] for i in range(0, 10): host = MagicMock() host.name = host.get_name.return_value = 'host%02d' % i hosts.append(host) mock_var_manager._fact_cache['host00'] = dict() inventory = MagicMock() inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], play_context=play_context, variable_manager=mock_var_manager, all_vars=dict(), ) # lookup up an original task target_task = p._entries[0].tasks[0].block[0] task_copy = target_task.copy(exclude_parent=True) found_task = itr.get_original_task(hosts[0], task_copy) self.assertEqual(target_task, found_task) bad_task = Task() found_task = itr.get_original_task(hosts[0], bad_task) self.assertIsNone(found_task) # pre task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # role task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertIsNotNone(task._role) # regular play task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertIsNone(task._role) # block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a block task")) # sub-block task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a block")) # mark the host failed itr.mark_host_failed(hosts[0]) # block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a rescue task")) # sub-block rescue task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in a rescue")) # block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is an always task")) # sub-block always task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') self.assertEqual(task.args, dict(msg="this is a sub-block in an always")) # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # post task (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'debug') # implicit meta: flush_handlers (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNotNone(task) self.assertEqual(task.action, 'meta') # end of iteration (host_state, task) = itr.get_next_task_for_host(hosts[0]) self.assertIsNone(task) # host 0 shouldn't be in the failed hosts, as the error # was handled by a rescue block failed_hosts = itr.get_failed_hosts() self.assertNotIn(hosts[0], failed_hosts)