Page
Advanced Ansible Playbook features
Now that we’ve covered some of the fundamentals of writing playbooks, let’s explore more advanced topics, including handlers, conditional statements, and more.
In this lesson, you will:
- Learn about Jinja2 templates in Ansible.
- Learn about using handlers in playbooks.
Jinja2 templates in Ansible
Ansible uses Jinja2 templating to dynamically use variables, expressions, and control structures to customize files, playbook execution, and more based on specific conditions. You can use Jinja2 templates to:
- Substitute variable placeholders ({{ }}) with the actual values.
- Modify variables or include logic in configuration files.
- Dynamically change configurations based on conditions.
- Loop over items for a specific task.
Ansible, by default, looks for template files in the templates directory, which is in the playbooks directory:
project-name/
├── site.yml # Playbook site.yml'
└── templates/ # Jinja2 templates folder
│ ├── index.html.j2 # index.html.j2 template
Template folder structure example.
Code | Definition |
| This is the playbook. |
| Jinja2 template file. Using the |
Let’s use Jinja2 templating to deploy a custom index.html
file to the Apache web server. First, we’ll create the index.html.j2
template in the templates folder:
# templates/index.html.j2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ansible rocks!</title>
</head>
<body>
<h1>Server information</h1>
<p>This page is served from {{ ansible_hostname }}</p>
<p>Server IP: {{ ansible_default_ipv4.address }}</p>
</body>
</html>
Jinja2 template file example.
Code | Definition |
{{ ansible_hostname }} | The ansible_hostname Ansible fact is a built-in variable that returns the managed node’s IP address or hostname. |
{{ ansible_default_ipv4.address }} | The ansible_default_ipv4.address Ansible fact returns the default IPv4 address of the managed node. |
These variables will be substituted with values once the template is deployed to the remote node using the ansible.builtin.template module.
---
- name: Install and start Apache
hosts: web
become: true
tasks:
- name: Ensure the httpd package is installed
ansible.builtin.package:
name: httpd
state: present
- name: Deploy custom index.html
ansible.builtin.template:
src: index.html.j2
dest: /var/www/html/index.html
mode: "0644"
- name: Start the httpd service if needed
ansible.builtin.service:
name: httpd
state: started
enabled: true
Ansible playbook Jinja2 template file example.
Code | Definition |
| This task uses the ansible.builtin.template module to copy the |
| The name of the source template stored in the |
| The destination path for the template. |
Running this playbook would create a new index.html file with the following example content on the remote node:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ansible rocks!</title>
</head>
<body>
<h1>Server information</h1>
<p>This page is served from web2.example.com</p>
<p>Server IP: 192.168.0.11</p>
</body>
</html>
Example index.html output.
Your turn
Experiment with the examples provided and update the index.html.j2 template to show the following additional information:
- The current date.
- Operating System distribution name.
- System uptime in seconds.
HINT: Refer to the Ansible facts documentation for help.
Here’s an example of an updated index.html.j2:
# templates/index.html.j2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ansible rocks!</title>
</head>
<body>
<h1>Server information</h1>
<p>This page is served from {{ ansible_hostname }}</p>
<p>Server IP: {{ ansible_default_ipv4.address }}</p>
<p>Current date: {{ ansible_date_time.date }}</p>
<p>Distribution: {{ ansible_distribution }}</p>
<p>Uptime: {{ ansible_uptime_seconds }} seconds</p>
</body>
</html>
Updated index.html.j2.
Using handlers in playbooks
Ansible uses handlers to run tasks only when a change is made on the managed node. Typically, handlers are called after a set of tasks has run, such as restarting a service if a configuration change was made.
Consider the example playbook below that installs the httpd package and updates the index.html Apache configuration file. We’ll create a handler called Restart apache and use the notify keyword to run the task only if changes are made to the file:
---
- name: Install and start Apache
hosts: web
become: true
tasks:
- name: Ensure the httpd package is installed
ansible.builtin.package:
name: httpd
state: present
- name: Start the httpd service if needed
ansible.builtin.service:
name: httpd
state: started
enabled: true
- name: Deploy custom index.html
ansible.builtin.template:
src: index.html.j2
dest: /var/www/html/index.html
mode: "0644"
notify:
- Restart apache
handlers:
- name: Restart apache
ansible.builtin.service:
name: httpd
state: restarted
Ansible playbook handler example.
Code | Definition |
| The |
| The handlers section of the playbook contains the tasks that only run when notified. In this example, the |
Ansible playbook conditionals
Conditionals enable you to control your playbook's execution flow based on variables, remote node states, or any condition Ansible can evaluate. For example, conditionals allow you to execute different playbook tasks or skip tasks based on a previous task's result.
When you add the when statement to a task, you tell Ansible to evaluate whether a conditional statement returns true
or false
. If the test returns true, Ansible will run the task.
Let’s illustrate a conditional statement with an example playbook to check if a website works correctly. If Apache does not return a 200 status (i.e., the website is down), the playbook returns a "Health check failed. Please investigate" message.
---
- name: Install, start Apache and perform a health check
hosts: web
become: true
tasks:
- name: Perform a health check on the website
ansible.builtin.uri:
url: http://35.175.115.51/
return_content: true
register: http_response
ignore_errors: true
- name: Notify if the website is not available
ansible.builtin.debug:
msg: "Health check failed. Please investigate."
when:
- http_response.status is not defined or
http_response.status != 200
Ansible playbook conditional example.
Code | Definition |
| The |
| The |
| The this keyword tells Ansible to evaluate two conditionals and return true if one of the statements (or in the conditional statement) evaluates to true:
|
Well done!
Congratulations on completing this learning path. The below are links to additional resources and next steps. Happy automating!
Additional resources and next steps:
Have feedback on this learning path? Share it with us.