file_from_template_jinja2

Build a file from a jinja2 template.

⚙️ Compatible targets: Linux

Parameters

NameDocumentation
source_templateSource file containing a template to be expanded (absolute path on the target node).

This parameter is required.
pathDestination file (absolute path on the target node).

This parameter is required.

Outcome conditions

You need to replace ${path} with its actual canonified value.

  • ✅ Ok: file_from_template_${path}_ok
    • ☑️ Already compliant: file_from_template_${path}_kept
    • 🟨 Repaired: file_from_template_${path}_repaired
  • ❌ Error: file_from_template_${path}_error

Example

method: file_from_template_jinja2
params:
  source_template: VALUE
  path: VALUE

Documentation

See file_from_template_type for general documentation about templates usage.

This generic method will build a file from a jinja2 template using data (conditions and variables) found in the execution context.

Setup

It requires to have the jinja2 python module installed on the node, it can usually be done in ncf with package_present("python-jinja2", "", "", "").

WARNING: If you are using a jinja2 version older than 2.7 trailing newlines will not be preserved in the destination file.

Syntax

Jinja2 is a powerful templating language, running in Python. The Jinja2 syntax reference documentation is http://jinja.pocoo.org/docs/dev/templates/ which will likely be useful, as Jinja2 is very rich and allows a lot more that what is explained here.

This section presents some simple cases that cover what can be done with mustache templating, and the way the agent data is provided to the templating engine.

The main specificity of jinja2 templating is the use of two root containers:

  • classes to access currently defined conditions
  • vars to access all currently defined variables

Note: You can add comments in the template, that will not be rendered in the output file with {# ... #}.

You can extend the Jinja2 templating engine by adding custom FILTERS and TESTS in the script /var/rudder/configuration-repository/ncf/10_ncf_internals/modules/extensions/jinja2_custom.py

For instance, to add a filter to uppercase a string and a test if a number is odd, you can create the file /var/rudder/configuration-repository/ncf/10_ncf_internals/modules/extensions/jinja2_custom.py on your Rudder server with the following content:

def uppercase(input):
    return input.upper()

def odd(value):
    return True if (value % 2) else False

FILTERS = {'uppercase': uppercase}
TESTS = {'odd': odd}

These filters and tests will be usable in your jinja2 templates automatically.

Conditions

To display content based on conditions definition:

{% if classes.my_condition is defined  %}
   display this if defined
{% endif %}
{% if not classes.my_condition is defined %}
   display this if not defined
{% endif %}

Note: You cannot use condition expressions here.

You can also use other tests, for example other built-in ones or those defined in jinja2_custom.py:

{% if vars.variable_prefix.my_number is odd  %}
   display if my_number is odd
{% endif %}
Scalar variables

Here is how to display a scalar variable value (integer, string, ...), if you have defined variable_string("variable_prefix", "my_variable", "my_value"):

{{ vars.variable_prefix.my_variable }}

You can also modify what is displayed by using filters. The built-in filters can be extended in jinja2_custom.py:

{{ vars.variable_prefix.my_variable | uppercase }}

Will display the variable in uppercase.

Iteration

To iterate over a list, for example defined with:

variable_iterator("variable_prefix", "iterator_name", "a,b,c", ",")

Use the following file:

{% for item in vars.variable_prefix.iterator_name %}
{{ item }} is the current iterator_name value
{% endfor %}

Which will be expanded as:

a is the current iterator_name value
b is the current iterator_name value
c is the current iterator_name value

To iterate over a container defined by the following json file, loaded with variable_dict_from_file("variable_prefix", "dict_name", "path"):

{
   "hosts": [
       "host1",
       "host2"
   ],
   "files": [
       {"name": "file1", "path": "/path1", "users": [ "user1", "user11" ] },
       {"name": "file2", "path": "/path2", "users": [ "user2" ] }
   ],
   "properties": {
       "prop1": "value1",
       "prop2": "value2"
   }
}

Use the following template:

{% for item in vars.variable_prefix.dict_name.hosts %}
{{ item }} is the current hosts value
{% endfor %}

# will display the name and path of the current file
{% for file in vars.variable_prefix.dict_name.files %}
{{ file.name }}: {{ file.path }}
{% endfor %}

# will display the users list of each file
{% for file in vars.variable_prefix.dict_name.files %}
{{ file.name }}: {{ file.users|join(' ') }}
{% endfor %}


# will display the current properties key/value pair
{% for key, value in vars.variable_prefix.dict_name.properties.items() %}
{{ key }} -> {{ value }}
{% endfor %}

Which will be expanded as:

host1 is the current hosts value
host2 is the current hosts value

# will display the name and path of the current file
file1: /path1
file2: /path2

# will display the users list of each file
file1: user1 user11
file2: user2

# will display the current properties key/value pair
prop1 -> value1
prop2 -> value2
System variables

Some sys dict variables (like sys.ipv4) are also accessible as string, for example:

  • ${sys.ipv4} gives 54.32.12.4
  • $[sys.ipv4[ethO]} gives 54.32.12.4
  • $[sys.ipv4[eth1]} gives 10.45.3.2

These variables are not accessible as dict in the templating data, but are represented as string:

  • ipv4 is a string variable in the sys dict with value 54.32.12.4
  • ipv4[ethO] is a string variable in the sys dict with value 54.32.12.4
  • ipv4 is not accessible as a dict in the template

To access these value, use the following syntax in your jinja2 templates:

vars.sys['ipv4[eth0]']