'Ansible: Is there a way to check for an IP address and return a subnet from a list, if present?

I am tasked in setting up a check to verify if an IP address is contained within a subnet, with Ansible.

I have set up a test playbook, where I have done the following:

tasks:
   - name: "Include_vars"
      include_vars:
         file: /vlans.yml
   - name: "Set_fact"
      set_fact:
         test_item "{{ item | string | split (':') | last }}"
      loop: "{{ vlans }}"

Within the vlans.yml, the file contains a list of VLAN subnets, formatted like this:

vlans:
   - "vlan-1-external:10.0.1.0/24"
   - "vlan-2-internal:10.0.2.0/24"
   [...]

The playbook manages - with a debug instruction - to split the given string and only return the subnet like 10.0.1.0/24.

My objective is to make the playbook evaluate every VLAN within the list, passing an IP as an argument, and returning the specific VLAN which contains that IP address.

I have looked into the ipaddr filter, but I cannot see any way to perform this kind of check.

Does anybody know a way to perform the check that I'm looking for?

Thanks in advance for any hints.



Solution 1:[1]

Q: "Verify if an IP address is contained within a subnet."

A: Test a list of the IP addresses in the loop, e.g.

    - debug:
        msg: "{{ item.0 }}: {{ test_list|ansible.netcommon.ipaddr(item.1) }}"
      loop: "{{ vlans|map('split', ':')|list }}"
      vars:
        test_list:
          - 10.0.1.99
          - 10.0.2.99
          - 10.0.3.99

gives (abridged)

  msg: 'vlan-1-external: [''10.0.1.99'']'
  msg: 'vlan-2-internal: [''10.0.2.99'']'

Optionally, convert the list to a dictionary first

vlans_subnet: "{{ dict(vlans|map('split', ':')) }}"

gives

  vlans_subnet:
    vlan-1-external: 10.0.1.0/24
    vlan-2-internal: 10.0.2.0/24

Then, test a list of IP addresses in the loop

    - debug:
        msg: "{{ item.key }}: {{ test_list|ansible.netcommon.ipaddr(item.value) }}"
      loop: "{{ vlans_subnet|dict2items }}"
      vars:
        test_list:
          - 10.0.1.99
          - 10.0.2.99
          - 10.0.3.99

gives (abridged)

  msg: 'vlan-1-external: [''10.0.1.99'']'
  msg: 'vlan-2-internal: [''10.0.2.99'']'

Solution 2:[2]

Other than Vladimir's answer, there is another way to accomplish this:

First, set up a mapped list such as

vlans:
  - name: "vlan-1-internal"
    network: "192.168.1.0/24"
    [...]

Then cycle through this list and use network_in_usable, in order to verify if the IP address is within such list. Then, convert it to a JSON object:

vlan:
  {% set map = [] %}
    {% for object in vlans %}
      {%if (object.network | ansible.netcommon.network_in_usable(ip_to_check) ) %}
      {% set x=map.append({
        "name": object.name
        "network": object.network
        [...]
       }) %}
     {% endif %}
   {% endfor %}
  {{ map | to_json }}

Hope this helps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Alessandro