How can I test jinja2 templates in ansible?
Asked Answered
Y

5

84

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
Yam answered 15/2, 2016 at 11:10 Comment(0)
Y
115

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.

Yam answered 15/2, 2016 at 11:10 Comment(7)
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.Koval
@AutomatedMike, my answer–which seems to have been stolen with attribution above–fails with missing vars as you'd expectPetrillo
@Yam please remove "Jinja2test.tk"— unfortunately the domain seems to have been taken over by spammy types, and there's no online test there.Simitar
There is also this online service: ansible.sivel.net/test with source here: github.com/sivel/ansible-template-uiAscus
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.Acanthous
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!Parbuckle
thanks, option 3) worked great for me; option 1 does not work if you want to use Ansible community plugins like json_query or something.Carpel
P
52

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"]}'
Petrillo answered 16/1, 2017 at 18:35 Comment(2)
I added your answer to list.Yam
I appreciate ansible-native way, also allows you to use ansible filters, too.Insurgence
K
17

You can use the debug module

tasks: 
- name: show templating results
  debug:
   msg: "{{ lookup('template', 'template-test.j2') }}"
Kief answered 27/1, 2020 at 13:42 Comment(1)
Do you know if it's possible to print it pretty (with new lines)?Singlebreasted
P
9

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

Phenix answered 21/5, 2020 at 10:51 Comment(0)
L
3

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"
Limicoline answered 22/6, 2021 at 7:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.