From 2c8d9beca3b0383c3af244f25c4ba00669b4c28c Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Wed, 21 Feb 2018 11:34:13 -0600 Subject: [PATCH] cherry-pick #36470 for 2.5 (#36525) * Re-use logic from StrategyBase._load_included_file in StrategyModule.run for free and linear (#36470) This improves include_role performance and recursion limits (cherry picked from commit 10fefc715673bfee786097d1fdb88454ec99b093) * Add changelog for 36470 --- ...nclude_role_recursion_and_performance.yaml | 3 +++ lib/ansible/plugins/strategy/__init__.py | 21 +++++++++++++------ lib/ansible/plugins/strategy/free.py | 5 ++--- lib/ansible/plugins/strategy/linear.py | 3 +-- 4 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 changelogs/fragments/include_role_recursion_and_performance.yaml diff --git a/changelogs/fragments/include_role_recursion_and_performance.yaml b/changelogs/fragments/include_role_recursion_and_performance.yaml new file mode 100644 index 00000000000..4acb8d1f6e2 --- /dev/null +++ b/changelogs/fragments/include_role_recursion_and_performance.yaml @@ -0,0 +1,3 @@ +bugfixes: +- | + include_role - Improve performance and recursion depth (https://github.com/ansible/ansible/pull/36470) diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index 4c081d1c415..4099d8d9635 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -750,6 +750,20 @@ class StrategyBase: return changed + def _copy_included_file(self, included_file): + ''' + A proven safe and performant way to create a copy of an included file + ''' + ti_copy = included_file._task.copy(exclude_parent=True) + ti_copy._parent = included_file._task._parent + + temp_vars = ti_copy.vars.copy() + temp_vars.update(included_file._args) + + ti_copy.vars = temp_vars + + return ti_copy + def _load_included_file(self, included_file, iterator, is_handler=False): ''' Loads an included YAML file of tasks, applying the optional set of variables. @@ -763,10 +777,7 @@ class StrategyBase: elif not isinstance(data, list): raise AnsibleError("included task files must contain a list of tasks") - ti_copy = included_file._task.copy(exclude_parent=True) - ti_copy._parent = included_file._task._parent - temp_vars = ti_copy.vars.copy() - temp_vars.update(included_file._args) + ti_copy = self._copy_included_file(included_file) # pop tags out of the include args, if they were specified there, and assign # them to the include. If the include already had tags specified, we raise an # error so that users know not to specify them both ways @@ -781,8 +792,6 @@ class StrategyBase: display.deprecated("You should not specify tags in the include parameters. All tags should be specified using the task-level option") included_file._task.tags = tags - ti_copy.vars = temp_vars - block_list = load_list_of_blocks( data, play=iterator._play, diff --git a/lib/ansible/plugins/strategy/free.py b/lib/ansible/plugins/strategy/free.py index 07e02cfb83b..c0a8a2bcd80 100644 --- a/lib/ansible/plugins/strategy/free.py +++ b/lib/ansible/plugins/strategy/free.py @@ -193,10 +193,9 @@ class StrategyModule(StrategyBase): display.debug("collecting new blocks for %s" % included_file) try: if included_file._is_role: - new_ir = included_file._task.copy() - new_ir.vars.update(included_file._args) + new_ir = self._copy_included_file(included_file) - new_blocks, handler_blocks = included_file._task.get_block_list( + new_blocks, handler_blocks = new_ir.get_block_list( play=iterator._play, variable_manager=self._variable_manager, loader=self._loader, diff --git a/lib/ansible/plugins/strategy/linear.py b/lib/ansible/plugins/strategy/linear.py index 3409888fa08..d9a0c185e88 100644 --- a/lib/ansible/plugins/strategy/linear.py +++ b/lib/ansible/plugins/strategy/linear.py @@ -324,8 +324,7 @@ class StrategyModule(StrategyBase): # list of noop tasks, to make sure that they continue running in lock-step try: if included_file._is_role: - new_ir = included_file._task.copy() - new_ir.vars.update(included_file._args) + new_ir = self._copy_included_file(included_file) new_blocks, handler_blocks = new_ir.get_block_list( play=iterator._play,