How can I test jinja2 templates in ansible?

65,371

Solution 1

At this time exists 4 different variants:

1_Online (using https://cryptic-cliffs-32040.herokuapp.com/)
Based on jinja2-live-parser code.

Example

2_Interactive (using python and library jinja2, PyYaml)

import yaml
from jinja2 import Template
>>> template = Template("""
... {% if users is defined and users %}
... {% for user in users %}{{ user }}
... {% endfor %}
... {% endif %}
... """)
>>> values = yaml.load("""
... ---
... users:
...   - Mike
...   - Smith
...   - Klara
...   - Alex
... """)
>>> print "{}".format(template.render(values))


Mike
Smith
Klara
Alex

3_Ansible (using --check)
Create test playbook jinja2test.yml:

---
- hosts: 127.0.0.1
  tasks:
  - name: Test jinja2template
    template: src=test.j2 dest=test.conf

and run it:

ansible-playbook jinja2test.yml --check --diff --connection=local

sample output:

PLAY [127.0.0.1] **************************************************************

GATHERING FACTS ***************************************************************

ok: [127.0.0.1]

TASK: [Test jinja2template] ***************************************************
--- before: test.conf
+++ after: /Users/user/ansible/test.j2
@@ -0,0 +1,4 @@
+Mike
+Smith
+Klara
+Alex

changed: [127.0.0.1]

PLAY RECAP ********************************************************************
127.0.0.1                  : ok=2    changed=1    unreachable=0    failed=0

4_Ansible (using -m template) thanks for @artburkart

Make a file called test.txt.j2

{% if users is defined and users %}
{% for user in users %}
{{ user }}
{% endfor %}
{% endif %}

Call ansible like so:

ansible all -i "localhost," -c local -m template -a "src=test.txt.j2 dest=./test.txt" --extra-vars='{"users": ["Mike", "Smith", "Klara", "Alex"]}'

It will output a file called test.txt in the current directory, which will contain the output of the evaluated test.txt.j2 template.

I understand this doesn't directly use a vars file, but I think it's the simplest way to test a template without using any external dependencies. Also, I believe there are some differences between what the jinja2 library provides and what ansible provides, so using ansible directly circumvents any discrepancies. When the JSON that is fed to --extra-vars satisfies your needs, you can convert it to YAML and be on your way.

Solution 2

If you have a jinja2 template called test.j2 and a vars file located at group_vars/all.yml, then you can test the template with the following command:

ansible all -i localhost, -c local -m template -a "src=test.j2 dest=./test.txt" --extra-vars=@group_vars/all.yml

It will output a file called test.txt in the current directory, which will contain the output of the evaluated test.j2 template.

I think this is the simplest way to test a template without using any external dependencies. Also, there are differences between what the jinja2 library provides and what ansible provides, so using ansible directly circumvents any discrepancies. It's also possible to test ad-hoc variables without making an additional vars file by using JSON:

ansible all -i "localhost," -c local -m template -a "src=test.j2 dest=./test.txt" --extra-vars='{"users": ["Mike", "Smith", "Klara", "Alex"]}'

Solution 3

You can use the debug module

tasks: 
- name: show templating results
  debug:
   msg: "{{ lookup('template', 'template-test.j2') }}"

Solution 4

Disclaimer - I am the author of this, but I put together JinjaFx (https://github.com/cmason3/jinjafx).

This is a Python based tool that allows you to pass Jinja2 templates with a YAML file for variables. I originally wrote it so it can pass CSV based data to generate group_vars and host_vars for our deployments, but it also allows easy testing of Jinja2 templates - there is an online version at https://jinjafx.io

Solution 5

I needed to verify that the template I had defined gave the right result for the server it was created for. (The template included the hostname as a variable and other per host defined variables.)

Neither of the above methods worked for me. The solution for me was to add

  check_mode: yes
  diff: yes

to the task executing the template command, this got me the difference between the generated file and the file actually on the server without changing the remote file. For me it actually worked better than looking at the whole generated file, since the changes was the interesting part anyway. It needs to log in on the remote machine, so a limited use-case. Example of a complete command:

    - name: diff server.properties
      check_mode: yes
      diff: yes
      ansible.builtin.template:
        src: "src.properties"
        dest: "/opt/kafka/config/server.properties"
Share:
65,371
Alex
Author by

Alex

Updated on July 05, 2022

Comments

  • Alex
    Alex almost 2 years

    Sometimes I need to test some jinja2 templates that I use in my ansible roles. What is the simplest way for doing this?

    For example, I have a template (test.j2):

    {% if users is defined and users %}
    {% for user in users %}{{ user }}
    {% endfor %}
    {% endif %}
    

    and vars (in group_vars/all):

    ---
    users:
      - Mike
      - Smith
      - Klara
      - Alex
    
  • AutomatedMike
    AutomatedMike over 7 years
    None of these seem to have the same behavior regarding missing variables. Missing vars fail in ansible but seem to default to false/empty in the above.
  • Alex
    Alex over 7 years
    I added your answer to list.
  • artburkart
    artburkart over 6 years
    @AutomatedMike, my answer–which seems to have been stolen with attribution above–fails with missing vars as you'd expect
  • mlncn
    mlncn over 5 years
    @Alex please remove "Jinja2test.tk"— unfortunately the domain seems to have been taken over by spammy types, and there's no online test there.
  • Felipe Alvarez
    Felipe Alvarez over 5 years
    I appreciate ansible-native way, also allows you to use ansible filters, too.
  • user228505
    user228505 almost 5 years
    There is also this online service: ansible.sivel.net/test with source here: github.com/sivel/ansible-template-ui
  • gczarnocki
    gczarnocki over 2 years
    Do you know if it's possible to print it pretty (with new lines)?
  • 0xC0000022L
    0xC0000022L over 2 years
    Another answer popped up last year and it looks like it's the "persistent" version of your third method. Still perhaps worthwhile mentioning the option.
  • Pyrocater
    Pyrocater about 2 years
    While the last option above (ansible -m template) doesn't use a vars file as written, you can easily make it do so using @ -- ansible -m template -a "yadda yadda" --extra-vars=@vars_file.yaml Edit: looks like this was covered in the answer below, whoops!