2

There's a unappreciated but very useful answer here which explains how to loop through the interface facts for an arbitrary number of interfaces.

Basically, it comes down to this:

debug:
  msg: "{{ hostvars[inventory_hostname]['ansible_%s' | format(item)] }}"
with_items: "{{ ansible_interfaces }}"

This is fantastic, but I want to access the individual items of the interface information - such as the address, and the MTU. I can't work out how to extract these fields. I was expecting to use something like:

msg: "{{ hostvars[inventory_hostname]['ansible_%s' | format(item)] ['ipv4']['address']}}"

But that produces an error when the template is filled. How do I address the sub-elements of the dictionary, please?

I can probably set facts in a loop in the playbook, as debugging seems able to reference the sub-elements, but I'd rather keep everything in the template.

Here's what the whole object looks like:

bond0 :
    {u'lacp_rate': u'slow', u'macaddress': u'00:24:e8:58:36:12', u'features': {u'generic_receive_offload': u'off', u'tx_checksumming': u'on', u'large_receive_offload': u'on', u'rx_checksumming': u'on',         u'udp_fragmentation_offload': u'off', u'generic_segmentation_offload': u'off', u'tcp_segmentation_offload': u'on', u'scatter_gather': u'on', u'ntuple_filters': u'off', u'receive_hashing': u'off'}, u'm
    iimon': u'100', u'speed': 1000, u'mtu': 1500, u'active': True, u'promisc': False, u'mode': u'active-backup', u'slaves': [u'eth0', u'eth1'], u'device': u'bond0', u'type': u'bonding', u'ipv4': {u'broadca
    st': u'10.138.162.255', u'netmask': u'255.255.255.0', u'network': u'10.138.162.0', u'address': u'10.138.162.11'}}

UPDATE: I can get the mtu like so:

MTU: {{ hostvars[inventory_hostname]['ansible_%s'|format(iface)]['mtu'] }}

But if I try to get the address info like so:

{{ {{ hostvars[inventory_hostname]['ansible_%s'|format(iface)]['ipv4'] }} }}

this error is generated:

fatal: [server_name]: FAILED! => {"changed": false, "failed": true, "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'ipv4'"}

Further Update: I've had an epiphany: for some interfaces there is no address, so ipv4 does not exist. I'll find out how to limit to when the interface does have an address, and write an answer to my question.

Graham Nicholls
  • 291
  • 2
  • 5
  • 13

1 Answers1

3

This is what's required:

{% for iface in ansible_interfaces %}
 {{ iface}} :
 {% if  hostvars[inventory_hostname]['ansible_%s'|format(iface)]['ipv4'] is defined %}
   {{ hostvars[inventory_hostname]['ansible_%s'|format(iface)]['ipv4']['address'] }}
 {% else %}
   No ip address set
 {% endif %}
   MTU: {{ hostvars[inventory_hostname]['ansible_%s'|format(iface)]['mtu'] }}
{% endfor %}

This works. NOTE that you can't have the condition check for a sub-element of (in this case) 'ipv4' like so:

{% if ... ['ipv4']['address'] %}

Because this still assumes that the dictionary has an element 'ipv4', when it doesn't.

I hope this helps someone else.

Graham Nicholls
  • 291
  • 2
  • 5
  • 13