

We can declare variables in
- playbook
- inventory
- commands
Which can be used & Intropolate only in playbook Tasks but not in the files used in playbook.
Solution: Template
Using Template module you can Interpolate vars mentioned in the files used in playbook
Rule for using template Module
- A file must be .j2 ext
- Must use a module call “template”
What is a Template in Ansible?
In Ansible, a template is a file that contains variables and expressions using the Jinja2 templating engine. Templates are used to generate dynamic content, which can be configuration files, scripts, or any other text files. The template files typically have a .j2
extension to denote that they are Jinja2 templates.
Importance of Templates
Templates are important in Ansible for several reasons:
- Dynamic Content Generation: Templates allow you to create files that can change based on the variables and facts available at runtime. This makes your configuration files flexible and adaptable to different environments.
- Reuse and Maintainability: Using templates reduces duplication by enabling you to reuse the same template file across multiple hosts or environments with different values.
- Consistency: Templates help ensure that the generated files are consistent across different deployments, reducing the risk of errors and configuration drift.
Why Use Templates?
Using templates in Ansible is beneficial because it allows you to:
- Automate the creation of configuration files and scripts.
- Dynamically adjust configurations based on the host or environment.
- Simplify and streamline your automation scripts by using variables and loops within templates.
How to Use Templates in Ansible
Basic Usage
1.Create a Template FileCreate a Jinja2 template file with placeholders for variables. For example, nginx.conf.j2
:
server {
listen 80;
server_name {{ server_name }};
location / {
proxy_pass http://{{ proxy_pass }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
2.Use the Template Module in a Playbook
Use the template
module in your playbook to apply the template and generate the final configuration file.
- name: Configure Nginx
hosts: webservers
become: yes
vars:
server_name: example.com
proxy_pass: backend.example.com
tasks:
- name: Deploy Nginx configuration
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
notify:
- Reload Nginx
- name: Ensure Nginx is running
ansible.builtin.service:
name: nginx
state: started
Advanced Usage with Loops and Conditionals
Templates can also include loops and conditionals to create more complex and dynamic content.
1.Template File with Loops and ConditionalsFor example, hosts.j2
:
{% for host in groups['all'] %}
{{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} ansible_user={{ hostvars[host]['ansible_user'] }}
{% endfor %}
2.Playbook Using the Template
- name: Generate /etc/hosts file
hosts: localhost
vars:
ansible_host: "{{ inventory_hostname }}"
ansible_user: "{{ ansible_user_id }}"
tasks:
- name: Create /etc/hosts
ansible.builtin.template:
src: hosts.j2
dest: /etc/hosts
Using Facts in Templates
You can use Ansible facts to dynamically populate templates with information about the hosts.
1.Template File Using FactsFor example, motd.j2
:
Welcome to {{ ansible_facts['hostname'] }}!
Your IP address is {{ ansible_facts['default_ipv4']['address'] }}.
2.Playbook Applying the Template
- name: Generate /etc/motd
hosts: all
tasks:
- name: Create /etc/motd
ansible.builtin.template:
src: motd.j2
dest: /etc/motd
Real-World Example: Configuring an Application
Imagine you are deploying an application that requires a configuration file with environment-specific settings. Using Ansible templates, you can automate the creation of these configuration files.
- Template File for Application Config (
app_config.j2
)
[application]
environment = {{ env }}
debug = {{ debug }}
database_url = {{ database_url }}
[logging]
level = {{ log_level }}
2. Playbook to Deploy Application Configuration
- name: Deploy application configuration
hosts: app_servers
become: yes
vars:
env: production
debug: false
database_url: postgres://user:password@db.example.com/dbname
log_level: INFO
tasks:
- name: Create application configuration
ansible.builtin.template:
src: app_config.j2
dest: /etc/myapp/config.ini
notify:
- Restart application
handlers:
- name: Restart application
ansible.builtin.service:
name: myapp
state: restarted
Templates in Ansible are powerful tools that enable dynamic content generation, flexibility, and maintainability in your automation scripts. By leveraging the Jinja2 templating engine, you can create complex configurations that adapt to different environments and host-specific settings. Understanding how to use templates effectively can greatly enhance your ability to manage configurations and deploy applications consistently and efficiently.
Example Code for Cento/RHEL
---
- name: Update web servers
hosts: web
vars:
myname: "Rajesh Kumar"
tasks:
- name: Install Apache in centos7
ansible.builtin.yum:
name: httpd
state: latest
- name: Copy index.html
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: Template index.html
template:
src: index.html.j2
dest: /var/www/html/index-template.html
- name: Starting a Apache Server
ansible.builtin.service:
name: httpd
state: started
index.html.j2

Project Requirement
- When you Change APACHE STATIC HTML Content -> HTTPD restart is not required
- When you Change APACHE Conf -> HTTPD restart is not required
- HTTP should be run 90
- No restart should be done on STATIC
- Restart must be done at conf changes
---
- name: Update web servers
hosts: web
vars:
myname: "Rajesh Kumar"
httpport: 8090
tasks:
- name: Install Apache in centos7
ansible.builtin.yum:
name: httpd
state: latest
- name: Copy index.html
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: Starting a Apache Server
ansible.builtin.service:
name: httpd
state: started
- name: stopped a Apache Server
ansible.builtin.service:
name: httpd
state: stopped
- name: Template for httpd.conf
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
- name: Starting a Apache Server
ansible.builtin.service:
name: httpd
state: started
Example code for Template for Ubuntu
---
- name: Update web servers
hosts: web
vars:
myname: "Rajesh Kumar"
port: 81
tasks:
- name: Install Apache in Ubuntu
ansible.builtin.apt:
name: apache2
state: latest
- name: Copy index.html
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: stopped a Apache Server
ansible.builtin.service:
name: apache2
state: stopped
- name: Template for httpd.conf
template:
src: ports.conf.j2
dest: /etc/apache2/ports.conf
- name: Starting a Apache Server
ansible.builtin.service:
name: apache2
state: started
Live Practical:
Create temp.yaml file
---
- name: Update web servers
hosts: web
vars:
myname: "Rajesh Kumar"
port: 81
tasks:
- name: Install Apache in Ubuntu
ansible.builtin.apt:
name: apache2
state: latest
- name: Copy index.html
ansible.builtin.copy:
src: /home/jami/index.html
dest: /var/www/html/index.html
- name: stopped a Apache Server
ansible.builtin.service:
name: apache2
state: stopped
- name: Template for httpd.conf
template:
src: /home/jami/ports.conf.j2
dest: /etc/apache2/ports.conf
- name: Starting a Apache Server
ansible.builtin.service:
name: apache2
state: started
move ports.conf from /etc/apache2 to your source directly /home/jami/ports.conf in ACS change port.conf file to port.conf.j2 and change list to Listen {{port}} so it will listen to port 81 instead of 80
cd /etc/apache2
cp ports.conf /root/
cd /root/
vi ports.conf
mv ports.conf ports.conf.j2
vi /home/jami/ports.conf.j2
Listen {{port}}
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
Run the ansible playbook
ansible-playbook -i inventory temp.yaml -u jami -k -b
Now web server listen to 81 instead of 80

Problems
- No change in config file but STOP and START happening
Solution
- Handlers

Handler in Ansible
What are Handlers in Ansible?
Handlers in Ansible are special tasks that are triggered by other tasks using the notify
directive. They are used to perform actions that should occur only if there have been changes to the system, such as restarting a service after a configuration file has been updated. Handlers help ensure that changes are applied only when necessary, making them crucial for efficient and effective configuration management.
Importance of Handlers
- Conditional Execution: Handlers run only when notified, ensuring actions are taken only when needed.
- Efficiency: Reduces unnecessary operations, such as restarting a service when there have been no changes.
- Consistency: Helps maintain a consistent state by ensuring dependent tasks are executed after changes.


How to use handler for above example
Handlers Code Example for Ubuntu
---
- name: Update web servers
hosts: localhost
vars:
myname: "Rajesh Kumar"
port: 81
tasks:
- name: Install Apache in Ubuntu
ansible.builtin.apt:
name: apache2
state: latest
- name: Copy index.html
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: Template for httpd.conf
template:
src: ports.conf.j2
dest: /etc/apache2/ports.conf
notify:
- ReStarting a Apache Server
- name: Starting a Apache Server
ansible.builtin.service:
name: apache2
state: started
handlers:
- name: ReStarting a Apache Server
ansible.builtin.service:
name: apache2
state: restarted
No sopped of server if no changes made to file.

For centros
---
- name: Update web servers
hosts: localhost
vars:
myname: "Rajesh Kumar"
port: 81
tasks:
- name: Install Apache in Ubuntu
ansible.builtin.apt:
name: apache2
state: latest
- name: Copy index.html
ansible.builtin.copy:
src: index.html
dest: /var/www/html/index.html
- name: Template for httpd.conf
template:
src: ports.conf.j2
dest: /etc/apache2/ports.conf
notify:
- ReStarting a Apache Server
- name: Starting a Apache Server
ansible.builtin.service:
name: apache2
state: started
handlers:
- name: ReStarting a Apache Server
ansible.builtin.service:
name: apache2
state: restarted
Basic Usage
- Define a HandlerHandlers are defined in the same way as regular tasks but are listed under the
handlers
section.
handlers:
- name: Restart Apache
ansible.builtin.service:
name: apache2
state: restarted
2.Notify a Handler
Use the notify
keyword in a task to trigger the handler when the task results in a change.
tasks:
- name: Copy new Apache config
ansible.builtin.copy:
src: /path/to/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- Restart Apache
3. Complete Playbook Example
Here’s a complete playbook that demonstrates the use of handlers:
---
- name: Ensure Apache is installed and running
hosts: webservers
become: yes
tasks:
- name: Install Apache
ansible.builtin.yum:
name: httpd
state: present
- name: Copy Apache config
ansible.builtin.copy:
src: /path/to/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- Restart Apache
handlers:
- name: Restart Apache
ansible.builtin.service:
name: httpd
state: restarted
Advanced Usage
- Multiple HandlersYou can define and notify multiple handlers. Handlers will run in the order they are defined.
tasks:
- name: Copy Apache config
ansible.builtin.copy:
src: /path/to/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- Restart Apache
- Send Notification
handlers:
- name: Restart Apache
ansible.builtin.service:
name: httpd
state: restarted
- name: Send Notification
ansible.builtin.command: /usr/local/bin/send_notification
2.Handlers in Different Roles
Handlers can be defined in different roles and notified across roles.
Role 1: Webserver Role
- name: Webserver Configuration
hosts: webservers
roles:
- role: webserver
Role 2: Database Role
- name: Database Configuration
hosts: dbservers
roles:
- role: database
Webserver Role Definition (roles/webserver/tasks/main.yml
)
- name: Install Apache
ansible.builtin.yum:
name: httpd
state: present
- name: Copy Apache config
ansible.builtin.copy:
src: /path/to/httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify:
- Restart Apache
handlers:
- name: Restart Apache
ansible.builtin.service:
name: httpd
state: restarted
3. Running Handlers Only Once
If multiple tasks notify the same handler, the handler will run only once, at the end of the play.
tasks:
- name: Task 1
ansible.builtin.copy:
src: /path/to/file1
dest: /destination/file1
notify:
- Handler
- name: Task 2
ansible.builtin.copy:
src: /path/to/file2
dest: /destination/file2
notify:
- Handler
handlers:
- name: Handler
ansible.builtin.command: /usr/local/bin/handler_script
3.
Using meta: flush_handlers
By default, handlers run at the end of the play. You can force handlers to run at a specific point in your playbook using meta: flush_handlers
.
tasks:
- name: Task 1
ansible.builtin.copy:
src: /path/to/file1
dest: /destination/file1
notify:
- Handler
- name: Flush Handlers
meta: flush_handlers
- name: Task 2
ansible.builtin.copy:
src: /path/to/file2
dest: /destination/file2
Example: Real-World Use Case
Scenario: You have a web server where you need to update the application configuration and restart the application service only if the configuration changes.
- Playbook Definition
---
- name: Deploy application configuration
hosts: app_servers
become: yes
tasks:
- name: Copy application config
ansible.builtin.template:
src: app_config.j2
dest: /etc/myapp/config.ini
notify:
- Restart MyApp
handlers:
- name: Restart MyApp
ansible.builtin.service:
name: myapp
state: restarted
2. Template File (app_config.j2
)
[application]
environment = {{ env }}
debug = {{ debug }}
database_url = {{ database_url }}
3. Running the PlaybookWhen you run the playbook, the handler Restart MyApp
will be triggered only if the configuration file changes, ensuring the application is restarted only when necessary.