This is in continuation to the articles of Ansible. In the previous article, we have seen how we can set up the local NTP configuration file and how we can deploy it to the servers to get the benefit of setting up the configuration at one place and not doing this again and again in case we have 100s of servers.
But If we look closely at the playbook that we wrote we can see that if we again run the same playbook then the NTP service will again get restarted, and this should not happen as we have already deployed the NTP config file and if we have not done any change in that config then the NTP service should not get restarted.
So, we should devise a way such that NTP service will only get restarted if we have made some change in NTP configuration files. To resolve this, we can make use of handlers in Ansible. Thus, in this article we will be covering Handlers in Ansible.
Handlers
Handlers are just like regular tasks in an Ansible playbook (see Tasks) but are only run if the Task contains a “notify” directive and also indicates that it changed something. For example, if a config file is changed then the task referencing the config file templating operation may notify a service restart handler.
Handlers are the same as tasks, but they get executed only when they are notified but tasks get executed every time we run the playbook. Handlers should be in the same line as that of tasks inside the playbook.
So below is the updated version of the playbook that we wrote in the previous article
---
- name: Deploying NTP Service
hosts: all
become: yes
tasks:
- name: Install packages on RedHat OS
yum:
name: "{{item}}"
state: present
loop:
- ntp
- unzip
- git
- wget
- zip
when: ansible_os_family == "RedHat"
- name: Install packages on Debian OS
apt:
name: "{{item}}"
state: present
loop:
- ntp
- unzip
- git
- wget
- zip
when: ansible_os_family == "Debian"
- name: Start and Enable NTP service in RedHat OS
service:
name: ntpd
state: started
enabled: yes
when: ansible_os_family == "RedHat"
- name: Start and Enable NTP service in Debian OS
service:
name: ntp
state: started
enabled: yes
when: ansible_os_family == "Debian"
- name: Deploy the NTP configuration file for Debian OS
copy:
src: files/ntp_debian.conf
dest: /etc/ntp.conf
backup: yes
when: ansible_os_family == "Debian"
notify:
- Restart NTP service in Debian OS
- name: Deploy the NTP configuration file for RedHat OS
copy:
src: files/ntp_redhat.conf
dest: /etc/ntp.conf
backup: yes
when: ansible_os_family == "RedHat"
notify:
- Restart NTP service in RedHat OS
handlers:
- name: Restart NTP service in RedHat OS
service:
name: ntpd
state: restarted
when: ansible_os_family == "RedHat"
- name: Restart NTP service in Debian OS
service:
name: ntp
state: restarted
when: ansible_os_family == "Debian"
We can syntax check our playbook with the below command.
ansible-playbook ntp_playbook.yml --syntax-check
Let’s run the playbook
Here we can see that as we have not changed anything inside the RedHat and Debian NTP configuration files, our handlers didn’t execute.
Now let’s try to add some dummy values inside the RedHat(ntp_redhat.conf) configuration files and see if our handlers get executed or not.
Now ansible knows that the source NTP configuration files and the destination NTP configuration files are different so will execute the tasks and will notify the handlers.
We can clearly see that handlers get executed for the redhat OS and not for debian system.
Handlers are lists of tasks, not really any different from regular tasks, that are referenced by a globally unique name, and are notified by notifiers. If nothing notifies a handler, it will not run. Regardless of how many tasks notify a handler, it will run only once, after all of the tasks complete in a particular play.
IMPORTANT NOTE
Handlers gets executed in the end of the playbook, so if you want to execute some task immediately as soon as the configuration gets changes then handlers won’t help and that can be handled via Conditions.