Use pre_tasks and post_tasks sections to control whether tasks run before or after roles, and listen directives to notify multiple handlers at the same time.
Outcomes
Control the execution order of tasks.
Trigger handlers using the listen directive.
As the student user on the workstation machine, use the lab command to prepare your system for this exercise.
This command creates an Ansible project in the /home/student/task-execution/ directory.
[student@workstation ~]$ lab start task-execution
Procedure 6.2. Instructions
From a terminal, change to the /home/student/task-execution/ directory and review the deploy.yml playbook.
[student@workstation ~]$cd ~/task-execution[student@workstation task-execution]$cat deploy.yml--- - name: Implementing Handlers hosts: web_servers pre_tasks: - name: Configuring Apache ansible.builtin.include_tasks: apache.yml roles: - role: firewall
The deploy.yml playbook consists of one play.
This play uses a pre_tasks section to include tasks that configure an Apache HTTPD web server, and then a roles section to run a role that allows access through the firewall.
Edit the deploy.yml playbook to add tasks that notify handlers.
Use the ansible.builtin.set_fact module to assign the static values 80/tcp for the web_port variable and public for the web_zone variable.
Use changed_when: true to guarantee that the task always notifies the display variables handler.
The content for the pre_tasks section should read as follows:
pre_tasks:
- name: Configuring Apache
ansible.builtin.include_tasks: apache.yml
- name: Setting web port and zone for firewall
ansible.builtin.set_fact:
web_port: 80/tcp
web_zone: public
changed_when: true
notify: display variablesAfter the roles section, add the post_tasks section with a task to copy the index.html file to the /var/www/html directory.
Use the ansible.builtin.copy module to copy the file.
Notify the verify connectivity handler if the task changes the managed host.
The content for the post_tasks section should read as follows:
roles:
- role: firewall
post_tasks:
- name: Ensure the web content is copied
ansible.builtin.copy:
src: index.html
dest: /var/www/html/
notify: verify connectivityYou could define the Ensure the web content is copied task under a tasks section because Ansible also runs the tasks section after the roles.
However, to mirror the pre_tasks section, define the task under the post_tasks section.
Add the handlers for the play.
Two handlers must listen for the display variables notification in order to show the values for the web_port and the web_zone variables when they are defined.
The same notification must trigger both handlers.
In addition, add a handler named verify connectivity that verifies that the web content at http://{{ ansible_facts['fqdn'] }} can be retrieved at the end of the first play if the play changed the content.
This confirms that the play worked.
Make sure that you create this handlers section in the deploy.yml playbook at the end of the play.
Create the handlers section at the end of the play, and include two similar handlers using the ansible.builtin.debug module to print the value of the web_port and the web_zone variables.
Give them an arbitrary string as a name, and use the listen directive for the display variables notification.
The handlers section is highlighted and should consist of the following content:
post_tasks:
- name: Ensure the web content is copied
ansible.builtin.copy:
src: index.html
dest: /var/www/html/
notify: verify connectivity
handlers:
- name: Showing the web port configured as pre_task
ansible.builtin.debug:
var: web_port
listen: display variables
- name: Showing the web zone configured as pre_task
ansible.builtin.debug:
var: web_zone
listen: display variablesAdd the handler for the verify connectivity notification.
Use the ansible.builtin.uri module to verify that the web content is available.
handlers:
- name: Showing the web port configured as pre_task
ansible.builtin.debug:
var: web_port
listen: display variables
- name: Showing the web zone configured as pre_task
ansible.builtin.debug:
var: web_zone
listen: display variables
- name: verify connectivity
ansible.builtin.uri:
url: http://{{ ansible_facts['fqdn'] }}
status_code: 200
become: falseThe complete deploy.yml file should consist of the following content:
---
- name: Implementing Handlers
hosts: web_servers
pre_tasks:
- name: Configuring Apache
ansible.builtin.include_tasks: apache.yml
- name: Setting web port and zone for firewall
ansible.builtin.set_fact:
web_port: 80/tcp
web_zone: public
changed_when: true
notify: display variables
roles:
- role: firewall
post_tasks:
- name: Ensure the web content is copied
ansible.builtin.copy:
src: index.html
dest: /var/www/html/
notify: verify connectivity
handlers:
- name: Showing the web port configured as pre_task
ansible.builtin.debug:
var: web_port
listen: display variables
- name: Showing the web zone configured as pre_task
ansible.builtin.debug:
var: web_zone
listen: display variables
- name: verify connectivity
ansible.builtin.uri:
url: http://{{ ansible_facts['fqdn'] }}
status_code: 200
become: falseRun the deploy.yml Ansible Playbook to verify your work and confirm that Ansible triggers your handlers.
Pay attention to the order of execution of the handlers.
In particular, you should see that the handlers subscribed to display variables called in the pre_tasks section run before the verify connectivity handler called in the post_tasks section.
Run the deploy.yml playbook.
[student@workstation task-execution]$ansible-navigator run \>-m stdout deploy.ymlPLAY [Implementing Handlers] *************************************************** TASK [Gathering Facts] ********************************************************* ok: [serverf.lab.example.com] TASK [Configuring Apache] ****************************************************** included: /home/student/task-execution/apache.yml for serverf.lab.example.com TASK [Installing apache] ******************************************************* changed: [serverf.lab.example.com] TASK [Starting apache] ********************************************************* changed: [serverf.lab.example.com] TASK [Setting web port and zone for firewall] ********************************** changed: [serverf.lab.example.com] RUNNING HANDLER [Showing the web port configured as pre_task] ****************** ok: [serverf.lab.example.com] => { "web_port": "80/tcp" } RUNNING HANDLER [Showing the web zone configured as pre_task] ****************** ok: [serverf.lab.example.com] => { "web_zone": "public" } TASK [firewall : Ensure Firewall Port Configuration] *************************** changed: [serverf.lab.example.com] => (item={'port': '80/tcp', 'zone': 'public'}) RUNNING HANDLER [firewall : reload firewalld] ********************************** changed: [serverf.lab.example.com] TASK [Ensure the web content is copied] **************************************** changed: [serverf.lab.example.com] RUNNING HANDLER [verify connectivity] ************************************************* ok: [serverf.lab.example.com] PLAY RECAP ********************************************************************* serverf.lab.example.com : ok=11 changed=6 unreachable=0 failed=0 ...
Use the curl command to verify that the playbook successfully updated the host:
[student@workstation task-execution]$ curl serverf.lab.example.com
This is the index fileUpdate two tasks in the revert.yml playbook to notify handlers and add a new handler to the playbook.
Add a notify: package check statement to the Uninstall apache task.
Add a notify: post handler statement to the Removing index.html file task.
After you modify the revert.yml file, the content for the playbook should read as follows:
...output omitted... tasks: - name: Uninstall apache ansible.builtin.yum: name: httpd state: absent autoremove: truenotify: package checkpost_tasks: - name: Removing index.html file ansible.builtin.file: path: /var/www/html/index.html state: absentnotify: post handler...output omitted...
In the revert.yml playbook, create a handler called post handler that uses the ansible.builtin.debug module to print The index.html file was deleted to stdout.
The complete revert.yml file should consist of the following content:
---
- name: Cleaning Firewall rules
hosts: web_servers
roles:
- role: firewall
vars:
firewall_rules:
- port: 80/tcp
zone: public
state: disabled
tasks:
- name: Uninstall apache
ansible.builtin.yum:
name: httpd
state: absent
autoremove: true
notify: package check
post_tasks:
- name: Removing index.html file
ansible.builtin.file:
path: /var/www/html/index.html
state: absent
notify: post handler
handlers:
- name: Gather package facts
ansible.builtin.package_facts:
manager: auto
listen: package check
- name: Check for the httpd package
ansible.builtin.debug:
msg: "httpd is not installed!"
when: "'httpd' not in ansible_facts['packages']"
listen: package check
- name: post handler
ansible.builtin.debug:
msg: The index.html file was deletedRun the revert.yml Ansible Playbook to verify your work and confirm that Ansible triggers your handlers.
Pay attention to the order of execution of the handlers.
Run the revert.yml playbook.
[student@workstation task-execution]$ansible-navigator run \>-m stdout revert.ymlPLAY [Cleaning Firewall rules] ************************************************* TASK [Gathering Facts] ********************************************************* ok: [serverf.lab.example.com] TASK [firewall : Ensure Firewall Port Configuration] *************************** changed: [serverf.lab.example.com] => (item={'port': '80/tcp', 'zone': 'public', 'state': 'disabled'}) TASK [Uninstall apache] ******************************************************** changed: [serverf.lab.example.com] RUNNING HANDLER [firewall : reload firewalld] ********************************** changed: [serverf.lab.example.com] RUNNING HANDLER [Gather package facts] ***************************************** ok: [serverf.lab.example.com] RUNNING HANDLER [Check for the httpd package] ********************************** ok: [serverf.lab.example.com] => { "msg": "httpd is not installed!" } TASK [Removing index.html file] ************************************************ changed: [serverf.lab.example.com] RUNNING HANDLER [post handler] ************************************************* ok: [serverf.lab.example.com] => { "msg": "The index.html file was deleted" } PLAY RECAP ********************************************************************* serverf.lab.example.com : ok=9 changed=4 unreachable=0 failed=0 ...
Use the curl command to verify that the playbook successfully updated the host:
[student@workstation task-execution]$ curl serverf.lab.example.com
curl: (7) Failed to connect to serverf.lab.example.com port 80: No route to host