Reusable templating in Jinja
Jinja is a powerful template engine, I started learning it recently to implement Ansible based kubernetes operator.
I struggle a lot in initial days, so I though to share my experience with you all.
Here we go. Simplest way to invoke Jinja template from Ansible task is,
- name: create data stores config map
community.kubernetes.k8s:
state: present
definition: "{{ lookup('template', 'templates/datastores-info.j2') }}"
Define your template inside file templates/datastores-info.j2, and resulting yaml will be applied on kubernetes.
Like most of the other scripting languages, Jinja has way to create functions to promote code reusability ( to keep your code DRY), they are called as Macros.
The definition of Macro looks like,
{% macro MacroName(parameter list) %}
Macro Body
{% endmacro %}
For example, this macro takes dictionary and check if it has field enabled and return true or false,
{%- macro isModelEnabled(model) -%}
{%- if model['enabled'] is defined and model['enabled'] -%}
true
{%- else -%}
false
{%- endif -%}
{%- endmacro -%}
Macros can be collected into a file or group them into multiple files as macro libraries.
A macro can call other macros defined in same file or other. If macros is defined in other file then it has to be imported using syntax,
{% import 'roles/<path>/macros.j2' as macroLibrary %}
And to invoke that imported macro use syntax
{{ macroLibrary.macroName() }}
Macro Context
When you include macros from other template file, by default the variable from importing template are not visible to macro block, to make them visible you need to qualify import statement with context as,
{% import 'roles/<path>/macros.j2' as macroLibrary with context %}
Import vs Include
Similar to import
Jinja also has include
statement which renders whole template at the place of include template, which you can use more for including repeating static or dynamic content( like headers or footer),
Import can be used to invoke individual macros more as a function where as include can be used more for content inclusion.
Include’s default behavior is to have context of calling template available to its disposal.