ansible_facts showing interface eth0_1

I’m using ansible-core 1.18. When I gather facts on a device, it shows the interfaces of eth0, eth0_1, eth1 and lo. The results of “ip a” show only eth0, eth1 and lo interfaces . When I try to start arpwatch for each interface (other than lo), it fails on eth0_1, which makes sense to me. Why does ansible_facts interfaces show eth0_1?

Hi :wave:

It’s the VLAN ID for the sub-interface which ansible_facts is showing for eth0_1

You must use the iproute 2 package with ip addr not net-tools

If you want to modify this then you will need set_facts magic;

To access variables of other hosts, you should enable fact caching.

In playbook files, you should adding gather_facts: True to update facts.

The ansible_interfaces fact lists all of the existing network interfaces.

Some hints to get an interface when you know more information:

    var:
      allNetworkInterfaces: "{{ ansible_facts | dict2items | selectattr('value.ipv4', 'defined') | map(attribute='value') | list }}"
      allNetworkInterfaces_variant2: "{{ ansible_facts.interfaces | map('extract', ansible_facts ) | list }}"
      interfaceWithKnownIp: "{{ ansible_facts | dict2items | selectattr('value.ipv4', 'defined') | selectattr('value.ipv4.address', 'equalto', myKnowIpV4) | first }}"
      interfaceWithKnownIp_fromVar: "{{ allNetworkInterfaces | selectattr('ipv4.address', 'equalto', myKnowIpV4) | first }}"
      interfacesWithPartialKnowMac: "{{ allNetworkInterfaces | selectattr('macaddress', 'match', knownMacPrefix~'.*') | list }}"
      interfacesWitKnowType: "{{ allNetworkInterfaces | selectattr('type', 'equalto', knownType) | sort(attribute='device') | list }}"
      # extended on 2020-10-28
      queryForKnownIpv6: "[*].{device: device, ipv4: ipv4, ipv6: ipv6[? address == 'fe80::a00:27ff:fe38:ad36']}[?ipv6])" # string must be in ' # sorry, only partial interface info, did not find out how to return all info directly
      interfacesWithKnownIpv6: '{{ allNetworkInterfaces | json_query(queryForKnownIpv6) | first }}'
      queryForKnownIpv4_linux: "[?ipv4.address == '{{ myKnownIpV4 }}']}[?ipv4])" # string must be in '
      interfacesWithKnownIp_variantJsonQuery: '{{ allNetworkInterfaces | json_query(queryForKnownIpv4_linux) | first }}'

some short explications:

the ansible_interfaces fact contains a list of all the network interfaces and they appear to be in order (i.e., the first ethernet interface would have been called eth0, the second eth1, etc). With a little set_fact magic:

- name: define traditional ethernet facts
  set_fact:
    ansible_eth: "{% set ansible_eth = ansible_eth|default([]) + [hostvars[inventory_hostname]['ansible_' + item]] %}{{ ansible_eth|list }}"
  when: hostvars[inventory_hostname]['ansible_' + item]['type'] == 'ether'
  with_items:
    - "{{ hostvars[inventory_hostname]['ansible_interfaces'] }}"

This loops over all of the ansible_interfaces entries for the current machine and builds a list of the hostvars[inventory_hostname]['ansible_' + item] entries that have a type equal to “ether”.

Thus now ansible_eth.0 and ansible_eth.1 should be roughly equivalent to the old ansible_eth0`` and ``ansible_eth1 respectively.

Best,

S.W

Hi :wave:

It’s the VLAN ID for the sub-interface which ansible_facts is showing for eth0_1

You must use the iproute 2 package with ip addr not net-tools

If you want to modify this then you will need set_facts magic;

To access variables of other hosts, you should enable fact caching.

In playbook files, you should add in:

gather_facts: True

#to update facts.

The ansible_interfaces fact lists all of the existing network interfaces.

Some hints to get an interface when you know more information:

var:

allNetworkInterfaces: “{{ ansible_facts | dict2items | selectattr(‘value.ipv4’, ‘defined’) | map(attribute=‘value’) | list }}”

allNetworkInterfaces_variant2: “{{ ansible_facts.interfaces | map(‘extract’, ansible_facts ) | list }}”

interfaceWithKnownIp: “{{ ansible_facts | dict2items | selectattr(‘value.ipv4’, ‘defined’) | selectattr(‘value.ipv4.address’, ‘equalto’, myKnowIpV4) | first }}”

interfaceWithKnownIp_fromVar: “{{ allNetworkInterfaces | selectattr(‘ipv4.address’, ‘equalto’, myKnowIpV4) | first }}”

interfacesWithPartialKnowMac: “{{ allNetworkInterfaces | selectattr(‘macaddress’, ‘match’, knownMacPrefix~‘.*’) | list }}”

interfacesWitKnowType: “{{ allNetworkInterfaces | selectattr(‘type’, ‘equalto’, knownType) | sort(attribute=‘device’) | list }}”

extended on 2020-10-28

queryForKnownIpv6: “[*].{device: device, ipv4: ipv4, ipv6: ipv6[? address == ‘fe80::a00:27ff:fe38:ad36’]}[?ipv6])” # string must be in ’ # sorry, only partial interface info, did not find out how to return all info directly

interfacesWithKnownIpv6: ‘{{ allNetworkInterfaces | json_query(queryForKnownIpv6) | first }}’

queryForKnownIpv4_linux: “[?ipv4.address == ‘{{ myKnownIpV4 }}’]}[?ipv4])” # string must be in ’

interfacesWithKnownIp_variantJsonQuery: ‘{{ allNetworkInterfaces | json_query(queryForKnownIpv4_linux) | first }}’

some short explications:

the ansible_interfaces fact contains a list of all the network interfaces and they appear to be in order (i.e., the first ethernet interface would have been called eth0, the second eth1, etc). With a little set_fact magic:

  • name: define traditional ethernet facts

set_fact:

ansible_eth: “{% set ansible_eth = ansible_eth|default() + [hostvars[inventory_hostname][‘ansible_’ + item]] %}{{ ansible_eth|list }}”

when: hostvars[inventory_hostname][‘ansible_’ + item][‘type’] == ‘ether’

with_items:

  • “{{ hostvars[inventory_hostname][‘ansible_interfaces’] }}”

This loops over all of the ansible_interfaces entries for the current machine and builds a list of the hostvars[inventory_hostname][‘ansible_’ + item] entries that have a type equal to “ether”.

Thus now ansible_eth.0 and ansible_eth.1 should be roughly equivalent to the old ansible_eth0 and ansible_eth1 respectively.

Best,

S.W

Thanks for that info - very interesting.

I’m trying to start arpwatch for each interface using the following:

name: Start arpwatch
command: arpwatch -i {{ item }}
loop: “{{ ansible_interfaces }}”
when: ansible_facts[item] is defined and not ‘lo’

I need to provide for eth interfaces as well as ens192… etc. Any idea what I can do to ignore these VLAN interfaces?

Kathy, your “when:” condition is incorrect. “not ‘lo’” will always be false, so likewise

  when: ansible_facts[item] is defined and not 'lo'

will also always be false.

That makes sense -thank you. Sorry for the confusion - some of your text is white and did not display against my white background! It works now!