Repository: ansible/ansible

Issue:
Handlers from roles included with include_role module is not found if the playbook including the role also has handlers
<!---
Please do not report issues/requests related to Ansible modules here !!

Report them to the appropriate modules-core or modules-extras project:
  - https://github.com/ansible/ansible-modules-core/issues
  - https://github.com/ansible/ansible-modules-extras/issues

Also verify first that your issue/request is not already reported in GitHub
-->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### COMPONENT NAME

<!--- Name of the plugin/task/feature -->

include_role module
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
ansible 2.2.0.0
  config file = 
  configured module search path = Default w/o overrides
```

Installed with:

```
pip2 install --user --upgrade git+https://github.com/ansible/ansible.git@v2.2.0.0-0.2.rc2#egg=ansible
```
##### CONFIGURATION

<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

No config file.
##### OS / ENVIRONMENT

<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->

Sample to reproduce runs on gentoo with target also being gentoo.
##### SUMMARY

<!--- Explain the problem briefly -->

If I include a role with the `include_role` module from a play with handlers then its handlers from the role are not available.
##### STEPS TO REPRODUCE

<!---
For bugs, show exactly how to reproduce the problem.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->

```
iwana@iwana-nb.concurrent.co.za:/var/tmp
$ git clone https://gitlab.com/iwan.aucamp/issue-ansible-201610-000-include_role.git
Cloning into 'issue-ansible-201610-000-include_role'...
remote: Counting objects: 10, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 10 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (10/10), done.
Checking connectivity... done.
iwana@iwana-nb.concurrent.co.za:/var/tmp
$ cd issue-ansible-201610-000-include_role
iwana@iwana-nb.concurrent.co.za:/var/tmp/issue-ansible-201610-000-include_role
(failed reverse-i-search)`ansibile -p': cd issue-^Csible-201610-000-include_role
iwana@iwana-nb.concurrent.co.za:/var/tmp/issue-ansible-201610-000-include_role
$ ansible-playbook main.yml 

iwana@iwana-nb.concurrent.co.za:/var/tmp/issue-ansible-201610-000-include_role
$ find . -name .git -prune -o -type f ! -name 'README*' -print | sort | xargs grep '^'
./main.yml:# vim: set sts=2 ts=2 sw=2 filetype=yaml expandtab:
./main.yml:---
./main.yml:- hosts: localhost
./main.yml:  tasks:
./main.yml:  - name: "this should trigger main-handler-one"
./main.yml:    command: "uname -a"
./main.yml:    notify: "main-handler-one"
./main.yml:  - include_role: { name: "test.irh", static: yes }
./main.yml:  handlers:
./main.yml:  - name: "main-handler-one"
./main.yml:    debug: { msg: "in main-handler-one" }
./roles/test.irh/handlers/main.yml:# vim: set sts=2 ts=2 sw=2 filetype=yaml expandtab:
./roles/test.irh/handlers/main.yml:---
./roles/test.irh/handlers/main.yml:- name: test.irh-handler-one
./roles/test.irh/handlers/main.yml:  debug: { msg: "in test.irh-handler-one" }
./roles/test.irh/tasks/main.yml:# vim: set sts=2 ts=2 sw=2 filetype=yaml expandtab:
./roles/test.irh/tasks/main.yml:---
./roles/test.irh/tasks/main.yml:- name: "this should trigger test.irh-handler-one"
./roles/test.irh/tasks/main.yml:  command: "uname -a"
./roles/test.irh/tasks/main.yml:  notify: test.irh-handler-one
```

<!--- You can also paste gist.github.com links for larger files -->
##### EXPECTED RESULTS

<!--- What did you expect to happen when running the steps above? -->

I expected `test.irh-handler-one` to run.
##### ACTUAL RESULTS

<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

Could not find `test.irh-handler-one`.

<!--- Paste verbatim command output between quotes below -->

```
$ ansible-playbook main.yml 
 [WARNING]: Host file not found: /etc/ansible/hosts

 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [localhost] ***************************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [this should trigger main-handler-one] ************************************
changed: [localhost]

TASK [test.irh : this should trigger test.irh-handler-one] *********************
ERROR! The requested handler 'test.irh-handler-one' was not found in either the main handlers list nor in the listening handlers list
```



Discussion:
bot_skip

An unsavory workaround is to copy the role's handlers (the ones from the role that are mistakenly not found) to the `handlers` section of the playbook with the other handlers.

We are getting by for now, but
- the scope of the mess cascades when you have included multiple roles with handlers
- it's not clear if handlers requiring var substitution will work right
- and this almost certainly messes with the order of handler execution

@flatrocks what I'm doing for the moment is

```
  handlers:
    - include: roles/.../handlers/part.yml
```
@aucampia would you mind testing this with the latest release of 2.4 and tell us if you're still seeing the issue. We believe this might be fixed. Thanks!

needs_info
seem to be encountering this, having multiple levels of role_includes (and no handlers in the playbook)
and running ansible 2.4
@calfonso I'm still seeing this issue with v2.4.2.0-0.5.rc1. It's also been reported on 2.5 (#31071).
@rpijlman can you provide a simple reproducer? According to my testing #31071 was fixed in https://github.com/ansible/ansible/pull/31463 which is included in `2.4.1`. Thanks!
 
needs_info
The mentioned workaround no longer works, doing a `include`, or `import_tasks` inside handlers will not save you from getting the error about missing handlers. This happens even with `ansible 2.4.3.0`.

Resolving patch:
diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py
--- a/lib/ansible/playbook/play.py
+++ b/lib/ansible/playbook/play.py
@@ -169,7 +169,11 @@ def _load_handlers(self, attr, ds):
         Bare handlers outside of a block are given an implicit block.
         '''
         try:
-            return load_list_of_blocks(ds=ds, play=self, use_handlers=True, variable_manager=self._variable_manager, loader=self._loader)
+            return self._extend_value(
+                self.handlers,
+                load_list_of_blocks(ds=ds, play=self, use_handlers=True, variable_manager=self._variable_manager, loader=self._loader),
+                prepend=True
+            )
         except AssertionError as e:
             raise AnsibleParserError("A malformed block was encountered while loading handlers", obj=self._ds, orig_exc=e)
 


Test patch: