73
votes

Can I notify the handler in another role? What should I do to make ansible find it?

The use case is, e.g. I want to configure some service and then restart it if changed. Different OS have probably different files to edit and even the file format can be different. So I would like to put them into different roles (because the file format can be different, it can't be done by setting group_vars). But the way to restart the service is the same, using service module; so I'd like to put the handler to common role.

Is anyway to achieve this? Thanks.

5
Did you find any solution?Robert

5 Answers

76
votes

You can also call handlers of a dependency role. May be cleaner than including files or explicitly listing roles in a playbook just for the purpose of role to role relationship. E.g.:

  • roles/my-handlers/handlers/main.yml

    ---
    - name: nginx restart
      service: >
        name=nginx
        state=restarted
    
  • roles/my-other/meta/main.yml

    ---
    dependencies:
    - role: my-handlers
    
  • roles/my-other/tasks/main.yml

    ---
    - copy: >
        src=nginx.conf
        dest=/etc/nginx/
      notify: nginx restart
    
36
votes

You should be able to do that if you include the handler file.

Example:

handlers:
  - include: someOtherRole/handlers/main.yml 

But I don't think its elegant.

A more elegant way is to have a play that manages both roles, something like this:

- hosts: all
  roles:
  - role1
  - role2

This will make both roles able to call other handlers.

But again I would suggest to make it all in one role and separate files and use a conditional include http://docs.ansible.com/playbooks_conditionals.html#conditional-imports

Hope that helps

10
votes

You may import additional handlers from YourRole/handlers/main.yml file by using import_tasks.

So, if MyRole needs to call handlers in some OtherRole, roles/MyRole/handlers/main.yml will look like this:

- import_tasks: roles/OtherRole/handlers/main.yml

Of course roles/MyRole/handlers/main.yml may include additional handlers as well.

This way if I want to run MyRole without running tasks from the OtherRole, ansible will be able to correctly import and run handlers from the OtherRole

4
votes

I had a similar issue, but needed to take many actions in the other dependent roles.

So rather than invoking the handeler - we set a fact like so:

- name: install mylib to virtualenv
  pip: requirements=/opt/mylib/requirements.txt virtualenv={{ mylib_virtualenv_path }}
  sudo_user: mylib
  register: mylib_wheel_upgraded

- name: set variable if source code was upgraded
  set_fact:
    mylib_source_upgraded: true
  when: mylib_wheel_upgraded.changed

Then elsewhere in another role:

- name: restart services if source code was upgraded
  command: /bin/true
  notify: restart mylib server
  when: mylib_source_upgraded
0
votes

Currently I'm using ansible v2.10.3 and it supports to call handlers on different roles. This was because the handlers are visible on the play-level, as per Ansible Docs says. You can see the docs mentioned that in the bottom-most point.

handlers are play scoped and as such can be used outside of the role they are defined in.

FYI, I tested the solution i.e. calling other role's handlers and it works! No need to import or else, just make sure that the roles are in the same playbook execution.

To illustrate:

  • roles/vm/handlers/main.yaml

    ---
    - name: rebootvm
      ansible.builtin.reboot:
        reboot_timeout: 600
        test_command: whoami
    
  • roles/config-files/tasks/main.yaml

    ---
    - name: Copy files from local to remote
      ansible.builtin.copy:
        dest: /home/ubuntu/config.conf
        src: config.conf
        backup: yes
        force: yes
      notify:
        - rebootvm
    

So when the config file (i.e. config.conf) changed, Ansible will send it to the remote location and it will notify the handler rebootvm, then the VM is rebooted.

P.S. I don't know what version exactly Ansible support this.

Edit: code indentation fix