Michael
Michael

Reputation: 2942

Use first handler defined with same name

According to docs "Handlers always run in the order they are defined". When running a role multiple times with the same handler name, Ansible overwrites the first ones and uses only the last handler. This way the handler has less priority than defined in the handlers file.

Is there a way to run a handler at first when triggered multiple times via a loop?

Example

Playbook "test.yml"

- hosts: localhost
  gather_facts: no
  become: yes
  become_method: sudo

  vars:
    services:
      - service_name: abc
      - service_name: xyz

  tasks:
    - include_role:
        name: install-service
      vars:
        service_name: "{{ item.service_name }}"
      loop: "{{ services }}"

Role "install-service" tasks

- name: Installing service {{ service_name }}
  command: echo hello {{ service_name }}
  notify:
    - reload systemd
    - restart service {{ service_name }}

Role "install-service" handlers

- name: reload systemd
  debug:
    msg: Reloading systemd
- name: restart service {{ service_name }}
  debug:
    msg: Restarting {{ service_name }}

Run

> ansible-playbook test.yml                                     

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

TASK [include_role : install-service] **********************************************************************************

TASK [install-service : Installing service abc] ************************************************************************
changed: [localhost]

TASK [install-service : Installing service xyz] ************************************************************************
changed: [localhost]

RUNNING HANDLER [install-service : restart service abc] ****************************************************************
ok: [localhost] => 
  msg: Restarting abc

RUNNING HANDLER [install-service : reload systemd] *********************************************************************
ok: [localhost] => 
  msg: Reloading systemd

RUNNING HANDLER [install-service : restart service xyz] ****************************************************************
ok: [localhost] => 
  msg: Restarting xyz

PLAY RECAP *************************************************************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

In this example the role "install-service" is called multiple times for all "services". And at the end, Ansible should reload systemd and then restart all services.

But actually Ansible will Restart all services but the last, then it will reload systemd and then the last service is restarted.

This makes sence as the role gets included multiple times and the handlers with the same name overwriting themself. Only the last one is kept. And the last "reload systemd" handler is defined before the last "restart service ...".

So how can I run the handler "reload systemd" before all the services?

Upvotes: 0

Views: 874

Answers (1)

Frenchy
Frenchy

Reputation: 17017

the only way i see to resolv your problem is to notify the restart from handlers:

handlers:

- name: reload systemd
  debug:
    msg: Reloading systemd
  changed_when: true
  notify:
    - restart service

- name: restart service
  debug:
    msg: Restarting {{ service_name }}
  vars:
    service_name: "{{ item.service_name }}"
  loop: "{{ services }}"

role:

- name: Installing service {{ service_name }}
  command: echo hello {{ service_name }}
  notify:
    - reload systemd

result:

PLAY [localhost] 

TASK [include_role : install-service] 

TASK [install-service : Installing service abc] 
changed: [localhost]

TASK [install-service : Installing service xyz] 
changed: [localhost]

RUNNING HANDLER [install-service : reload systemd] 
changed: [localhost] => {
    "msg": "Reloading systemd"
}

RUNNING HANDLER [install-service : restart service] 

ok: [localhost] => (item={'service_name': 'abc'}) => {
    "msg": "Restarting abc"
}
ok: [localhost] => (item={'service_name': 'xyz'}) => {
    "msg": "Restarting xyz"
}

Upvotes: 0

Related Questions