The setup module from ansible provides the fact ansible_interfaces

"ansible_interfaces": [

And per interface some facts:

"ansible_eth0": {
    "active": true, 
    "device": "eth0", 
    "ipv4": {
        "address": "", 
        "broadcast": "", 
        "netmask": "", 
        "network": ""
    "macaddress": "52:54:00:5c:c1:36", 
    "module": "virtio_net", 
    "mtu": 1500, 
    "pciid": "virtio0", 
    "promisc": false, 
    "type": "ether"

How do I use the ansible_interfaces fact to loop through the available interfaces?

    - name: find interface facts
      debug: msg=ansible_{{ item }}
      with_items: "{{ ansible_interfaces }}"

This is clearly not working, because it prints out the strings ansible_lo, ansible_eth0 and ansible_eth1, but I want it to print the facts from those interfaces. Some servers have other interfaces, like bridges, so I don't know in advance wich interfaces to use.

p.s. this example is not very usefull, but eventually I want to use it to store facts like macaddresses in elasticsearch for easy searching which server has which macaddress.


You came across one of the limitations of Jinja/Ansible templating, namely there is no way to evaluate expressions, which would be required to get to the value of something like ansible_{{ item }}. You're stuck with a string.

Fortunately there is the global hostvars object where you can access all the facts by key, which is... a string.

Something along these lines should get you there:

  - name: find interface facts
      msg: "{{ hostvars[inventory_hostname]['ansible_%s' | format(item)] }}"
    with_items: "{{ ansible_interfaces }}"

You actually can do this.You just have to know j2 syntax pretty well, search a little bit and combine it with some hacks. DOH. just lost 2 hours. Hope I save it to someone!

It's doable like this:

    - name: Display all interfaces
    msg: "{{ msg.split('\n') }}"
    msg: |
        {% for iface in ansible_interfaces|sort %}
            System interface {{ iface }}
            {{ vars.ansible_facts[iface] | to_nice_json }}
        {% endfor %}

And as I suspect, the people searching to do this, want to calculate the next free interface (which I was after for).

I did it like this:

    - name: calc next free interface
        nextFreeIf: "{% set ifacePrefix = vars.ansible_default_ipv4.alias %}{% set ifaceNum = { 'cnt': 0 } %}{% macro increment(dct, key, inc=1)%}{% if dct.update({key: dct[key] + inc}) %} {% endif %}{% endmacro %}{% for iface in ansible_interfaces|sort %}{% if iface| regex_search('^' ~ vars.ansible_default_ipv4.alias) %}{{ increment(ifaceNum, 'cnt') }}{% endif %}{% endfor %}{{ifacePrefix}}:{{ifaceNum.cnt}}"

the nextFreeIf is on one line, because, otherwise you get empty spaces and headaches to trim it. It's ugly, but hey, it works.

Really hope to save someones time. Cheers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.