Skip to content

Instantly share code, notes, and snippets.

@Ramblurr
Created October 28, 2020 13:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ramblurr/5d8324e0154ea6be52407618222fcaf7 to your computer and use it in GitHub Desktop.
Save Ramblurr/5d8324e0154ea6be52407618222fcaf7 to your computer and use it in GitHub Desktop.
Ansible find interface name given an ip address on Linux and FreeBSD
---
# Answer from Vladimir Botka @ https://serverfault.com/questions/1040246/how-to-select-network-interface-given-ip-address-in-ansible-across-debian-and-fr/1040273#1040273
# Tested on Ansible 2.10
# can this be simplified? Watch https://github.com/ansible/ansible/issues/69638
- name: find interface name assigned given ip address
hosts: all
vars:
ip_find_iface: "10.1.0.51"
freebsd_query: >-
[?value.type == 'ether'].{device: value.device,
ipv4: value.ipv4[].address}
linux_query: >-
[?value.type == 'ether'].{device: value.device,
ipv4: value.ipv4.address}
ip_query: >-
{% if ansible_system == "FreeBSD" %}
{{ freebsd_query }}
{% else %}
{{ linux_query }}
{% endif %}
ifc_list: >-
{{ ansible_facts|
dict2items|
json_query(ip_query)|
selectattr('ipv4')|list }}
tasks:
- set_fact:
iface_for_ip: "{{ (iface_for_ip|default([]) + [item.device]) | first }}"
loop: "{{ ifc_list }}"
when: ip_find_iface in item.ipv4
- debug:
var: _ip_query
- debug:
var: ifc_list
- debug:
var: iface_for_ip
- debug:
msg: "iface for {{ ip_find_iface }} is {{ iface_for_ip }}"
@SimonHeimberg
Copy link

SimonHeimberg commented Oct 28, 2020

suggestions for directly getting the matches from json_query (I only write differences of variables):

freebsd_query: "[?value.type == 'ether'].{device: device, active: active, ipv6: ipv6, ipv4: ipv4[? address == '{{ ip_find_iface }}']}[?ipv4])" # string must be in ' # sorry, only partial interface info, did not find out how to return all info directly
linux_query: "[?value.type == 'ether'][?ipv4.address == '{{ ip_find_iface }}']" # string must be in '
# optional, a vendor independent query
ip_query: "{{ ansible_facts[ansible_facts.interfaces | first].ipv4 is mapping | ternary(linux_query, freedsd_query) }}"

for getting the device name only, append .device to both queries (or to ip_qury only)

set_fact: is unnecessary after this

note: solaris also returns the data as FreeBSD does ansible/ansible#16615, therefore the vendor independent variant for ip_query.
note: loopback has type loopback, type bridge exists as well. So maybe [?value.mtu] instead of [value.type == 'ether'] would be better. (or does there exist a network interface with no mtu set? (localhost does not have a macaddress)) Or go get all interfaces for sure, use ansible_facts.interfaces | map('extract', ansible_facts ) before the filter, so [*] would replace [value.type == 'ether'].

to also check ipv6 address:

ipv6_query: "[?value.type == 'ether'].{device: device, active: active, ipv4: ipv4, ipv6: ipv6[? address == '{{ ip_find_iface }}']}[?ipv6]" # string must be in ' # sorry, only partial info, did not find how to return the full one
ip_query: "{{ ip_find_iface | ipv6 | ternary(
    ipv6_query,
    ansible_facts[ansible_facts.interfaces | first].ipv4 is mapping | ternary(linux_query, freebds_query)
) }}"

about | ipv6 see https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#ip-address-filters

all put together: https://serverfault.com/a/1040389/482659

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment