Sunday, August 4, 2019

Simple list vs dictionary in Ansible (and how easily you can mess)

I've been working on a relatively simple task in Ansible, namely create the VRF configuration for a Cisco router.

I would use a 'for' loop in a Jinja2 template and iterate over a variable that holds my VRF parameters.

Now it depends how you have declared your variable, as a list or as a dictionary? There are valid use-cases to use any method, the point is to understand what you're doing and why.. 


List example
router_vrfs:
  - {vrf_name: "VRF1", vrf_rd: 100, vrf_import_rt: "1:100", vrf_export_rt: "1:100"}
  - {vrf_name: "VRF2", vrf_rd: 200, vrf_import_rt: "1:300", vrf_export_rt: "1:200"}
  - {vrf_name: "VRF3", vrf_rd: 200, vrf_import_rt: "1:300", vrf_export_rt: "1:300"}  


Dictionary example
router_vrfs:
  "VRF1": {vrf_rd: 100, vrf_import_rt: "1:100", vrf_export_rt: "1:100"}
  "VRF2": {vrf_rd: 200, vrf_import_rt: "1:300", vrf_export_rt: "1:200"}
  "VRF3": {vrf_rd: 200, vrf_import_rt: "1:300", vrf_export_rt: "1:300"} 

If you have declared a list, it's an indexed list and you can use router_vrfs[0], router_vrfs[1], router_vrfs[2], or you can use a 'for' loop to access one item after the other as per below

{% for data in router_vrfs %}
 vrf context {{ data.vrf_name }}
   rd {{ router_loopback0 }}:{{ data.vrf_rd }}
   address-family ipv4 unicast
    route-target import {{ data.vrf_import_rt }}
    route-target export {{ data.vrf_export_rt }}
{% endfor %}

If you have declared a dictionary, things are a bit more complex. In this case you actually need to define two variables within your loop and use the 'items()' function on the variable. In the following snippet you also see I'm using a 'sort' filter, because dictionaries are unordered by default and you could have different result every time.

{% for name, data in router_vrfs.items()|sort(false,true) %}
 vrf context {{ name }}
   rd {{ router_loopback0 }}:{{ data.vrf_rd }}
   address-family ipv4 unicast
    route-target import {{ data.vrf_import_rt }}
    route-target export {{ data.vrf_export_rt }}
{% endfor %}


And now the messy part..

What would happen if you declare a dictionary and by mistake use dash (-) in the beginning of each line??

Wrong dictionary example
router_vrfs:
  - "VRF1": {vrf_rd: 100, vrf_import_rt: "1:100", vrf_export_rt: "1:100"}
  - "VRF2": {vrf_rd: 200, vrf_import_rt: "1:300", vrf_export_rt: "1:200"}
  - "VRF3": {vrf_rd: 200, vrf_import_rt: "1:300", vrf_export_rt: "1:300"} 

You have just created a simple list, in which each element is a dictionary! 

Each element contains only one key/value pair, but the damage is done. You understand if you try to use any of the above 'for' loop examples nothing will work. Instead you would need to do something like the following, which is just the wrong way of doing things..

{% for dict in router_vrfs %}
  {% for key,value in dict.items() %}


So, beware how you declare variables!

No comments:

Post a Comment