Jinja2 is a powerful templating engine for Python.

Inside LAVA, we use Jinja2 to generate configuration files for every boards that we support.

The configuration is generated from a template that does inherit from a base template.

For instance, for a beaglebone-black called bbb-01, the template inheritance tree is the following:

  • devices/bbb-01.jinja2
  • -> device-types/beaglebone-black.jinja2
  • --> device-types/base-uboot.jinja2
  • ---> device-types/base.jinja2

The first template (devices/bbb-01.jinja) is usually a list of variables with their corresponding values for this specific device.

{% extends 'beaglebone-black.jinja2' %}

{% set usb_uuid = 'usb-SanDisk_Ultra_20060775320F43006019-0:0' %}
{% set connection_command = "telnet localhost 6000" %}
{% set hard_reset_command = "/usr/bin/pduclient --daemon localhost --hostname pdu --command reboot --port 08" %}
{% set power_off_command = "/usr/bin/pduclient --daemon localhost --hostname pdu --command off --port 08" %}
{% set power_on_command = "/usr/bin/pduclient --daemon localhost --hostname pdu --command on --port 08" %}

In the base templates we where using:

host: {{ ssh_host|default(localhost) }}
port: {{ ssh_port|default(22) }}

This is in fact wrong. If the variables ssh_host and ssh_port are not defined, the resulting file will be:

port: 22

The default function in Jinja is expecting:

  • a python object (a string, an int, an array, ...)
  • a template variable name

In this case, localhost is interpreted as an undefined template variable name. Hence the result.

The correct template is:

host: {{ ssh_host|default('localhost') }}
port: {{ ssh_port|default(22) }}

That's a really simple mistake that can remain unnoticed for a long time.