diff options
author | Matt Martz <matt@sivel.net> | 2020-10-12 14:21:15 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-12 14:21:15 -0500 |
commit | c4acd41d6e4ed756b4e25545a03b540277168497 (patch) | |
tree | a449c287e8b166205e279b636dce3ea9d8e265c6 /lib/ansible/vars | |
parent | 5d811fc5518ae57275e178e45c4aef09ee139da1 (diff) | |
download | ansible-c4acd41d6e4ed756b4e25545a03b540277168497.tar.gz |
Ensure delegate vars calculation has correct loop context. Fixes #37132 (#71477)
Diffstat (limited to 'lib/ansible/vars')
-rw-r--r-- | lib/ansible/vars/manager.py | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/lib/ansible/vars/manager.py b/lib/ansible/vars/manager.py index 346270b7f9..0c819d4105 100644 --- a/lib/ansible/vars/manager.py +++ b/lib/ansible/vars/manager.py @@ -517,6 +517,12 @@ class VariableManager: return variables def _get_delegated_vars(self, play, task, existing_variables): + # This method has a lot of code copied from ``TaskExecutor._get_loop_items`` + # if this is failing, and ``TaskExecutor._get_loop_items`` is not + # then more will have to be copied here. + # TODO: dedupe code here and with ``TaskExecutor._get_loop_items`` + # this may be possible once we move pre-processing pre fork + if not hasattr(task, 'loop'): # This "task" is not a Task, so we need to skip it return {}, None @@ -525,16 +531,41 @@ class VariableManager: # as we're fetching vars before post_validate has been called on # the task that has been passed in vars_copy = existing_variables.copy() + + # get search path for this task to pass to lookup plugins + vars_copy['ansible_search_path'] = task.get_search_path() + + # ensure basedir is always in (dwim already searches here but we need to display it) + if self._loader.get_basedir() not in vars_copy['ansible_search_path']: + vars_copy['ansible_search_path'].append(self._loader.get_basedir()) + templar = Templar(loader=self._loader, variables=vars_copy) items = [] has_loop = True if task.loop_with is not None: if task.loop_with in lookup_loader: + fail = True + if task.loop_with == 'first_found': + # first_found loops are special. If the item is undefined then we want to fall through to the next + fail = False try: loop_terms = listify_lookup_plugin_terms(terms=task.loop, templar=templar, - loader=self._loader, fail_on_undefined=True, convert_bare=False) - items = wrap_var(lookup_loader.get(task.loop_with, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy)) + loader=self._loader, fail_on_undefined=fail, convert_bare=False) + + if not fail: + loop_terms = [t for t in loop_terms if not templar.is_template(t)] + + mylookup = lookup_loader.get(task.loop_with, loader=self._loader, templar=templar) + + # give lookup task 'context' for subdir (mostly needed for first_found) + for subdir in ['template', 'var', 'file']: # TODO: move this to constants? + if subdir in task.action: + break + setattr(mylookup, '_subdir', subdir + 's') + + items = wrap_var(mylookup.run(terms=loop_terms, variables=vars_copy)) + except AnsibleTemplateError: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail |