diff --git a/changelogs/fragments/include-role-name.yaml b/changelogs/fragments/include-role-name.yaml new file mode 100644 index 00000000000..9565321735f --- /dev/null +++ b/changelogs/fragments/include-role-name.yaml @@ -0,0 +1,5 @@ +minor_changes: + - magic variables - added a new ``ansible_parent_role_names`` magic variable that, when a role is included by another + role, contains a list of all parent roles. + - magic variables - added a new ``ansible_parent_role_paths`` magic variable that, when a role is included by another + role, contains a list of all parent role paths. diff --git a/docs/docsite/rst/reference_appendices/special_variables.rst b/docs/docsite/rst/reference_appendices/special_variables.rst index 41324834d6c..9a0d562547e 100644 --- a/docs/docsite/rst/reference_appendices/special_variables.rst +++ b/docs/docsite/rst/reference_appendices/special_variables.rst @@ -31,6 +31,16 @@ ansible_loop ansible_loop_var The name of the value provided to ``loop_control.loop_var``. Added in ``2.8`` +ansible_parent_role_names + When the current role is being executed by means of an :ref:`include_role ` or :ref:`import_role ` action, this variable contains a list of all parent roles, with the most recent role (i.e. the role that included/imported this role) being the first item in the list. + When multiple inclusions occur, this list lists the *last* role (i.e. the role that included this role) as the *first* item in the list. It is also possible that a specific role exists more than once in this list. + + For example: When role **A** includes role **B**, inside role B, ``ansible_parent_role_names`` will equal to ``['A']``. If role **B** then includes role **C**, the list becomes ``['B', 'A']``. + +ansible_parent_role_paths + When the current role is being executed by means of an :ref:`include_role ` or :ref:`import_role ` action, this variable contains a list of all parent roles, with the most recent role (i.e. the role that included/imported this role) being the first item in the list. + Please refer to ``ansible_parent_role_names`` for the order of items in this list. + ansible_play_batch List of active hosts in the current play run limited by the serial, aka 'batch'. Failed/Unreachable hosts are not considered 'active'. @@ -100,7 +110,7 @@ playbook_dir The path to the directory of the playbook that was passed to the ``ansible-playbook`` command line. role_name - The name of the currently executed role + The name of the role currently being executed. role_names Deprecated, the same as ansible_play_role_names diff --git a/lib/ansible/playbook/role_include.py b/lib/ansible/playbook/role_include.py index 870dea80d6b..d1da3c94879 100644 --- a/lib/ansible/playbook/role_include.py +++ b/lib/ansible/playbook/role_include.py @@ -166,4 +166,6 @@ class IncludeRole(TaskInclude): v = super(IncludeRole, self).get_include_params() if self._parent_role: v.update(self._parent_role.get_role_params()) + v.setdefault('ansible_parent_role_names', []).insert(0, self._parent_role.get_name()) + v.setdefault('ansible_parent_role_paths', []).insert(0, self._parent_role._role_path) return v diff --git a/test/integration/targets/include_parent_role_vars/aliases b/test/integration/targets/include_parent_role_vars/aliases new file mode 100644 index 00000000000..23abb8d3712 --- /dev/null +++ b/test/integration/targets/include_parent_role_vars/aliases @@ -0,0 +1,2 @@ +# Continuation of special_vars integration tests to test special variables set on role inclusion. +hidden \ No newline at end of file diff --git a/test/integration/targets/include_parent_role_vars/tasks/included_by_other_role.yml b/test/integration/targets/include_parent_role_vars/tasks/included_by_other_role.yml new file mode 100644 index 00000000000..79b7b1cbde8 --- /dev/null +++ b/test/integration/targets/include_parent_role_vars/tasks/included_by_other_role.yml @@ -0,0 +1,37 @@ +# Copyright 2019 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: ensure our parent role tree to contain only our direct parent item + assert: + that: + - "ansible_parent_role_names == ['special_vars']" + +- name: ensure that ansible_parent_role_paths has the same length as ansible_parent_role_names + assert: + that: + - "ansible_parent_role_names|length == ansible_parent_role_paths|length" + +- name: attempt to import ourselves + import_role: + name: "include_parent_role_vars" + tasks_from: "included_by_ourselves.yml" + +- name: ensure our parent role tree to contain only our direct parent item after importing + assert: + that: + - "ansible_parent_role_names == ['special_vars']" + +- name: attempt to include ourselves + include_role: + name: "include_parent_role_vars" + tasks_from: "included_by_ourselves.yml" + +- name: ensure our parent role tree to contain only our direct parent item after including + assert: + that: + - "ansible_parent_role_names == ['special_vars']" + +- name: ensure that ansible_parent_role_paths has the same length as ansible_parent_role_names + assert: + that: + - "ansible_parent_role_names|length == ansible_parent_role_paths|length" diff --git a/test/integration/targets/include_parent_role_vars/tasks/included_by_ourselves.yml b/test/integration/targets/include_parent_role_vars/tasks/included_by_ourselves.yml new file mode 100644 index 00000000000..3ea93004519 --- /dev/null +++ b/test/integration/targets/include_parent_role_vars/tasks/included_by_ourselves.yml @@ -0,0 +1,14 @@ +# Copyright 2019 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: check if the inclusion tree shows ourself twice as well as our initial parent + assert: + that: + - "ansible_parent_role_names|length == 2" + - "ansible_parent_role_names[0] == 'include_parent_role_vars'" # Since we included ourselves, we're the top level + - "ansible_parent_role_names[1] == 'special_vars'" + +- name: ensure that ansible_parent_role_paths has the same length as ansible_parent_role_names + assert: + that: + - "ansible_parent_role_names|length == ansible_parent_role_paths|length" diff --git a/test/integration/targets/include_parent_role_vars/tasks/main.yml b/test/integration/targets/include_parent_role_vars/tasks/main.yml new file mode 100644 index 00000000000..56a485bc25e --- /dev/null +++ b/test/integration/targets/include_parent_role_vars/tasks/main.yml @@ -0,0 +1,21 @@ +# Copyright 2019 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +- name: ensure our parent role tree to contain only our direct parent item + assert: + that: + - "ansible_parent_role_names == ['special_vars']" + +- name: ensure that ansible_parent_role_paths has the same length as ansible_parent_role_names + assert: + that: + - "ansible_parent_role_names|length == ansible_parent_role_paths|length" + +# task importing should not affect ansible_parent_role_names +- name: test task-importing after we've been included by another role + import_tasks: "included_by_other_role.yml" + +# task inclusion should not affect ansible_parent_role_names +- name: test task-inclusion after we've been included by another role + include_tasks: "included_by_other_role.yml" diff --git a/test/integration/targets/special_vars/aliases b/test/integration/targets/special_vars/aliases index 765b70da796..2d9e6788ad5 100644 --- a/test/integration/targets/special_vars/aliases +++ b/test/integration/targets/special_vars/aliases @@ -1 +1,2 @@ shippable/posix/group2 +needs/target/include_parent_role_vars diff --git a/test/integration/targets/special_vars/tasks/main.yml b/test/integration/targets/special_vars/tasks/main.yml index ab5c318d73e..1950f4cbeaa 100644 --- a/test/integration/targets/special_vars/tasks/main.yml +++ b/test/integration/targets/special_vars/tasks/main.yml @@ -56,3 +56,45 @@ assert: that: - "(ansible_play_role_names + ansible_dependent_role_names)|unique|sort|list == ansible_role_names|sort|list" + +- name: check that ansible_parent_role_names is normally unset when not included/imported (before including other roles) + assert: + that: + - "ansible_parent_role_names is undefined" + - "ansible_parent_role_paths is undefined" + +- name: ansible_parent_role_names - test functionality by including another role + include_role: + name: include_parent_role_vars + tasks_from: included_by_other_role.yml + +- name: check that ansible_parent_role_names is normally unset when not included/imported (after including other role) + assert: + that: + - "ansible_parent_role_names is undefined" + - "ansible_parent_role_paths is undefined" + +- name: ansible_parent_role_names - test functionality by importing another role + import_role: + name: include_parent_role_vars + tasks_from: included_by_other_role.yml + +- name: check that ansible_parent_role_names is normally unset when not included/imported (after importing other role) + assert: + that: + - "ansible_parent_role_names is undefined" + - "ansible_parent_role_paths is undefined" + +- name: ansible_parent_role_names - test functionality by including another role + include_role: + name: include_parent_role_vars + +- name: check that ansible_parent_role_names is normally unset when not included/imported (after both import and inlcude) + assert: + that: + - "ansible_parent_role_names is undefined" + - "ansible_parent_role_paths is undefined" + +- name: ansible_parent_role_names - test functionality by importing another role + import_role: + name: include_parent_role_vars