Ansible Playbook: Execute Specific Tasks Based on Task Status
Using Handlers
First, let’s take an example of using Ansible to modify the SSH service configuration file and restart the service. The following Playbook can achieve this functionality:
- name: set sshd conf
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
backrefs: true
regexp: "^#?\\s*PermitRootLogin"
line: PermitRootLogin yes
- name: restart ssh
ansible.builtin.systemd:
name: sshd
state: restarted
enabled: true
In this Playbook, the SSH service is restarted every time it is executed. Although this achieves the desired result, it does not comply with Ansible’s idempotency rules.
To address this issue, Ansible can execute specific tasks when certain tasks are in a <span>changed</span> state. Ansible implements this functionality through the following three fields:
- •
<span>notify</span>: Specifies which tasks trigger specific tasks when in a<span>changed</span>state - •
<span>handlers</span>: Specifies tasks that can be triggered by<span>notify</span> - •
<span>listen</span>: Used to listen for<span>notify</span>
Below is an optimized Playbook:
- name: set sshd conf
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
backrefs: true
regexp: "^#?\\s*PermitRootLogin"
line: PermitRootLogin yes
notify: restart sshd
handlers:
- name: restart ssh
ansible.builtin.systemd:
name: sshd
state: restarted
enabled: true
listen: restart sshd
Here we can see:
- • The Play that sets the SSH configuration file has a
<span>notify</span>entry of<span>restart sshd</span>, indicating that there is a notification for<span>restart sshd</span> - • There is a Play under
<span>handlers</span>to restart the SSHD service - • There is a
<span>listen</span>entry of<span>restart sshd</span>, which corresponds to the previous<span>notify</span>
The functionality implemented by these three fields is that when the SSH configuration file is modified, the SSHD service is restarted. If no modification occurs, the Play to restart the SSHD service will not execute.
[root@study ansible]# ansible-playbook /tmp/test.yml
PLAY [test handlers] **********************************************************************************************************************************************
TASK [set sshd conf] **********************************************************************************************************************************************
ok: [servera]
TASK [restart ssh] ************************************************************************************************************************************************
changed: [servera]
PLAY RECAP ********************************************************************************************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@study ansible]# ansible-playbook test.yml
PLAY [test handlers] **********************************************************************************************************************************************
TASK [set sshd conf] **********************************************************************************************************************************************
ok: [servera]
PLAY RECAP ********************************************************************************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
If there is only one Play that
<span>notify</span>triggers, then<span>listen</span>can be omitted; it is sufficient for the<span>notify</span>content to correspond with the<span>name</span>of the Play in<span>handlers</span>.
If
<span>notify</span>is used in conjunction with<span>loop</span>, when a<span>changed</span>occurs, all triggerable<span>handlers</span>Plays will be executed.https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#notifying-and-loops
When multiple tasks trigger the same
<span>handlers</span>Play, the Play will only execute once.
<span>handlers</span>containing static imports or dynamic imports will behave differently; static imports support notifying the imported Play individually, while dynamic imports will execute all tasks when notified.https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#includes-and-imports-in-handlers
Setting Handlers Task Trigger Timing
By default, <span>handlers</span> Plays will execute only after all <span>tasks</span> have completed. By using <span>meta: flush_handlers</span>, you can make the <span>handlers</span> Play execute earlier:
- name: set sshd conf
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
backrefs: true
regexp: "^#?\\s*PermitRootLogin"
line: PermitRootLogin yes
notify: restart sshd
- name: Flush handlers
meta: flush_handlers
- name: debug
ansible.builtin.debug:
msg: "Hello World!"
handlers:
- name: restart ssh
ansible.builtin.systemd:
name: sshd
state: restarted
enabled: true
listen: restart sshd
In this Playbook, the Play to restart the service will execute before the debug task.
[root@study ansible]# ansible-playbook test.yml
PLAY [test handlers] **********************************************************************************************************************************************
TASK [set sshd conf] **********************************************************************************************************************************************
changed: [servera]
TASK [Flush handlers] *********************************************************************************************************************************************
RUNNING HANDLER [restart ssh] *************************************************************************************************************************************
changed: [servera]
TASK [debug] ******************************************************************************************************************************************************
ok: [servera] => {
"msg": "Hello World!"
}
PLAY RECAP ********************************************************************************************************************************************************
servera : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0