Don't pollute include_variables (#54687)

* Don't pollute include_variables. Fixes #51667. Fixes #54618.

* Rename include_variables to include_args, so we can make the distinction about what they are

* Track args and vars separately

* oops

* oops again

* linting fix

* Add test
This commit is contained in:
Matt Martz
2019-04-09 10:14:42 -05:00
committed by GitHub
parent dd20c7c04e
commit fbf2d5d2f4
7 changed files with 51 additions and 22 deletions

View File

@@ -559,18 +559,18 @@ class TaskExecutor:
# if this task is a TaskInclude, we just return now with a success code so the
# main thread can expand the task list for the given host
if self._task.action in ('include', 'include_tasks'):
include_variables = self._task.args.copy()
include_file = include_variables.pop('_raw_params', None)
include_args = self._task.args.copy()
include_file = include_args.pop('_raw_params', None)
if not include_file:
return dict(failed=True, msg="No include file was specified to the include")
include_file = templar.template(include_file)
return dict(include=include_file, include_variables=include_variables)
return dict(include=include_file, include_args=include_args)
# if this task is a IncludeRole, we just return now with a success code so the main thread can expand the task list for the given host
elif self._task.action == 'include_role':
include_variables = self._task.args.copy()
return dict(include_variables=include_variables)
include_args = self._task.args.copy()
return dict(include_args=include_args)
# Now we do final validation on the task, which sets all fields to their final values.
self._task.post_validate(templar=templar)

View File

@@ -33,9 +33,10 @@ display = Display()
class IncludedFile:
def __init__(self, filename, args, task, is_role=False):
def __init__(self, filename, args, vars, task, is_role=False):
self._filename = filename
self._args = args
self._vars = vars
self._task = task
self._hosts = []
self._is_role = is_role
@@ -47,10 +48,13 @@ class IncludedFile:
raise ValueError()
def __eq__(self, other):
return other._filename == self._filename and other._args == self._args and other._task._parent._uuid == self._task._parent._uuid
return (other._filename == self._filename and
other._args == self._args and
other._vars == self._vars and
other._task._parent._uuid == self._task._parent._uuid)
def __repr__(self):
return "%s (%s): %s" % (self._filename, self._args, self._hosts)
return "%s (args=%s vars=%s): %s" % (self._filename, self._args, self._vars, self._hosts)
@staticmethod
def process_include_results(results, iterator, loader, variable_manager):
@@ -81,20 +85,21 @@ class IncludedFile:
except KeyError:
task_vars = task_vars_cache[cache_key] = variable_manager.get_vars(play=iterator._play, host=original_host, task=original_task)
include_variables = include_result.get('include_variables', dict())
include_args = include_result.get('include_args', dict())
special_vars = {}
loop_var = 'item'
index_var = None
if original_task.loop_control:
loop_var = original_task.loop_control.loop_var
index_var = original_task.loop_control.index_var
if loop_var in include_result:
task_vars[loop_var] = include_variables[loop_var] = include_result[loop_var]
task_vars[loop_var] = special_vars[loop_var] = include_result[loop_var]
if index_var and index_var in include_result:
task_vars[index_var] = include_variables[index_var] = include_result[index_var]
task_vars[index_var] = special_vars[index_var] = include_result[index_var]
if '_ansible_item_label' in include_result:
task_vars['_ansible_item_label'] = include_variables['_ansible_item_label'] = include_result['_ansible_item_label']
if original_task.no_log and '_ansible_no_log' not in include_variables:
task_vars['_ansible_no_log'] = include_variables['_ansible_no_log'] = original_task.no_log
task_vars['_ansible_item_label'] = special_vars['_ansible_item_label'] = include_result['_ansible_item_label']
if original_task.no_log and '_ansible_no_log' not in include_args:
task_vars['_ansible_no_log'] = special_vars['_ansible_no_log'] = original_task.no_log
# get search path for this task to pass to lookup plugins that may be used in pathing to
# the included file
@@ -166,21 +171,21 @@ class IncludedFile:
include_file = loader.path_dwim(include_result['include'])
include_file = templar.template(include_file)
inc_file = IncludedFile(include_file, include_variables, original_task)
inc_file = IncludedFile(include_file, include_args, special_vars, original_task)
else:
# template the included role's name here
role_name = include_variables.pop('name', include_variables.pop('role', None))
role_name = include_args.pop('name', include_args.pop('role', None))
if role_name is not None:
role_name = templar.template(role_name)
new_task = original_task.copy()
new_task._role_name = role_name
for from_arg in new_task.FROM_ARGS:
if from_arg in include_variables:
if from_arg in include_args:
from_key = from_arg.replace('_from', '')
new_task._from_files[from_key] = templar.template(include_variables.pop(from_arg))
new_task._from_files[from_key] = templar.template(include_args.pop(from_arg))
inc_file = IncludedFile(role_name, include_variables, new_task, is_role=True)
inc_file = IncludedFile(role_name, include_args, special_vars, new_task, is_role=True)
idx = 0
orig_inc_file = inc_file

View File

@@ -762,7 +762,7 @@ class StrategyBase:
ti_copy._parent = included_file._task._parent
temp_vars = ti_copy.vars.copy()
temp_vars.update(included_file._args)
temp_vars.update(included_file._vars)
ti_copy.vars = temp_vars