Jinja2 is a powerful templating engine for Python and is supported by Ansible. It is also used to generate any text-based files, such as HTML, CSV, or YAML. We can utilize Jinja2 with Ansible variables in order to generate custom configuration files for network devices. In this recipe, we will outline how to use Jinja2 templates with Ansible.
Using Jinja2 with Ansible
Getting ready
In order to follow along with this recipe, an Ansible inventory file must be present and configured as outlined in the previous recipes.
How to do it...
- Create a new file inside the group_vars directory called network.yml:
$ cat group_vars/network.yml
---
ntp_servers:
- 172.20.1.1
- 172.20.2.1
- Create a new templates directory and create a new ios_basic.j2 file with the following content:
$ cat templates/ios_basic.j2
hostname {{ hostname }}
!
{% for server in ntp_servers %}
ntp {{ server }}
{% endfor %}
!
- Create a new junos_basic.j2 file within the templates directory with the following content:
$ cat templates/junos_basic.j2
set system host-name {{ hostname }}
{% for server in ntp_servers %}
set system ntp server {{ server }}
{% endfor %}
- Create a new playbook called ansible_jinja2.yml with the following content:
---
- name: Generate Cisco config from Jinja2
hosts: localhost
gather_facts: no
tasks:
- name: Create Configs Directory
file: path=configs state=directory
- name: Generate Cisco config from Jinja2
hosts: cisco
gather_facts: no
tasks:
- name: Generate Cisco Basic Config
template:
src: "templates/ios_basic.j2"
dest: "configs/{{inventory_hostname}}.cfg"
delegate_to: localhost
- name: Generate Juniper config from Jinja2
hosts: juniper
gather_facts: no
tasks:
- name: Generate Juniper Basic Config
template:
src: "templates/junos_basic.j2"
dest: "configs/{{inventory_hostname}}.cfg"
delegate_to: localhost
- Run the Ansible playbook as shown here:
$ ansible-playbook -i hosts ansible_jinja2.yml
How it works...
We created the network.yml file in order to group all the variables that will apply to all devices under this group. After that, we create two Jinja2 files, one for Cisco IOS devices, and the other for Juniper devices. Inside each Jinja2 template, we reference the Ansible variables using {{}}. We also use the for loop construct, {% for server in ntp_servers %} , supported by the Jinja2 templating engine in order to loop over the ntp_servers variable (which is a list) to access each item within this list.
Ansible provides the template module that takes two parameters:
- src: This references the Jinja2 template file.
- dest: This specifies the output file that will be generated.
In our case, we use the {{inventory_hostname}} variable in order to make the output configuration file unique for each router in our inventory.
By default, the template modules create the output file on the remotely managed nodes. However, this is not possible in our case since the managed devices are network nodes. Consequently, we use the delegate_to: localhost option in order to run this task locally on the Ansible control machine.
The first play in the playbook creates the configs directory to store the configuration files for the network devices. The second play runs the template module on Cisco devices, and the third play runs the template task on Juniper devices.
The following is the configuration file for one of the Cisco devices:
$ cat configs/csr1.cfg
hostname edge-csr1
!
ntp 172.20.1.1
ntp 172.20.2.1
!
This is the configuration file for one of the Juniper devices:
$ cat configs/mx1.cfg
set system host-name core-mx1
set system ntp server 172.20.1.1
set system ntp server 172.20.2.1
See also...
For more information regarding the Ansible template module, please consult the following URL:
https://docs.ansible.com/ansible/latest/modules/template_module.html