HomeBlogUpdating Structured Data in Ansible & Jinja
Updating a list or dictionary within python is a trivial manner, however within Ansible and Jinja, it is not as easy or well defined. The user must understand the scoping limitations, and how to navigate through them, in addition to the syntax, which is not always obvious.
This data was captured from an ntc-template, and the current structure does not fit in with X internal integration point, or preferred output.
Here we will demonstrate several ways to iterate over the list for your preferred output.
Creating a list of MAC addresses
There is no scoping issues here, but it’s important to keep in mind two things.
The variable has to be initialized as a list already.
You do not want to over write the data each time, and adding + one list to another is the same as extend in python.
-name:"100 - SET FACT TO NORMALIZE DATA"set_fact:mac_table_normalized:"{{ mac_table_normalized | default([]) }} + [ '{{ item.destination_address }}' ]"loop:"{{ show_mac_address_table }}"
Breakdown:
mac_table_normalized | default([]) – If mac_table_normalized is not set, default it to an empty list.
` + [ ` – Add current variable (ensured to be a list), to this new list of one item.
'{{ item["destination_address"] }}' – Working with a single list item entry, which is a dictionary in this case, obtain the value from destination_address key, and add it as the item into mac_table_normalized list.
loop: "{{ show_mac_address_table }}" Iterate over each element in the list, and assign it the local variable of item.
This produces a concise list of mac addresses now accessible within the playbook. Similarly, within Jinja, you could do the following.
-name:"101 - SET FACT TO NORMALIZE DATA IN JINJA"set_fact:mac_table_normalized:"{{ lookup('template', 'template1.j2') }}"
There are two primary things to consider here. First to initialize the list with {% set mac_table_normalized = []. Second, when you append to the list you can safely ignore the value assigned, but because of Jinja’s syntax, you still must use a set method, as it will create empty lines using standard {{ }} syntax. Assigning it to underscore, indicates to the reader of the code, that it is no longer needed after the current scope.
Another syntax that ends in the same result, often seen is.
-name:"102 - SET FACT TO NORMALIZE DATA IN JINJA"set_fact:mac_table_normalized:"{{ lookup('template', 'template2.j2') }}"
Transposing a list of dictionaries, to a preferred list of dictionaries
Still using the same data, you now want to format it, in a way that is preferable to an API you will call in a later step. So the API is expecting 4 key/value pairs: [device, vlan, mac, interface].
-name:"111 - SET FACT TO NORMALIZE DATA"set_fact:mac_table_normalized:"{{ lookup('template', 'template4.j2') }}"loop:"{{ show_mac_address_table }}"
Conclusion
The syntax is not obvious, and there are actually several different ways to accomplish the same thing. If you end up with something that is simpler, would love to hear about it in in the comments.
We have only covered a few of the most common data translations, and you can see how complex they can become. At some point, it will likely make sense to break out into python, with a custom filter or module. However, in a pinch, it’s good to know what is available to use.
You can follow along with all of the examples by reviewing this gist.
Does this all sound amazing? Want to know more about how Network to Code can help you do this, reach out to our sales team. If you want to help make this a reality for our clients, check out our careers page.