Jinja2 template with nested loops

OK: what’s this about?

I have defined various hosts in my inventory. Among other things, the hosts in the IDMZ zone each have an array with a different number of alias definitions.

The host vml010110 has the following array:

host_cnames:
  - name:           "host_alias"
    cname:           '{{ host_alias }}'
  - name:           "Firewall C"
    cname:           'fwc'
  - name:           "Time-Server"
    cname:           'time'
  - name:           "DHCP-Server"
    cname:           'dhcp'
  - name:           "DNS-Server"
    cname:           'dns'

The host vml010200, on the other hand, looks like this:

host_cnames:
  - name:           "host_alias"
    cname:           '{{ host_alias }}'
  - name:           "Build-Maschine"
    cname:           'build'

In my jinja2 looks like:

{% for host in groups['idmz'] %}    
{{'{:31}'.format(host) }} has IPv4:   {{ hostvars[host]['host_ipv4'] }}
                                has IPv6:   {{ hostvars[host]['host_ipv6'] }}
{% for item in host_cnames %}       
{{ '%-31s' % (item.cname) }} belongs to: {{ host }}
{% endfor %}                        


{% endfor %} 

Unfortunately, this gives me the following result:

vml010110                       has IPv4:   10.0.10.110
                                has IPv6:   fd00::3:10:0:10:110
fwi-arch                        belongs to: vml010110
fwc                             belongs to: vml010110
time                            belongs to: vml010110
dhcp                            belongs to: vml010110
dns                             belongs to: vml010110
 
 
vml010200                       has IPv4:   10.0.10.200
                                has IPv6    fd00::3:10:0:10:200
fwi-arch                        belongs to: vml010200
fwc                             belongs to: vml010200
time                            belongs to: vml010200
dhcp                            belongs to: vml010200
dns                             belongs to: vml010200

On the second host, vml010200, the array from host vml010110 is therefore attracted. However, I would like to produce the following result:

vml010110                       has IPv4:   10.0.10.110
                                has IPv6:   fd00::3:10:0:10:110
fwi-arch                        belongs to: vml010110
fwc                             belongs to: vml010110
time                            belongs to: vml010110
dhcp                            belongs to: vml010110
dns                             belongs to: vml010110
 
 
vml010200                       has IPv6:   10.0.10.200
                                has IPv4    fd00::3:10:0:10:200
build-arch                      belongs to: vml010200
build                           belongs to: vml010200

I’ve already spent hours on this, reading how2’s and trying to understand. One thing I already know is that I have to link my second “inner” for item loop with the first “outer” for item loop. But how? I’m sure it’s relatively easy, but my problem is probably stuck between my ears again. :thinking:

1 Like

Yeahhhhhhhhhhhhhh … :smiling_face_with_sunglasses:

I fixed it!

{% for host in groups['idmz'] %}    
{{'{:31}'.format(host) }} has IPv4:   {{ hostvars[host]['host_ipv4'] }}
                                has IPv6:   {{ hostvars[host]['host_ipv6'] }}
{% for item in hostvars[host]['host_cnames'] %}       
{{ '%-31s' % (item.cname) }} belongs to: {{ host }}
{% endfor %}                        


{% endfor %} 

Now it works! :+1:

1 Like

I stared at your fix for a while before I spotted the difference.
For the benefit of anybody else casually reading along…

The inner for loop before the fix was (with spaces added for easier comparison)
{% for item in host_cnames %}
The fix was to change this to
{% for item in hostvars[host]['host_cnames'] %}
That is, to loop over the host_cnames relevant to the outer loop’s host rather than to the current play host.

Even thinking it was probably something like that, it still took me several passes to spot the difference.

Glad you got it working, @Django .

2 Likes