diff --git a/changelogs/fragments/import_tasks-fixes.yml b/changelogs/fragments/import_tasks-fixes.yml new file mode 100644 index 00000000000..cd5d56b0ba3 --- /dev/null +++ b/changelogs/fragments/import_tasks-fixes.yml @@ -0,0 +1,3 @@ +bugfixes: + - Fix traceback when trying to import non-existing file via nested ``import_tasks`` (https://github.com/ansible/ansible/issues/69882) + - Fix issues with keywords being incorrectly validated on ``import_tasks`` (https://github.com/ansible/ansible/issues/85855, https://github.com/ansible/ansible/issues/85856) diff --git a/lib/ansible/playbook/helpers.py b/lib/ansible/playbook/helpers.py index 805f46145d3..e3e9fab7bfc 100644 --- a/lib/ansible/playbook/helpers.py +++ b/lib/ansible/playbook/helpers.py @@ -165,17 +165,29 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h subdir = 'tasks' if use_handlers: subdir = 'handlers' + try: + include_target = templar.template(task.args['_raw_params']) + except AnsibleUndefinedVariable as ex: + raise AnsibleParserError( + message=f"Error when evaluating variable in import path {task.args['_raw_params']!r}.", + help_text="When using static imports, ensure that any variables used in their names are defined in vars/vars_files\n" + "or extra-vars passed in from the command line. Static imports cannot use variables from facts or inventory\n" + "sources like group or host vars.", + obj=task_ds, + ) from ex + # FIXME this appears to be (almost?) duplicate code as in IncludedFile for include_tasks while parent_include is not None: if not isinstance(parent_include, TaskInclude): parent_include = parent_include._parent continue - parent_include.post_validate(templar=templar) - parent_include_dir = os.path.dirname(parent_include.args.get('_raw_params')) + if isinstance(parent_include, IncludeRole): + parent_include_dir = parent_include._role_path + else: + parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params'))) if cumulative_path is None: cumulative_path = parent_include_dir elif not os.path.isabs(cumulative_path): cumulative_path = os.path.join(parent_include_dir, cumulative_path) - include_target = templar.template(task.args['_raw_params']) if task._role: new_basedir = os.path.join(task._role._role_path, subdir, cumulative_path) include_file = loader.path_dwim_relative(new_basedir, subdir, include_target) @@ -189,16 +201,6 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h parent_include = parent_include._parent if not found: - try: - include_target = templar.template(task.args['_raw_params']) - except AnsibleUndefinedVariable as ex: - raise AnsibleParserError( - message=f"Error when evaluating variable in import path {task.args['_raw_params']!r}.", - help_text="When using static imports, ensure that any variables used in their names are defined in vars/vars_files\n" - "or extra-vars passed in from the command line. Static imports cannot use variables from facts or inventory\n" - "sources like group or host vars.", - obj=task_ds, - ) from ex if task._role: include_file = loader.path_dwim_relative(task._role._role_path, subdir, include_target) else: diff --git a/test/integration/targets/include_import/roles/nested_tasks/tasks/bar.yml b/test/integration/targets/include_import/roles/nested_tasks/tasks/bar.yml new file mode 100644 index 00000000000..25fdfa54b48 --- /dev/null +++ b/test/integration/targets/include_import/roles/nested_tasks/tasks/bar.yml @@ -0,0 +1 @@ +- import_tasks: does-not-exist.yml diff --git a/test/integration/targets/include_import/roles/nested_tasks/tasks/foo.yml b/test/integration/targets/include_import/roles/nested_tasks/tasks/foo.yml new file mode 100644 index 00000000000..4ba2582011b --- /dev/null +++ b/test/integration/targets/include_import/roles/nested_tasks/tasks/foo.yml @@ -0,0 +1 @@ +- include_tasks: bar.yml diff --git a/test/integration/targets/include_import/roles/nested_tasks/tasks/main.yml b/test/integration/targets/include_import/roles/nested_tasks/tasks/main.yml new file mode 100644 index 00000000000..27c0ec7ecb2 --- /dev/null +++ b/test/integration/targets/include_import/roles/nested_tasks/tasks/main.yml @@ -0,0 +1 @@ +- import_tasks: foo.yml diff --git a/test/integration/targets/include_import/runme.sh b/test/integration/targets/include_import/runme.sh index 1e144a455d1..b28b7222515 100755 --- a/test/integration/targets/include_import/runme.sh +++ b/test/integration/targets/include_import/runme.sh @@ -155,3 +155,9 @@ ansible-playbook test_null_include_filename.yml 2>&1 | tee test_null_include_fil test "$(grep -c 'No file specified for ansible.builtin.include_tasks' test_null_include_filename.out)" = 1 test "$(grep -c '.*/include_import/null_filename/tasks.yml:4:3.*' test_null_include_filename.out)" = 1 test "$(grep -c '\- name: invalid include_task definition' test_null_include_filename.out)" = 1 + +# https://github.com/ansible/ansible/issues/69882 +set +e +ansible-playbook test_nested_non_existent_tasks.yml 2>&1 | tee test_nested_non_existent_tasks.out +set -e +test "$(grep -c 'Could not find or access' test_nested_non_existent_tasks.out)" = 3 diff --git a/test/integration/targets/include_import/test_nested_non_existent_tasks.yml b/test/integration/targets/include_import/test_nested_non_existent_tasks.yml new file mode 100644 index 00000000000..62f371b3d3c --- /dev/null +++ b/test/integration/targets/include_import/test_nested_non_existent_tasks.yml @@ -0,0 +1,5 @@ +- hosts: localhost + gather_facts: false + tasks: + - include_role: + name: nested_tasks diff --git a/test/integration/targets/include_import_tasks_nested/tasks/main.yml b/test/integration/targets/include_import_tasks_nested/tasks/main.yml index 671eb2f1c5d..742d942b4fb 100644 --- a/test/integration/targets/include_import_tasks_nested/tasks/main.yml +++ b/test/integration/targets/include_import_tasks_nested/tasks/main.yml @@ -10,4 +10,9 @@ that: - nested_adjacent_count|int == 2 +- set_fact: + not_available_at_parsing: root + - import_tasks: "{{ role_path }}/tests/main.yml" + become: true + become_user: "{{ not_available_at_parsing }}" diff --git a/test/integration/targets/include_import_tasks_nested/tests/tests_relative.yml b/test/integration/targets/include_import_tasks_nested/tests/tests_relative.yml index e69de29bb2d..76a54def3f1 100644 --- a/test/integration/targets/include_import_tasks_nested/tests/tests_relative.yml +++ b/test/integration/targets/include_import_tasks_nested/tests/tests_relative.yml @@ -0,0 +1,6 @@ +- command: whoami + register: r + +- assert: + that: + - r.stdout == not_available_at_parsing