Kan Li
Kan Li

Reputation: 8797

Ansible notify handlers in another role

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.

Upvotes: 78

Views: 64008

Answers (5)

stackdump
stackdump

Reputation: 748

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

So rather than invoking the handler - 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

Upvotes: 4

kxu
kxu

Reputation: 83

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

Upvotes: 2

Dima L.
Dima L.

Reputation: 3583

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

Upvotes: 11

famousgarkin
famousgarkin

Reputation: 14116

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
    

Upvotes: 82

DomaNitro
DomaNitro

Reputation: 3234

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

Upvotes: 36

Related Questions