Iterate over a YAML object using Jinja template - yaml

I have a yaml file with the following contents in it
interfaces:
'loopback:local':
-address: 0.0.0.0
prefix: 24
area: 192.168.1.2
grp: testint
intname: global
-address: 0.0.0.0
prefix: 24
area: 192.168.1.3
grp: prodint
intname: global2
My jinja template looks like this
{% for intf in interfaces %}
{{ intf }}
{% for key,value in intf.items() %}
{{ key }}
{{ value }}
{% endfor %}
{% endfor %}
When I try to access the elements from the object, I get an error saying no elements found

More likely you shoud try something like this:
vars:
interfaces:
- loopback_local:
- address: 0.0.0.0
prefix: 24
area: 192.168.1.2
grp: testint
intname: global
- address: 0.0.0.0
prefix: 24
area: 192.168.1.3
grp: prodint
intname: global2
jinjafile
{% for intf in interfaces %}
{% for i in intf.loopback_local %}
{% for key,value in i.items() %}
{{ key }}:{{ value }}
{% endfor %}
{% endfor %}
{% endfor %}

Related

How to exclude an host in Ansible Jinja2 template for-loop?

I have a template named foo.yml.j2 used in an Ansible task to generate a foo.yml file:
{% for host in ansible_play_hosts_all %}
{{ host }},
{% endfor %}
Everything works fine except I need something like the following statement: For every host in ansible_play_hosts_all except for host==bar do this or that.
Is this achievable or the only way to do this is to categorize my hosts in different groups and use ansible_play_hosts_group?
You can use the reject filter to take your host out of the list so that it is not part of your loop:
{% for host in ansible_play_hosts_all | reject('==', 'bar') %}
{{ host }},
{% endfor %}
There are more options. The trivial one is using the condition in Jinja
{% for host in ansible_play_hosts_all %}
{% if host != 'bar' %}
{{ host }},
{% endif %}
{% endfor %}
Fit the format to your needs.
Example of a complete playbook for testing
- hosts: host_1,host_2,host_3
gather_facts: false
tasks:
- debug:
msg: |
{% for host in ansible_play_hosts_all %}
{% if host != 'host_2' %}
{{ host }},
{% endif %}
{% endfor %}
run_once: true
gives (abridged)
msg: |-
host_1,
host_3,
The next option is to remove blacklisted hosts from the loop, e.g.
blacklist: [host_2]
The template below gives the same result
{% for host in ansible_play_hosts_all|difference(blacklist) %}
{{ host }},
{% endfor %}

ansible jinja2: nested dictionary

I'm trying to generate the following list:
list1:127.0.0.1,127.0.0.2
list2:192.168.1.1,192.168.1.254
From this dictionary:
ip_allowed:
list1:
- 127.0.0.1
- 127.0.0.2
list2:
- 192.168.1.1
- 192.168.1.254
Using the following jinja2 Ansible template:
#ZONE HOST(S) OPTIONS
{% for hosts_key, hosts_value in ip_allowed.iteritems() %}
{% set hosts_dict = hosts_value %}
{% for item in hosts_dict %}
{{ hosts_key }} {{ item }}
{%- if loop.first %},{% endif %}
{% endfor %}
{% endfor %}
But I'm getting the following result:
#ZONE HOST(S) OPTIONS
list1 127.0.0.1, list1 127.0.0.2 list2 192.168.1.1, list2 192.168.1.254
I'm not entirely sure I got the exact format you want out of the template but you'll adapt if needed once you get the idea. Just join each ip in the value.
#ZONE HOST(S) OPTIONS
{% for allowed_item in (ip_allowed | dict2items) %}
{{ allowed_item.key }} {{ allowed_item.value | join(',') }}
{% endfor %}

refer variable in host file from jinja2

I am using jinja2 template for haproxy configuration and I have variable declared in inventory file. how do I refer this variable in template. i have paste below script but it is not working.
My Inventory:-
[as]
10.0.0.1 asRole=batch
10.0.0.2 asRole=batch
10.0.0.3 asRole=transaction
10.0.0.4 asRole=transaction
[hap]
10.0.0.6
[hap] is the ip for the haproxy and my ansible is to set the haproxy configuration on [hap] node based on the [as] node.
My Jinja2 tempalte:-
{% for host in groups['as'] %}
{% if "transaction" in "{{ asRole }} %}
server {{ hostvars[host]['inventory_hostname'] }} {{ host }}:{{ httpd_port }}check
{% endif %}
{% endfor %}
Br,
Tanmoy
Be careful with the asRole Var:
{% for host in groups['as'] %}
{% if "transaction" in asRole %}
server {{ hostvars[host]['inventory_hostname'] }} {{ host }}:{{ httpd_port }}check
{% endif %}
{% endfor %}

AnsibleUndefinedVariable: 'list object' has no attribute

Yaml template
bgp:
local: 109
remote: 109
site:
- neighbor:
peer_ip: [ 172.16.110.3, 172.16.110.4 ]
vpnv4:
vrf: Site-1
network: 109.10.1.1
mask: 255.255.255.0
- neighbor:
peer_ip: [ 172.16.120.3, 172.16.120.4 ]
vpnv4:
vrf: Site-2
network: 109.10.1.1
mask: 255.255.255.0
Jinja2 template
router bgp {{ item.bgp.local }}
{% for i in item.bgp.site %}
address-family ipv4 vrf {{ i.vpnv4.vrf }}
network {{ i.vpnv4.network }} mask {{ i.vpnv4.mask }}
{% for b in item.bgp.site.neighbor.peer_ip %}
neighbor {{ b }} remote-as {{ item.bgp.remote }}
neighbor {{ b }} activate
{% endfor %}
{% endfor %}
If I remove this it works. I am suspecting an issue with "list" but no idea how to fix it.
{% for b in item.bgp.site.neighbor.peer_ip %}
neighbor {{ b }} remote-as {{ item.bgp.remote }}
neighbor {{ b }} activate
{% endfor %}
item.bgp.site is actually i of your outer loop.
Try: {% for b in i.neighbor.peer_ip %}

Ansible/Jinja: condition with an undefined statement

I need to iterate over all hosts and generate config file for hosts that are not contained in group somegroup:
{% for host in groups.all if host not in groups['somegroup'] %}
But if somegroup does not exist, it fails (argument of type 'StrictUndefined' is not iterable).
How do I write this correctly to avoid two different for cycles:
{% if groups['somegroup'] is defined %}
{% for host in groups.all if host not in groups['somegroup'] %}
...
{% endfor %}
{% else %}
{% for host in groups.all %}
...
{% endfor %}
{% endif %}
I think you're looking for the default filter:
{% for host in groups.all if host not in groups['somegroup'] | default([]) %}

Resources