diff --git a/changelogs/fragments/79079-fix-role-dep-chain.yaml b/changelogs/fragments/79079-fix-role-dep-chain.yaml new file mode 100644 index 00000000000..f0e8a05ed8e --- /dev/null +++ b/changelogs/fragments/79079-fix-role-dep-chain.yaml @@ -0,0 +1,2 @@ +bugfixes: + - include_role - Inherit from role parents beyond a depth of 3 (https://github.com/ansible/ansible/issues/47023). diff --git a/lib/ansible/playbook/role/__init__.py b/lib/ansible/playbook/role/__init__.py index 7cb9b1a6ce6..33ea6cbfef6 100644 --- a/lib/ansible/playbook/role/__init__.py +++ b/lib/ansible/playbook/role/__init__.py @@ -442,6 +442,13 @@ class Role(Base, Conditional, Taggable, CollectionSearch): def get_parents(self): return self._parents + def get_dep_chain(self): + dep_chain = [] + for parent in self._parents: + dep_chain.extend(parent.get_dep_chain()) + dep_chain.append(parent) + return dep_chain + def get_default_vars(self, dep_chain=None): dep_chain = [] if dep_chain is None else dep_chain diff --git a/lib/ansible/playbook/role_include.py b/lib/ansible/playbook/role_include.py index 3bce92d2f4b..23d3af039d3 100644 --- a/lib/ansible/playbook/role_include.py +++ b/lib/ansible/playbook/role_include.py @@ -100,11 +100,7 @@ class IncludeRole(TaskInclude): # compile role with parent roles as dependencies to ensure they inherit # variables - if not self._parent_role: - dep_chain = [] - else: - dep_chain = list(self._parent_role._parents) - dep_chain.append(self._parent_role) + dep_chain = actual_role.get_dep_chain() p_block = self.build_parent_block() diff --git a/test/integration/targets/roles/47023.yml b/test/integration/targets/roles/47023.yml new file mode 100644 index 00000000000..6b41b52f52e --- /dev/null +++ b/test/integration/targets/roles/47023.yml @@ -0,0 +1,5 @@ +--- +- hosts: all + gather_facts: no + tasks: + - include_role: name=47023_role1 diff --git a/test/integration/targets/roles/role_dep_chain.yml b/test/integration/targets/roles/role_dep_chain.yml new file mode 100644 index 00000000000..cf99a25a0f9 --- /dev/null +++ b/test/integration/targets/roles/role_dep_chain.yml @@ -0,0 +1,6 @@ +--- +- hosts: all + tasks: + - name: static import inside dynamic include inherits defaults/vars + include_role: + name: include_import_dep_chain diff --git a/test/integration/targets/roles/roles/47023_role1/defaults/main.yml b/test/integration/targets/roles/roles/47023_role1/defaults/main.yml new file mode 100644 index 00000000000..166caa33b30 --- /dev/null +++ b/test/integration/targets/roles/roles/47023_role1/defaults/main.yml @@ -0,0 +1 @@ +my_default: defined diff --git a/test/integration/targets/roles/roles/47023_role1/tasks/main.yml b/test/integration/targets/roles/roles/47023_role1/tasks/main.yml new file mode 100644 index 00000000000..9c408ba2edd --- /dev/null +++ b/test/integration/targets/roles/roles/47023_role1/tasks/main.yml @@ -0,0 +1 @@ +- include_role: name=47023_role2 diff --git a/test/integration/targets/roles/roles/47023_role1/vars/main.yml b/test/integration/targets/roles/roles/47023_role1/vars/main.yml new file mode 100644 index 00000000000..bfda56b9b80 --- /dev/null +++ b/test/integration/targets/roles/roles/47023_role1/vars/main.yml @@ -0,0 +1 @@ +my_var: defined diff --git a/test/integration/targets/roles/roles/47023_role2/tasks/main.yml b/test/integration/targets/roles/roles/47023_role2/tasks/main.yml new file mode 100644 index 00000000000..4544215f84a --- /dev/null +++ b/test/integration/targets/roles/roles/47023_role2/tasks/main.yml @@ -0,0 +1 @@ +- include_role: name=47023_role3 diff --git a/test/integration/targets/roles/roles/47023_role3/tasks/main.yml b/test/integration/targets/roles/roles/47023_role3/tasks/main.yml new file mode 100644 index 00000000000..9479fe3f3d8 --- /dev/null +++ b/test/integration/targets/roles/roles/47023_role3/tasks/main.yml @@ -0,0 +1 @@ +- include_role: name=47023_role4 diff --git a/test/integration/targets/roles/roles/47023_role4/tasks/main.yml b/test/integration/targets/roles/roles/47023_role4/tasks/main.yml new file mode 100644 index 00000000000..64c96e97dd6 --- /dev/null +++ b/test/integration/targets/roles/roles/47023_role4/tasks/main.yml @@ -0,0 +1,5 @@ +- debug: + msg: "Var is {{ my_var | default('undefined') }}" + +- debug: + msg: "Default is {{ my_default | default('undefined') }}" diff --git a/test/integration/targets/roles/roles/imported_from_include/tasks/main.yml b/test/integration/targets/roles/roles/imported_from_include/tasks/main.yml new file mode 100644 index 00000000000..32126f87d2b --- /dev/null +++ b/test/integration/targets/roles/roles/imported_from_include/tasks/main.yml @@ -0,0 +1,4 @@ +- assert: + that: + - inherit_var is defined + - inherit_default is defined diff --git a/test/integration/targets/roles/roles/include_import_dep_chain/defaults/main.yml b/test/integration/targets/roles/roles/include_import_dep_chain/defaults/main.yml new file mode 100644 index 00000000000..5b8a643d1a9 --- /dev/null +++ b/test/integration/targets/roles/roles/include_import_dep_chain/defaults/main.yml @@ -0,0 +1 @@ +inherit_default: default diff --git a/test/integration/targets/roles/roles/include_import_dep_chain/tasks/main.yml b/test/integration/targets/roles/roles/include_import_dep_chain/tasks/main.yml new file mode 100644 index 00000000000..84884a8d811 --- /dev/null +++ b/test/integration/targets/roles/roles/include_import_dep_chain/tasks/main.yml @@ -0,0 +1,2 @@ +- import_role: + name: imported_from_include diff --git a/test/integration/targets/roles/roles/include_import_dep_chain/vars/main.yml b/test/integration/targets/roles/roles/include_import_dep_chain/vars/main.yml new file mode 100644 index 00000000000..0d4aaa94900 --- /dev/null +++ b/test/integration/targets/roles/roles/include_import_dep_chain/vars/main.yml @@ -0,0 +1 @@ +inherit_var: var diff --git a/test/integration/targets/roles/runme.sh b/test/integration/targets/roles/runme.sh index bad02bc9d0f..1e154b795a2 100755 --- a/test/integration/targets/roles/runme.sh +++ b/test/integration/targets/roles/runme.sh @@ -29,3 +29,9 @@ fi # ensure vars scope is correct ansible-playbook vars_scope.yml -i ../../inventory "$@" + +# test nested includes get parent roles greater than a depth of 3 +[ "$(ansible-playbook 47023.yml -i ../../inventory "$@" | grep '\<\(Default\|Var\)\>' | grep -c 'is defined')" = "2" ] + +# ensure import_role called from include_role has the include_role in the dep chain +ansible-playbook role_dep_chain.yml -i ../../inventory "$@"