YAML Structures in Jinja2¶
Data structure to use YAML
with JINJA2
templates. YAML
keeps data stored as a map containing keys and values associated to those keys.
Basic¶
Generic key allocation¶
YAML
input data structure
---
time_zone: Europe/Paris
hostname: myDevice
comment: “This device is a fake one”
JINJA2
to consume YAML
data structure
{% if time_zone is defined %}
clock timezone {{ time_zone }};
{% endif %}
Structured key allocation¶
YAML will consider lines prefixed with more spaces than parent key are contained inside it
---
routing_policy:
communities:
myCommunity: 99:1
tenant2: 99:2
Data structure similar to this YAML representation is :
routing_policy = {
"communities": {
"myCommunity": "99:1",
"tenant2": "99:2"
}
}
List Management¶
YAML List¶
Assuming following data structure in YAML
---
ntp_servers:
- 8.8.8.8
- 4.4.4.4
Access data from JINJA2 can be done with the following code:
{% for ntp_server in ntp_servers %}
ntp server {{ ntp_server }};
{% endfor %}
Data structure similar to this YAML representation is :
ntp_servers = ['8.8.8.8', '4.4.4.4']
YAML Dictionary¶
Assuming following data structure in YAML
---
vlans:
10: descr1
20: descr2
30: descr3
Access data from JINJA2 can be done with the following code:
{% for vlan_id, descr in vlans.items() %}
vlan {{ vlan_id }}
description {{ descr }}
{% endfor %}
Data structure similar to this YAML representation is :
vlans = {10: "descr1", 20: "descr2", 30: "descr3"}
YAML Maps¶
Assuming following data structure in YAML
---
interfaces:
- name: "ge-0/0/0"
descr: "Blah"
- name: "ge-0/0/1"
descr: "comment"
Access data from JINJA2 can be done with the following code:
{% for interface in interfaces %}
interface {{interface.name}} {
description {{interface.descr}};
{% endfor %}
Data structure similar to this YAML representation is :
interfaces = [{"name": "ge-0/0/0", "descr": "Blah"},
{"name": "ge-0/0/1", "descr": "comment"}]
Advanced Jinja2 syntax¶
Update variable in a Loop¶
Syntax below allows user to update value of a variable within a loop and access to it after in a different jinja2 block:
{% set ns = namespace (dev_state = "disable") %}
{% for portname, portlist in topo[inventory_hostname].iteritems() %}
{% if portlist.state == "enable" %}
{% set ns.dev_state = "enable" %}
{% endif %}
{% endfor %}
status: {{ns.dev_state|default("enable")}}
Use IPaddr within Jinja2 template¶
Assuming following yaml
definition:
id: 10
underlay:
networks:
loopbacks: 10.0.0.0/16
Jinja gives option to build IP address within loopback
network with following syntax where id
is the idth in the network:
loopback_ip: {{ underlay.networks.loopbacks | ipaddr(id) | ipaddr('address') }}
Another example:
{{ tenant.interconnect_prefix | ipaddr(6)}}
combined with interconnect_prefix: 172.25.10.16/28
resulst in 172.25.10.22
Manage Jinja2 rendering indentation¶
Jinja2 can manage whitespace and tabular indentation with lstrip_blocks
and trim_blocks
options:
trim_blocks
: If this is set toTrue
the first newline after a block is removed (block, not variable tag!). Defaults toFalse
.lstrip_blocks
: If this is set toTrue
leading spaces and tabs are stripped from the start of a line to a block. Defaults toFalse
.
To manage these options, just put this line in your template:
#jinja2: lstrip_blocks: "True (or False)", trim_blocks: "True (or False)"
...
Example
Using this template:
{% for host in groups['webservers'] %}
{% if inventory_hostname in hostvars[host]['ansible_fqdn'] %}
{{ hostvars[host]['ansible_default_ipv4']['address'] }} {{ hostvars[host]['ansible_fqdn'] }} {{ hostvars[host]['inventory_hostname'] }} MYSELF
{% else %}
{{ hostvars[host]['ansible_default_ipv4']['address'] }} {{ hostvars[host]['ansible_fqdn'] }} jcs-server{{ loop.index }} {{ hostvars[host]['inventory_hostname'] }}
{% endif %}
{% endfor %}
lstrip_block=False
Rendering is similar to :
172.16.25.1 spine1
172.16.25.3 spine2
172.16.25.4 spine3
lstrip_block=true
Rendering should be:
172.16.25.1 spine1
172.16.25.3 spine2
172.16.25.4 spine3
Loop management¶
Jinja2 has built-in option to manage loop information:
loop.index
: The current iteration of the loop. (1 indexed)
loop.index0
: The current iteration of the loop. (0 indexed)
loop.revindex
: The number of iterations from the end of the loop (1 indexed)
loop.revindex0
: The number of iterations from the end of the loop (0 indexed)
loop.first
: True if first iteration.
loop.last
: True if last iteration.
loop.length
: The number of items in the sequence.
loop.cycle
: A helper function to cycle between a list of sequences. See the explanation below.
loop.depth
: Indicates how deep in deep in a recursive loop the rendering currently is. Starts at level 1
loop.depth0
: Indicates how deep in deep in a recursive loop the rendering currently is. Starts at level 0