I'm looking for an expression to fetch the interface name given an ip address assigned to that iface, across Linux and FreeBSD.
This question is based on this answer: https://serverfault.com/a/948288/416946
This jinja2 expression will, on Debian, return the interface object (from ansible facts) for the given_ip
iface_for_ip: >-
{{ ansible_facts
| dict2items
| selectattr('value.ipv4', 'defined')
| selectattr('value.ipv4.address', 'equalto', given_ip)
| first }}
However this does not work on FreeBSD because the ipv4
structure is an array, not an object.
If you run just this snippet:
iface_for_ip: >-
{{ ansible_facts
| dict2items
| selectattr('value.ipv4', 'defined') }}
You will get an output like this:
on Debian - key: eth0
value:
active: true
device: eth0
ipv4:
address: 10.8.20.206
broadcast: 10.8.20.255
netmask: 255.255.255.0
network: 10.8.20.0
ipv6:
- address: fe80::84ee:35ff:fed4:a23c
prefix: '64'
scope: link
macaddress: 00:ee:35:00:00:00
mtu: 1500
promisc: false
speed: 10000
type: ether
on FreeBSD
- key: epair0b
value:
device: epair0b
flags:
- UP
- BROADCAST
- RUNNING
- SIMPLEX
- MULTICAST
ipv4:
- address: 10.8.20.207
broadcast: 10.8.20.255
netmask: 255.255.255.0
network: 10.8.20.0
ipv6: []
macaddress: 00:ee:23:00:00:00
media: Ethernet
media_options:
- full-duplex
media_select: 10Gbase-T
media_type: 10Gbase-T
metric: '0'
mtu: '1500'
options:
- PERFORMNUD
status: active
type: ether
How can I use a jinja2 ansible expression to fetch the interface given just the ip address cross platform? json_query
could be useful here, but the method eludes me.
There is a difference in data collected by setup on Debian and FreeBSD.
In Ubuntu (Debian derivative) the attribute ipv4 is a dictionary. Secondary addresses are stored in the list ipv4_secondaries. As a first step create a list of devices and ipv4 addresses. For example
give (abridged)
Then "select network interface for given ip address"
give (abridged)
In FreeBSD the attribute ipv4 is a list. Create a list of devices and ipv4
give (abridged)
Then "select network interface for given ip address"
give (abridged)
Since Ansible 2.8 you can use test contains. The task below gives the same results
Q: "How to remove the final set_fact + loop so it can be defined purely in a vars file?"
A: The attribute ipv4 is a list. To use selectattr, instead of a loop, you'll need a test contains(seq, value). There is no such test in Ansible version 2.7 and lower. Only in(value, seq) test with reversed order of parameters is available. If you don't have Ansible version 2.8 or higher you'll have to write your own test. For example
Then the set_fact gives the same result. The expression can be also used in vars
Inspired from the other answer and the gist linked there
ip_query
first checks if the ip is in ipv6 format. If not, it checks if{anyNetwork}.ipv4
is a dict. The query forjson_query()
is selected depending on this.(there may be typos, since I can not (simply) test all. already corrected about 5 times...)
(how this developped: https://gist.github.com/Ramblurr/5d8324e0154ea6be52407618222fcaf7)