Skip to content
Cloud Kung-Fu

Playbooks, Task Controls & Handlers

4 min read

What is a Playbook?

Ansible playbooks allow you to declare tasks to be performed on remote hosts.

Overview of Playbook Structure:

Playbook analogy. A pic of a cookbook represents the playbook, Each recipe in the cookbook is a play and the steps in the recipe are tasks. Modules are represented by an image of cooking utensils and ingredients.
  1. Play: specifies a group of tasks to be executed on a set of hosts.

  2. Task: an action to be performed on the host.

  3. Module: a piece of code for a specific task.

What is Task Control & Handler?

These are methods of controlling how and when your automation scripts are executed. Task control lets you specify conditions for running tasks while handlers are a form of tasks that you trigger only when changes need to be applied.

Task Control Overview

Task control in Ansible allows you to state the conditions under which your scripts should run. This can be implemented using conditionals such as:


This conditional allows you to execute a task only if it evaluates to true.

Ansible Facts

ansible_facts are variables containing information like network interfaces, operating system, IP addresses, and more, which are gathered from host machines and can be used in conditionals.

Task Handlers Overview

Handlers are tasks set to run only when certain changes occur, such as when a service's configuration file is updated by another task.


The notify directive in a task triggers a handler if the task results in any changes to the host.


The listen  directive allows multiple tasks to notify the same handler even if they use different notify names.


We'll start with two pre-configured inventory files. Inventory-webserver1.yaml contains two hosts while inventory-webserver2.yaml contains one host.

  1. Clone the repo
git clone

2. Spin up the environment using docker-compose

docker compose up -d --build

3. SSH into the Ansible server

ssh -o StrictHostKeyChecking=no -o NoHostAuthenticationForLocalhost=yes root@localhost -p 2200# password: test123

4. Change directory to ansible_learn

cd ansible_learn

Working with Playbooks

5. Create playbook file

touch install_nginx.yaml
nano install_nginx.yaml

6. Add the following config to install nginx

# ansible_learn/install_nginx.yaml
# setting the state param to "present" will ensure that it is installed
- name: Install NGINX Web Server
hosts: webserver1
- name: Install NGINX
name: nginx
state: present

7. Run the linter

ansible-lint install_nginx.yaml

8. Execute the playbook on inventory-webserver1.yaml

ansible-playbook --key-file /root/.ssh/id_rsa_ansible -u root -i inventory-webserver1.yaml install_nginx.yaml

9. Confirm installation on server1 & server2 then check if it's installed on server3

ssh -i /root/.ssh/id_rsa_ansible root@server1 nginx -V
ssh -i /root/.ssh/id_rsa_ansible root@server2 nginx -V
ssh -i /root/.ssh/id_rsa_ansible root@server3 nginx -V

Task Controls & Handlers

We want to create a playbook that installs Apache on servers that do not have a specific file (e.g., /var/www/html/index.nginx-debian.html), and then use a handler to restart Apache if it is newly installed or updated.

10. Create & open the install_nginx.yaml file

touch conditional_install_apache.yaml
nano conditional_install_apache.yaml

11. Add condition to install Apache if /var/www/html/index.nginx-debian.html doesn't exist then add a handler to restart Apache if it is newly installed.

- name: Conditional Install and Restart Apache
hosts: all
- name: Check if NGINX Default Page Exists
path: /var/www/html/index.nginx-debian.html
register: nginx_page
- name: Install Apache
name: apache2
state: present
when: not nginx_page.stat.exists
notify: Restart Apache
- name: Restart Apache
listen: "Restart Apache"
name: apache2
state: restarted
# The stat module checks for the existence of the default NGINX page. The result is registered in nginx_page.
# The installation task uses the when condition to install Apache only if the file does not exist.
# If the installation task runs, it notifies the handler to restart Apache.
# The handler listens for the notification and uses the service module to restart Apache.

12. Run the linter

ansible-lint conditional_install_apache.yaml

13. Execute the playbook on inventory-webserver1.yaml & inventory-webserver2.yaml

# webserver1
ansible-playbook --key-file /root/.ssh/id_rsa_ansible -u root -i inventory-webserver1.yaml conditional_install_apache.yaml
ansible-playbook --key-file /root/.ssh/id_rsa_ansible -u root -i inventory-webserver2.yaml conditional_install_apache.yaml

14. Confirm installation on server3 then check if it's installed on server1 & server2

ssh -i /root/.ssh/id_rsa_ansible root@server1 apache2 -V
ssh -i /root/.ssh/id_rsa_ansible root@server2 apache2 -V
ssh -i /root/.ssh/id_rsa_ansible root@server3 apache2 -V


Awesome effort! We just learned how to define Ansible playbooks and how to control the flow of execution using conditionals. Next, we'll look on variables, gathering facts about host machines and how to manage config files using templates.

© 2024 by Cloud Kung-Fu. All rights reserved.
Theme by LekoArts