Give IncludedFile more context via ansible_search_path (#50045)
* Give IncludedFile more context via ansible_search_path to template lookups. Fixes #49969 * Update units
This commit is contained in:
parent
6620facd19
commit
3b49bbcfde
8 changed files with 50 additions and 2 deletions
3
changelogs/fragments/include_tasks_parent_templating.yml
Normal file
3
changelogs/fragments/include_tasks_parent_templating.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
bugfixes:
|
||||||
|
- include_tasks - Ensure we give IncludedFile the same context as TaskExecutor when templating the parent include path
|
||||||
|
allowing for lookups in the included file path (https://github.com/ansible/ansible/issues/49969)
|
|
@ -21,6 +21,8 @@ __metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.playbook.task_include import TaskInclude
|
from ansible.playbook.task_include import TaskInclude
|
||||||
from ansible.playbook.role_include import IncludeRole
|
from ansible.playbook.role_include import IncludeRole
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
|
@ -78,7 +80,6 @@ class IncludedFile:
|
||||||
task_vars = task_vars_cache[cache_key]
|
task_vars = task_vars_cache[cache_key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
task_vars = task_vars_cache[cache_key] = variable_manager.get_vars(play=iterator._play, host=original_host, task=original_task)
|
task_vars = task_vars_cache[cache_key] = variable_manager.get_vars(play=iterator._play, host=original_host, task=original_task)
|
||||||
templar = Templar(loader=loader, variables=task_vars)
|
|
||||||
|
|
||||||
include_variables = include_result.get('include_variables', dict())
|
include_variables = include_result.get('include_variables', dict())
|
||||||
loop_var = 'item'
|
loop_var = 'item'
|
||||||
|
@ -95,6 +96,16 @@ class IncludedFile:
|
||||||
if original_task.no_log and '_ansible_no_log' not in include_variables:
|
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_no_log'] = include_variables['_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
|
||||||
|
task_vars['ansible_search_path'] = original_task.get_search_path()
|
||||||
|
|
||||||
|
# ensure basedir is always in (dwim already searches here but we need to display it)
|
||||||
|
if loader.get_basedir() not in task_vars['ansible_search_path']:
|
||||||
|
task_vars['ansible_search_path'].append(loader.get_basedir())
|
||||||
|
|
||||||
|
templar = Templar(loader=loader, variables=task_vars)
|
||||||
|
|
||||||
if original_task.action in ('include', 'include_tasks'):
|
if original_task.action in ('include', 'include_tasks'):
|
||||||
include_file = None
|
include_file = None
|
||||||
if original_task:
|
if original_task:
|
||||||
|
@ -113,7 +124,15 @@ class IncludedFile:
|
||||||
if isinstance(parent_include, IncludeRole):
|
if isinstance(parent_include, IncludeRole):
|
||||||
parent_include_dir = parent_include._role_path
|
parent_include_dir = parent_include._role_path
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params')))
|
parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params')))
|
||||||
|
except AnsibleError as e:
|
||||||
|
parent_include_dir = ''
|
||||||
|
display.warning(
|
||||||
|
'Templating the path of the parent %s failed. The path to the '
|
||||||
|
'included file may not be found. '
|
||||||
|
'The error was: %s.' % (original_task.action, to_text(e))
|
||||||
|
)
|
||||||
if cumulative_path is not None and not os.path.isabs(cumulative_path):
|
if cumulative_path is not None and not os.path.isabs(cumulative_path):
|
||||||
cumulative_path = os.path.join(parent_include_dir, cumulative_path)
|
cumulative_path = os.path.join(parent_include_dir, cumulative_path)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# https://github.com/ansible/ansible/issues/49969
|
||||||
|
- hosts: localhost
|
||||||
|
gather_facts: false
|
||||||
|
tasks:
|
||||||
|
- include_role:
|
||||||
|
name: test
|
||||||
|
public: true
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- included_other is defined
|
|
@ -0,0 +1 @@
|
||||||
|
- include_tasks: other.yml
|
|
@ -0,0 +1 @@
|
||||||
|
- include_tasks: "{{ lookup('first_found', inventory_hostname ~ '.yml') }}"
|
|
@ -0,0 +1,2 @@
|
||||||
|
- set_fact:
|
||||||
|
included_other: true
|
|
@ -90,3 +90,7 @@ ansible-playbook run_once/playbook.yml "$@"
|
||||||
# https://github.com/ansible/ansible/issues/48936
|
# https://github.com/ansible/ansible/issues/48936
|
||||||
ansible-playbook -v handler_addressing/playbook.yml 2>&1 | tee test_handler_addressing.out
|
ansible-playbook -v handler_addressing/playbook.yml 2>&1 | tee test_handler_addressing.out
|
||||||
test "$(egrep -c 'include handler task|ERROR! The requested handler '"'"'do_import'"'"' was not found' test_handler_addressing.out)" = 2
|
test "$(egrep -c 'include handler task|ERROR! The requested handler '"'"'do_import'"'"' was not found' test_handler_addressing.out)" = 2
|
||||||
|
|
||||||
|
# https://github.com/ansible/ansible/issues/49969
|
||||||
|
ansible-playbook -v parent_templating/playbook.yml 2>&1 | tee test_parent_templating.out
|
||||||
|
test "$(egrep -c 'Templating the path of the parent include_tasks failed.' test_parent_templating.out)" = 0
|
||||||
|
|
|
@ -65,6 +65,7 @@ def test_process_include_results(mock_iterator, mock_variable_manager):
|
||||||
|
|
||||||
parent_task_ds = {'debug': 'msg=foo'}
|
parent_task_ds = {'debug': 'msg=foo'}
|
||||||
parent_task = Task.load(parent_task_ds)
|
parent_task = Task.load(parent_task_ds)
|
||||||
|
parent_task._play = None
|
||||||
|
|
||||||
task_ds = {'include': 'include_test.yml'}
|
task_ds = {'include': 'include_test.yml'}
|
||||||
loaded_task = TaskInclude.load(task_ds, task_include=parent_task)
|
loaded_task = TaskInclude.load(task_ds, task_include=parent_task)
|
||||||
|
@ -91,12 +92,15 @@ def test_process_include_diff_files(mock_iterator, mock_variable_manager):
|
||||||
|
|
||||||
parent_task_ds = {'debug': 'msg=foo'}
|
parent_task_ds = {'debug': 'msg=foo'}
|
||||||
parent_task = Task.load(parent_task_ds)
|
parent_task = Task.load(parent_task_ds)
|
||||||
|
parent_task._play = None
|
||||||
|
|
||||||
task_ds = {'include': 'include_test.yml'}
|
task_ds = {'include': 'include_test.yml'}
|
||||||
loaded_task = TaskInclude.load(task_ds, task_include=parent_task)
|
loaded_task = TaskInclude.load(task_ds, task_include=parent_task)
|
||||||
|
loaded_task._play = None
|
||||||
|
|
||||||
child_task_ds = {'include': 'other_include_test.yml'}
|
child_task_ds = {'include': 'other_include_test.yml'}
|
||||||
loaded_child_task = TaskInclude.load(child_task_ds, task_include=loaded_task)
|
loaded_child_task = TaskInclude.load(child_task_ds, task_include=loaded_task)
|
||||||
|
loaded_child_task._play = None
|
||||||
|
|
||||||
return_data = {'include': 'include_test.yml'}
|
return_data = {'include': 'include_test.yml'}
|
||||||
# The task in the TaskResult has to be a TaskInclude so it has a .static attr
|
# The task in the TaskResult has to be a TaskInclude so it has a .static attr
|
||||||
|
@ -129,6 +133,9 @@ def test_process_include_simulate_free(mock_iterator, mock_variable_manager):
|
||||||
parent_task1 = Task.load(parent_task_ds)
|
parent_task1 = Task.load(parent_task_ds)
|
||||||
parent_task2 = Task.load(parent_task_ds)
|
parent_task2 = Task.load(parent_task_ds)
|
||||||
|
|
||||||
|
parent_task1._play = None
|
||||||
|
parent_task2._play = None
|
||||||
|
|
||||||
task_ds = {'include': 'include_test.yml'}
|
task_ds = {'include': 'include_test.yml'}
|
||||||
loaded_task1 = TaskInclude.load(task_ds, task_include=parent_task1)
|
loaded_task1 = TaskInclude.load(task_ds, task_include=parent_task1)
|
||||||
loaded_task2 = TaskInclude.load(task_ds, task_include=parent_task2)
|
loaded_task2 = TaskInclude.load(task_ds, task_include=parent_task2)
|
||||||
|
|
Loading…
Reference in a new issue