Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run an Ansible handler only once for the entire playbook

I would like to run a handler only once in an entire playbook.

I attempted using an include statement in the following in the playbook file, but this resulted in the handler being run multiple times, once for each play:

- name: Configure common config
  hosts: all
  become: true
  vars:
        OE: "{{ ansible_hostname[5] }}"
  roles:
    - { role: common }
  handlers:
    - include: handlers/main.yml

- name: Configure metadata config
  hosts: metadata
  become: true
  vars:
        OE: "{{ ansible_hostname[5] }}"
  roles:
    - { role: metadata }
  handlers:
    - include: handlers/main.yml

Here is the content of handlers/main.yml:

- name: restart autofs
  service:
    name: autofs.service
    state: restarted

Here is an example of one of the tasks that notifies the handler:

- name: Configure automount - /opt/local/xxx in /etc/auto.direct
  lineinfile:
     dest: /etc/auto.direct
     regexp: "^/opt/local/xxx"
     line: "/opt/local/xxx   -acdirmin=0,acdirmax=0,rdirplus,rw,hard,intr,bg,retry=2  nfs_server:/vol/xxx"
  notify: restart autofs

How can I get the playbook to only execute the handler once for the entire playbook?

like image 726
user3155618 Avatar asked Jan 09 '17 20:01

user3155618


People also ask

How do I make an Ansible run only once?

For such requirements where we need one tasks to run only once on a batch of hosts and we will be running that from Ansible controller node, we have feature parameter named run_once. When we have this parameter mentioned in a task, that task will run only once on first host it finds despite the host batch.

How do I limit Ansible hosts?

You can also limit the hosts you target on a particular run with the --limit flag. Negated limit. Note that single quotes MUST be used to prevent bash interpolation.

How do I run a specific part of my playbook in Ansible?

The easiest way to run only one task in Ansible Playbook is using the tags statement parameter of the “ansible-playbook” command. The default behavior is to execute all the tags in your Playbook with --tags all .


1 Answers

The answer

The literal answer to the question in the title is: no.

Playbook is a list of plays. Playbook has no namespace, no variables, no state. All the configuration, logic, and tasks are defined in plays.

Handler is a task with a different calling schedule (not sequential, but conditional, once at the end of a play, or triggered by the meta: flush_handlers task).

A handler belongs to a play, not a playbook, and there is no way to trigger it outside of the play (i.e. at the end of the playbook).


Solution

The solution to the problem is possible without referring to handlers.

You can use group_by module to create an ad-hoc group based on the result of the tasks at the bottom of each play.

Then you can define a separate play at the end of the playbook restarting the service on targets belonging to the above ad-hoc group.

Refer to the below stub for the idea:

- hosts: all
  roles:
    # roles declaration
  tasks:
    - # an example task modifying Nginx configuration
      register: nginx_configuration

    # ... other tasks ...

    - name: the last task in the play
      group_by:
        key: hosts_to_restart_{{ 'nginx' if nginx_configuration is changed else '' }}

# ... other plays ...

- hosts: hosts_to_restart_nginx
  gather_facts: no
  tasks:
    - service:
        name: nginx
        state: restarted
like image 171
techraf Avatar answered Oct 01 '22 18:10

techraf