|
|
|
# Copyright (c) 2018 Ansible Project
|
|
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
import unittest
|
|
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
|
|
|
|
from ansible.executor.play_iterator import PlayIterator
|
|
|
|
from ansible.playbook import Playbook
|
|
|
|
from ansible.playbook.play_context import PlayContext
|
|
|
|
from ansible.plugins.strategy.linear import StrategyModule
|
|
|
|
from ansible.executor.task_queue_manager import TaskQueueManager
|
|
|
|
|
|
|
|
from units.mock.loader import DictDataLoader
|
|
|
|
from units.mock.path import mock_unfrackpath_noop
|
|
|
|
|
|
|
|
|
|
|
|
class TestStrategyLinear(unittest.TestCase):
|
|
|
|
|
|
|
|
@patch('ansible.playbook.role.definition.unfrackpath', mock_unfrackpath_noop)
|
|
|
|
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)
|
|
|
|
|
Perfy McPerferton (#58400)
* InventoryManager start of perf improvements
* 0 not 1
* More startswith to [0] improvements
* Remove unused var
* The hash doesn't need to be a string, start as a list, make it into a tuple
* set actually appears faster than frozenset, and these don't need to be frozen
* Cache hosts lists, to avoid extra get_hosts calls, pass to get_vars too
* negligible perf improvement, it could help with memory later
* Try the fast way, fallback to the safe way
* Revert to previous logic, linting fix
* Extend pre-caching to free
* Address test failures
* Hosts are strings
* Fix unit test
* host is a string
* update test assumption
* drop SharedPluginLoaderObj, pre-create a set, instead of 2 comparisons in the list comprehension
* Dedupe code
* Change to _hosts and _hosts_all in get_vars
* Add backwards compat for strategies that don't do set host caches
* Add deprecation message to SharedPluginLoaderObj
* Remove unused SharedPluginLoaderObj import
* Update docs/comments
* Remove debugging
* Indicate what patterh_hash is
* That won't work
* Re-fix tests
* Update _set_hosts_cache to accept the play directly, use without refresh in get_hosts_remaining and get_failed_hosts for backwards compat
* Rename variable to avoid confusion
* On add_host only manipulate _hosts_cache_all
* Add warning docs around _hosts and _hosts_all args
5 years ago
|
|
|
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)
|
Perfy McPerferton (#58400)
* InventoryManager start of perf improvements
* 0 not 1
* More startswith to [0] improvements
* Remove unused var
* The hash doesn't need to be a string, start as a list, make it into a tuple
* set actually appears faster than frozenset, and these don't need to be frozen
* Cache hosts lists, to avoid extra get_hosts calls, pass to get_vars too
* negligible perf improvement, it could help with memory later
* Try the fast way, fallback to the safe way
* Revert to previous logic, linting fix
* Extend pre-caching to free
* Address test failures
* Hosts are strings
* Fix unit test
* host is a string
* update test assumption
* drop SharedPluginLoaderObj, pre-create a set, instead of 2 comparisons in the list comprehension
* Dedupe code
* Change to _hosts and _hosts_all in get_vars
* Add backwards compat for strategies that don't do set host caches
* Add deprecation message to SharedPluginLoaderObj
* Remove unused SharedPluginLoaderObj import
* Update docs/comments
* Remove debugging
* Indicate what patterh_hash is
* That won't work
* Re-fix tests
* Update _set_hosts_cache to accept the play directly, use without refresh in get_hosts_remaining and get_failed_hosts for backwards compat
* Rename variable to avoid confusion
* On add_host only manipulate _hosts_cache_all
* Add warning docs around _hosts and _hosts_all args
5 years ago
|
|
|
inventory.hosts[host.name] = host
|
|
|
|
inventory.get_hosts.return_value = hosts
|
|
|
|
inventory.filter_hosts.return_value = hosts
|
|
|
|
|
Perfy McPerferton (#58400)
* InventoryManager start of perf improvements
* 0 not 1
* More startswith to [0] improvements
* Remove unused var
* The hash doesn't need to be a string, start as a list, make it into a tuple
* set actually appears faster than frozenset, and these don't need to be frozen
* Cache hosts lists, to avoid extra get_hosts calls, pass to get_vars too
* negligible perf improvement, it could help with memory later
* Try the fast way, fallback to the safe way
* Revert to previous logic, linting fix
* Extend pre-caching to free
* Address test failures
* Hosts are strings
* Fix unit test
* host is a string
* update test assumption
* drop SharedPluginLoaderObj, pre-create a set, instead of 2 comparisons in the list comprehension
* Dedupe code
* Change to _hosts and _hosts_all in get_vars
* Add backwards compat for strategies that don't do set host caches
* Add deprecation message to SharedPluginLoaderObj
* Remove unused SharedPluginLoaderObj import
* Update docs/comments
* Remove debugging
* Indicate what patterh_hash is
* That won't work
* Re-fix tests
* Update _set_hosts_cache to accept the play directly, use without refresh in get_hosts_remaining and get_failed_hosts for backwards compat
* Rename variable to avoid confusion
* On add_host only manipulate _hosts_cache_all
* Add warning docs around _hosts and _hosts_all args
5 years ago
|
|
|
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)
|
Perfy McPerferton (#58400)
* InventoryManager start of perf improvements
* 0 not 1
* More startswith to [0] improvements
* Remove unused var
* The hash doesn't need to be a string, start as a list, make it into a tuple
* set actually appears faster than frozenset, and these don't need to be frozen
* Cache hosts lists, to avoid extra get_hosts calls, pass to get_vars too
* negligible perf improvement, it could help with memory later
* Try the fast way, fallback to the safe way
* Revert to previous logic, linting fix
* Extend pre-caching to free
* Address test failures
* Hosts are strings
* Fix unit test
* host is a string
* update test assumption
* drop SharedPluginLoaderObj, pre-create a set, instead of 2 comparisons in the list comprehension
* Dedupe code
* Change to _hosts and _hosts_all in get_vars
* Add backwards compat for strategies that don't do set host caches
* Add deprecation message to SharedPluginLoaderObj
* Remove unused SharedPluginLoaderObj import
* Update docs/comments
* Remove debugging
* Indicate what patterh_hash is
* That won't work
* Re-fix tests
* Update _set_hosts_cache to accept the play directly, use without refresh in get_hosts_remaining and get_failed_hosts for backwards compat
* Rename variable to avoid confusion
* On add_host only manipulate _hosts_cache_all
* Add warning docs around _hosts and _hosts_all args
5 years ago
|
|
|
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_noop_64999(self):
|
|
|
|
fake_loader = DictDataLoader({
|
|
|
|
"test_play.yml": """
|
|
|
|
- hosts: all
|
|
|
|
gather_facts: no
|
|
|
|
tasks:
|
|
|
|
- name: block1
|
|
|
|
block:
|
|
|
|
- name: block2
|
|
|
|
block:
|
|
|
|
- name: block3
|
|
|
|
block:
|
|
|
|
- name: task1
|
|
|
|
debug:
|
|
|
|
failed_when: inventory_hostname == 'host01'
|
|
|
|
rescue:
|
|
|
|
- name: rescue1
|
|
|
|
debug:
|
|
|
|
msg: "rescue"
|
|
|
|
- name: after_rescue1
|
|
|
|
debug:
|
|
|
|
msg: "after_rescue1"
|
|
|
|
""",
|
|
|
|
})
|
|
|
|
|
|
|
|
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])
|
|
|
|
|
|
|
|
# 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')
|
|
|
|
|
|
|
|
# debug: after_rescue1, debug: after_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, 'debug')
|
|
|
|
self.assertEqual(host2_task.action, 'debug')
|
|
|
|
self.assertEqual(host1_task.name, 'after_rescue1')
|
|
|
|
self.assertEqual(host2_task.name, 'after_rescue1')
|
|
|
|
|
|
|
|
# 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)
|