From a452c53375e0a05900103df25363fc055fb51543 Mon Sep 17 00:00:00 2001 From: Sloane Hertel <19572925+s-hertel@users.noreply.github.com> Date: Tue, 6 Feb 2024 10:13:47 -0500 Subject: [PATCH] import_role - allow subdirectories with _from options (#82642) * Allow subdirectories with import_role _from options Add tests that tasks_from is restricted to the role Note that a task like: - import_role: name: role tasks_from: tasks/entrypoint.yml will now load tasks from "{{ role_path }}/tasks/tasks/entrypoint.yml" instead of "{{ role_path }}/tasks/entrypoint.yml". This change in behavior matches include_role. * better test case (filename doesn't match one in tasks/) Fixes #82584 --- .../fix-import_role-_from-options.yml | 2 ++ lib/ansible/playbook/role_include.py | 4 +--- .../targets/roles/no_outside_import.yml | 6 ++++++ .../roles/roles/a/tasks/subdir/entrypoint.yml | 1 + test/integration/targets/roles/runme.sh | 20 ++++++++++++------- .../targets/roles/test_subdirs.yml | 10 ++++++++++ 6 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/fix-import_role-_from-options.yml create mode 100644 test/integration/targets/roles/no_outside_import.yml create mode 100644 test/integration/targets/roles/roles/a/tasks/subdir/entrypoint.yml create mode 100644 test/integration/targets/roles/test_subdirs.yml diff --git a/changelogs/fragments/fix-import_role-_from-options.yml b/changelogs/fragments/fix-import_role-_from-options.yml new file mode 100644 index 00000000000..b6b0e2395cc --- /dev/null +++ b/changelogs/fragments/fix-import_role-_from-options.yml @@ -0,0 +1,2 @@ +minor_changes: + - import_role - allow subdirectories with ``_from`` options for parity with ``include_role`` (https://github.com/ansible/ansible/issues/82584). diff --git a/lib/ansible/playbook/role_include.py b/lib/ansible/playbook/role_include.py index 1e5c48bb0e1..628f26ec0a8 100644 --- a/lib/ansible/playbook/role_include.py +++ b/lib/ansible/playbook/role_include.py @@ -16,8 +16,6 @@ from __future__ import annotations -from os.path import basename - import ansible.constants as C from ansible.errors import AnsibleParserError from ansible.playbook.attribute import NonInheritableFieldAttribute @@ -141,7 +139,7 @@ class IncludeRole(TaskInclude): args_value = ir.args.get(key) if not isinstance(args_value, string_types): raise AnsibleParserError('Expected a string for %s but got %s instead' % (key, type(args_value))) - ir._from_files[from_key] = basename(args_value) + ir._from_files[from_key] = args_value # apply is only valid for includes, not imports as they inherit directly apply_attrs = ir.args.get('apply', {}) diff --git a/test/integration/targets/roles/no_outside_import.yml b/test/integration/targets/roles/no_outside_import.yml new file mode 100644 index 00000000000..c9e0d130e50 --- /dev/null +++ b/test/integration/targets/roles/no_outside_import.yml @@ -0,0 +1,6 @@ +- hosts: testhost + gather_facts: false + tasks: + - import_role: + name: a + tasks_from: subdir/../../../../no_outside.yml diff --git a/test/integration/targets/roles/roles/a/tasks/subdir/entrypoint.yml b/test/integration/targets/roles/roles/a/tasks/subdir/entrypoint.yml new file mode 100644 index 00000000000..331ec9405f8 --- /dev/null +++ b/test/integration/targets/roles/roles/a/tasks/subdir/entrypoint.yml @@ -0,0 +1 @@ +- debug: msg=subdir diff --git a/test/integration/targets/roles/runme.sh b/test/integration/targets/roles/runme.sh index bf3aaf58239..5227e42ed86 100755 --- a/test/integration/targets/roles/runme.sh +++ b/test/integration/targets/roles/runme.sh @@ -26,13 +26,19 @@ ansible-playbook role_complete.yml -i ../../inventory -i fake, --tags unreachabl ansible-playbook data_integrity.yml -i ../../inventory "$@" # ensure role fails when trying to load 'non role' in _from -ansible-playbook no_outside.yml -i ../../inventory > role_outside_output.log 2>&1 || true -if grep "as it is not inside the expected role path" role_outside_output.log >/dev/null; then - echo "Test passed (playbook failed with expected output, output not shown)." -else - echo "Test failed, expected output from playbook failure is missing, output not shown)." - exit 1 -fi +test_no_outside=("no_outside.yml" "no_outside_import.yml") +for file in "${test_no_outside[@]}"; do + ansible-playbook "$file" -i ../../inventory > "${file}_output.log" 2>&1 || true + if grep "as it is not inside the expected role path" "${file}_output.log" >/dev/null; then + echo "Test passed for $file (playbook failed with expected output, output not shown)." + else + echo "Test failed for $file, expected output from playbook failure is missing, output not shown)." + exit 1 + fi +done + +# ensure subdir contained to role in tasks_from is valid +ansible-playbook test_subdirs.yml -i ../../inventory "$@" # ensure vars scope is correct ansible-playbook vars_scope.yml -i ../../inventory "$@" diff --git a/test/integration/targets/roles/test_subdirs.yml b/test/integration/targets/roles/test_subdirs.yml new file mode 100644 index 00000000000..503239d0999 --- /dev/null +++ b/test/integration/targets/roles/test_subdirs.yml @@ -0,0 +1,10 @@ +--- +- hosts: testhost + gather_facts: false + tasks: + - import_role: + name: a + tasks_from: subdir/entrypoint.yml + - include_role: + name: a + tasks_from: subdir/entrypoint.yml