Home > Articles

This chapter is from the book

This chapter is from the book

Using Jinja2 Templates

A template is a configuration file that contains variables and, based on the variables, is generated on the managed hosts according to host-specific requirements. Using templates allows for a structural way to generate configuration files, which is much more powerful than changing specific lines from specific files. Ansible uses Jinja2 to generate templates.

Working with Simple Templates

Jinja2 is a generic templating language for Python developers. It is used in Ansible templates, but Jinja2-based approaches are also found in other parts of Ansible. For instance, the way variables are referred to is based on Jinja2.

In a Jinja2 template, three elements can be used. Table 8-4 provides an overview.

key_topic_icon.jpg

Table 8-4 Jinja2 Template Elements

Element

Example

data

sample text

comment

{# sample text #}

variable

{{ ansible_facts['default_ipv4']['address'] }}

expression

{% for myhost in groups['web'] %}

{{ myhost }}

{% endfor %}

To work with a template, you must create a template file, written in Jinja2. Next, this template file must be included in an Ansible playbook that uses the template module. Listing 8-13 shows what a template file might look like, and Listing 8-14 shows an example of a playbook that calls the template.

Listing 8-13 Sample Template

# {{ ansible_managed }}

<VirtualHost *:80>
        ServerAdmin webmaster@{{ ansible_facts['fqdn'] }}
        ServerName {{ ansible_facts['fqdn'] }}
        ErrorLog logs/{{ ansible_facts['hostname'] }}-error.log
        CustomLog       logs/{{ ansible_facts['hostname'] }}-common.
log common
        DocumentRoot /var/www/vhosts/{{ ansible_facts['hostname'] }}/

        <Directory /var/www/vhosts/{{ ansible_facts['hostname'] }}>
                Options +Indexes +FollowSymlinks +Includes
                Order allow,deny
                Allow from all
        </Directory>
</VirtualHost>

The sample template in Listing 8-13 starts with # {{ ansible_managed }}. This string is commonly used to identify that a file is managed by Ansible so that administrators are not going to change file contents by accident. While processing the template, this string is replaced with the value of the ansible_managed variable. This variable can be set in ansible.cfg. For instance, you can use ansible_managed = This file is managed by Ansible to substitute the variable with its value while generating the template.

As for the remainder, the template file is just a text file that uses variables to substitute specific variables to their values. In this case that is just the ansible_fqdn and ansible_hostname variables that are set as Ansible facts. To generate the template, you need a playbook that uses the template module to call the template. Listing 8-14 shows an example.

Listing 8-14 Sample Playbook

---
- name: installing a template file
  hosts: ansible1
  tasks:
  - name: install http
    yum:
      name: httpd
      state: latest
  - name: start and enable httpd
    service:
      name: httpd
      state: started
      enabled: true
  - name: install vhost config file
    template:
      src: listing813.j2
      dest: /etc/httpd/conf.d/vhost.conf
      owner: root
      group: root
      mode: 0644
  - name: restart httpd
    service:
      name: httpd
      state: restarted

In the sample playbook in Listing 8-14, the template module is used to work on the source file specified as src, to generate the destination file, specified as dest. The result is that on the managed host the template is generated, with all the variables substituted to their values.

Applying Control Structures in Jinja2 Using for

In templates, control structures can be used to dynamically generate contents. A for statement can be used to iterate over all elements that exist as the value of a variable. Let’s look at some examples.

To start with, Listing 8-15 shows a template where a for statement is shown.

Listing 8-15 Exploring Jinja2 for Statements

{% for node in groups['all'] %}
host_port={{ node }}:8080
{% endfor %}

In this Jinja2 file, a variable with the name host_ports is defined on the second line (which is the line that will be written to the target file). To produce its value, the host group all is processed in the for statement on the first line. While processing the host group, a temporary variable with the name node is defined. This value of the node variable is replaced with the name of the host while it is processed, and after the host name, the string :8080 is copied, which will result in a separate line for each host that was found. As the last element, {% endfor %} is used to close the for loop. In Listing 8-16 you can see an example of a playbook that runs this template.

Listing 8-16 Generating a Template with a Conditional Statement

---
- name: generate host list
  hosts: ansible2
  tasks:
  - name: template loop
    template:
      src: listing815.j2
      dest: /tmp/hostports.txt

As you can see, the sample playbook in Listing 8-16 uses the template as the source file and, based on the template, produces the file /tmp/hostports.txt on the managed host. To verify, you can use the ad hoc command ansible ansible2 -a "cat /tmp/hostports.txt".

Using Conditional Statements with if

The for statement can be used in templates to iterate over a series of values. The if statement can be used to include text only if a variable contains a specific value or evaluates to a Boolean true. Listing 8-17 shows a sample template file that reacts on a variable that is set in the sample playbook in Listing 8-18.

Listing 8-17 Template Example with if

{% if apache_package == 'apache2' %}
  Welcome to Apache2
{% else %}
  Welcome to httpd
{% endif %}

Listing 8-18 Using the Template with if

---
- name: work with template file
  vars:
    apache_package: 'httpd'
  hosts: ansible2
  tasks:
  - template:
      src: listing817.j2
      dest: /tmp/httpd.conf

Using Filters

In Jinja2 templates, you can use filters. Filters are a way to perform an operation on the value of a template expression, such as a variable. The filter is included in the variable definition itself, and the result of the variable and its filter is used in the file that is generated. Table 8-5 gives an overview of some common filters. In Exercise 8-3 you practice your skills and work with templates that use a conditional statement.

Table 8-5 Common Filters Overview

Filter Example

Use

{{ myvar | to_json}}

Writes the contents of myvar in JSON format

{{ myvar || to_yaml }}

Writes the contents of myvar in YAML format

{{ myvar | ipaddr }}

Tests whether myvar contains an IP address

Pearson IT Certification Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from Pearson IT Certification and its family of brands. I can unsubscribe at any time.