'Ansible - Ensure list of IP addresses is valid against list of networks

Given a list of IP addresses, for example:

ip_addresses:
  - 192.168.10.198
  - 192.168.52.7
  - 192.168.109.78

A list of networks, for example:

valid_networks:
  - 192.168.10.0/24
  - 192.168.22.0/23
  - 192.168.50.0/21
  - 192.168.202.0/23
  - 192.168.205.0/24
  - 192.168.222.0/24

I'd like to assert that all entries in the ip_addresses list are a valid IP in one of the networks in the valid_networks list.

In the above example, it should fail because 192.168.109.78 isn't valid against any of the valid_networks.

Something like this will loop over the nested list and return true or false for each iteration, but I need to turn that into a useful overall pass or fail output. i.e., if there is no true for an IP address, it will fail and return the message “IP address x is not valid”. I'm struggling to come up with the accompanying logic.

- debug:
    msg: "{{ item.1 | network_in_usable(item.0) }}"
  with_nested:
    - "{{ ip_addresses }}"
    - "{{ valid_networks }}"

Many thanks in advance.



Solution 1:[1]

Use ansible.utils.ipaddr. For example

    - set_fact:
        vn_dict: "{{ vn_dict|d({})|
                     combine({item: ip_addresses|ansible.utils.ipaddr(item)}) }}"
      loop: "{{ valid_networks }}"

creates the dictionary

  vn_dict:
    192.168.10.0/24: [192.168.10.198]
    192.168.202.0/23: []
    192.168.205.0/24: []
    192.168.22.0/23: []
    192.168.222.0/24: []
    192.168.50.0/21: [192.168.52.7]

This can be used to get the list of valid IP addresses

  vn_dict.values()|flatten:
  - 192.168.10.198
  - 192.168.52.7

Then, the task below

    - assert:
        that: item in valid_ips
        fail_msg: "IP address {{ item }} is not valid."
      loop: "{{ ip_addresses }}"
      vars:
        valid_ips: "{{ vn_dict.values()|flatten }}"

tests the validity of the IP addresses one by one

TASK [assert] *****************************************************
ok: [localhost] => (item=192.168.10.198) => changed=false 
  ansible_loop_var: item
  item: 192.168.10.198
  msg: All assertions passed
ok: [localhost] => (item=192.168.52.7) => changed=false 
  ansible_loop_var: item
  item: 192.168.52.7
  msg: All assertions passed
failed: [localhost] (item=192.168.109.78) => changed=false 
  ansible_loop_var: item
  assertion: item in valid_ips
  evaluated_to: false
  item: 192.168.109.78
  msg: “IP address 192.168.109.78 is not valid.”

Optionally, to assert that all entries in the ip_addresses list are a valid IPs in one of the networks in the valid_networks list, the task below

    - assert:
        that: valid_ips_diff|length == 0
        fail_msg: "IP address(es) {{ valid_ips_diff }} not valid."
      vars:
        valid_ips: "{{ vn_dict.values()|flatten }}"
        valid_ips_diff: "{{ ip_addresses|difference(valid_ips) }}"

tests the validity of the IP addresses in one step

TASK [assert] *****************************************************
fatal: [localhost]: FAILED! => changed=false 
  assertion: valid_ips_diff|length == 0
  evaluated_to: false
  msg: "IP address(es) ['192.168.109.78'] not valid."

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