22

I have a host_var in ansible with dict with all interfaces:

---
interfaces:
  vlan0:
    ip: 127.0.0.1
    mask: 255.255.255.0
    state: true

  vlan2:
    ip: 127.0.1.1
    mask: 255.255.255.0
    state: true

And I want to check if dict has a key vlan1 if ok put to template value vlan1.ip else put vlan2.ip.

{% if interfaces.vlan1 %} 
# and also I try {% if 'vlan1' in interfaces %}
{{ interfaces.vlan1.ip }};
{% else %}
{{ interfaces.vlan2.ip|default("127.0.0.1") }};
{% endif %};

But i have an error:

fatal: [127.0.0.1] => {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'dict object' has no attribute 'vlan1'", 'failed': True}

I found that it have to be work in Jinja2 but it seems to doesn't work in ansible. Maybe someone have another way for solving this problem? When I define vlan1 it works fine. Ansible version 1.9.2

I was trying to reproduce it in python and have no error if my dictionary have not key vlan1. thanks to @GUIDO

>>> from jinja2 import Template
>>> b = Template("""
... {% if interfaces.vlan1 %}
... {{ interfaces.vlan1.ip }}
... {% else %}
... {{ interfaces.vlan2.ip|default("127.0.3.1") }}
... {% endif %}""")
>>> b.render(interfaces={'vlan3':{'ip':'127.0.1.1'},'vlan2':{'ip':'127.0.2.1'}})
u'\n\n127.0.2.1\n'
>>> b.render(interfaces={'vlan1':{'ip':'127.0.1.1'},'vlan2':{'ip':'127.0.2.1'}})
u'\n\n127.0.1.1\n'
Community
  • 1
  • 1
Alex
  • 5,728
  • 5
  • 20
  • 20

2 Answers2

35

The answer is simple and it showed on ansible error message. First of all I need to check if var is defined.

{% if interfaces.vlan1 is defined %}
{{ interfaces.vlan1.ip }}
{% else %}
{{ interfaces.vlan2.ip|default("127.0.3.1") }}
{% endif %}

This combination works well.

Alex
  • 5,728
  • 5
  • 20
  • 20
  • 1
    it seems like the `is defined` part is crucial. i haven't been able to make the `if` logic work with just using `{% if item.var %}` – ryantuck Feb 09 '16 at 19:59
  • @RyanTuck The {% if item.var %} checks only if var is not Null and if it is not defined that raise an error. If you need all checks use it together {% if item.var is defined and item.var %} – Alex Feb 11 '16 at 08:46
  • You cal also use `if x is not defined`. Thanks – Johann Burgess Jan 20 '21 at 06:17
11

The best way to check if a key exists in a dictionary (in any Jinja2 context, not just with Ansible) is to use the in operator, e.g.:

{% if 'vlan1' in interfaces %}
{{ interfaces.vlan1.ip |default(interfaces.vlan2.ip) }};
{% endif %}
larsks
  • 277,717
  • 41
  • 399
  • 399
  • Thank you. But I have another error: `fatal: [127.0.0.1] => {'msg': 'AnsibleUndefinedVariable: One or more undefined variables: float object has no element 0', 'failed': True}` – Alex Oct 29 '15 at 07:26
  • Maybe `vlan2` is also not available? I could help more if you could post a playbook that reproduces the specific problem. – larsks Oct 29 '15 at 13:09
  • host_var you can see in question. playbook is simple role: `- name: Configure named.conf.options template: src=named.conf.options.j2 dest=/etc/bind/named.conf.options backup=yes owner=root group=bind mode=0644 become: yes tags: bind notify: restart bind` In named.conf.options.j2 i use jinja template as described above. – Alex Oct 29 '15 at 14:30