diff --git a/README.md b/README.md index 49ce865..915e9d3 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Name | Description [ansible.utils.from_xml](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.from_xml_filter.rst)|Convert given XML string to native python dictionary. [ansible.utils.get_path](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.get_path_filter.rst)|Retrieve the value in a variable using a path [ansible.utils.index_of](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.index_of_filter.rst)|Find the indices of items in a list matching some criteria +[ansible.utils.ipsubnet](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.ipsubnet_filter.rst)|This filter can be used to manipulate network subnets in several ways. [ansible.utils.ipv6](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.ipv6_filter.rst)|To filter only Ipv6 addresses Ipv6 filter is used. [ansible.utils.ip4_hex](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.ip4_hex_filter.rst)|This filter is designed to convert IPv4 address to Hexadecimal notation with optional delimiter. [ansible.utils.ipmath](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.ipmath_filter.rst)|This filter is designed to do simple IP math/arithmetic. diff --git a/changelogs/fragments/add_ipsubnet_filter_plugin.yaml b/changelogs/fragments/add_ipsubnet_filter_plugin.yaml new file mode 100644 index 0000000..e832437 --- /dev/null +++ b/changelogs/fragments/add_ipsubnet_filter_plugin.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add ipsubnet filter plugin. diff --git a/docs/ansible.utils.ipsubnet_filter.rst b/docs/ansible.utils.ipsubnet_filter.rst new file mode 100644 index 0000000..a790bf6 --- /dev/null +++ b/docs/ansible.utils.ipsubnet_filter.rst @@ -0,0 +1,308 @@ +.. _ansible.utils.ipsubnet_filter: + + +********************** +ansible.utils.ipsubnet +********************** + +**This filter can be used to manipulate network subnets in several ways.** + + +Version added: 2.5.0 + +.. contents:: + :local: + :depth: 1 + + +Synopsis +-------- +- This filter can be used to manipulate network subnets in several ways. + + + + +Parameters +---------- + +.. raw:: html + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterChoices/DefaultsConfigurationComments
+
+ index + +
+ string +
+
+ + +
The second argument of the ipsubnet() filter is an index number; by specifying it you can get a new subnet + with the specified index.
+
+
+ query + +
+ string +
+
+ Default:
""
+
+ +
You can provide query as 1st argument. + To check if a given string is a subnet, pass it through the filter without any arguments. If the given + string is an IP address, it will be converted into a subnet. + If you specify a subnet size as the first parameter of the ipsubnet() filter, and the subnet size is + smaller than the current one, you will get the number of subnets a given subnet can be split into.
+
+
+ value + +
+ string + / required +
+
+ + +
subnets or individual address or any other values input for ipsubnet plugin
+
+
+ + + + +Examples +-------- + +.. code-block:: yaml + + #### examples + # Ipsubnet filter plugin with different queries. + vars: + address: '192.168.144.5' + subnet: '192.168.0.0/16' + tasks: + # If the given string is an IP address, it will be converted into a subnet. + - name: convert IP address to subnet + debug: + msg: "{{ address | ansible.utils.ipsubnet }}" + + # check if a given string is a subnet + - name: check if a given string is a subnet + debug: + msg: "{{ subnet | ansible.utils.ipsubnet }}" + + # Get the number of subnets a given subnet can be split into. + - name: Get the number of subnets a given subnet can be split into. + debug: + msg: "{{ subnet | ansible.utils.ipsubnet(20) }}" + + # Get a new subnet with the specified index. + - name: Get a 1st subnet + debug: + msg: "{{ subnet | ansible.utils.ipsubnet(20, 0) }}" + + # Get a new subnet with the specified index. + - name: Get a last subnet + debug: + msg: "{{ subnet | ansible.utils.ipsubnet(20, -1) }}" + + # If you specify an IP address instead of a subnet, and give a subnet size as the first argument, the ipsubnet() | + # filter will instead return the biggest subnet that contains that given IP address. + - name: Get biggest subnet that contains that given IP address. + debug: + msg: "{{ address | ansible.utils.ipsubnet(20) }}" + + # Get smaller and smaller subnets by specifying an index number as a second argument + - name: Get 1st smaller subnet by specifying 0 as index number + debug: + msg: "{{ address | ansible.utils.ipsubnet(18, 0) }}" + + # Get smaller and smaller subnets by specifying an index number as a second argument + - name: Get last subnet + debug: + msg: "{{ address | ansible.utils.ipsubnet(18, -1) }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: The rank of the IP in the subnet (the IP is the 36870nth /32 of the subnet) + debug: + msg: "{{ address | ansible.utils.ipsubnet(subnet) }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: The rank in the /24 that contain the address + debug: + msg: "{{ address | ansible.utils.ipsubnet('192.168.144.0/24') }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: An IP with the subnet in the first /30 in a /24 + debug: + msg: "{{ '192.168.144.1/30' | ansible.utils.ipsubnet('192.168.144.0/24') }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: he fifth subnet /30 in a /24 + debug: + msg: "{{ '192.168.144.16/30' | ansible.utils.ipsubnet('192.168.144.0/24') }}" + + + # PLAY [Ipsubnet filter plugin with different queries.] **************************************************************** + # TASK [convert IP address to subnet] ************************************************************************* + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:10 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "192.168.144.5/32" + # } + # + # TASK [check if a given string is a subnet] ****************************************************************** + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:15 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "192.168.0.0/16" + # } + # + # TASK [Get the number of subnets a given subnet can be split into.] ****************************************** + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:20 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "16" + # } + # + # TASK [Get a 1st subnet] ************************************************************************************* + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:25 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "192.168.0.0/20" + # } + # + # TASK [Get a last subnet] ************************************************************************************ + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:30 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "192.168.240.0/20" + # } + # + # TASK [Get biggest subnet that contains that given IP address.] ********************************************** + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:35 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "192.168.144.0/20" + # } + # + # TASK [Get 1st smaller subnet by specifying 0 as index number] *********************************************** + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:40 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "192.168.128.0/18" + # } + # + # TASK [Get last subnet] ************************************************************************************** + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:45 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "192.168.144.4/31" + # } + # + # TASK [The rank of the IP in the subnet (the IP is the 36870nth /32 of the subnet)] ************************** + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:50 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "36870" + # } + # + # TASK [The rank in the /24 that contain the address] ********************************************************* + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:55 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "6" + # } + # + # TASK [An IP with the subnet in the first /30 in a /24] ****************************************************** + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:60 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "1" + # } + # + # TASK [he fifth subnet /30 in a /24] ************************************************************************* + # task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:65 + # Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "5" + # } + + + +Return Values +------------- +Common return values are documented `here `_, the following are the fields unique to this filter: + +.. raw:: html + + + + + + + + + + + + +
KeyReturnedDescription
+
+ data + +
+ list + / elements=string +
+
+
Returns list with values valid for a particular query.
+
+
+

+ + +Status +------ + + +Authors +~~~~~~~ + +- Ashwini Mhatre (@amhatre) + + +.. hint:: + Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up. diff --git a/plugins/filter/ipsubnet.py b/plugins/filter/ipsubnet.py new file mode 100644 index 0000000..815277a --- /dev/null +++ b/plugins/filter/ipsubnet.py @@ -0,0 +1,342 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +filter plugin file for ipaddr filters: ipsubnet +""" +from __future__ import absolute_import, division, print_function +from functools import partial +from ansible_collections.ansible.utils.plugins.plugin_utils.base.ipaddr_utils import ( + ipaddr, + _need_netaddr, +) +from ansible.errors import AnsibleFilterError +from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( + AnsibleArgSpecValidator, +) + +__metaclass__ = type + + +try: + from jinja2.filters import pass_environment +except ImportError: + from jinja2.filters import environmentfilter as pass_environment + +try: + import netaddr + + HAS_NETADDR = True +except ImportError: + # in this case, we'll make the filters return error messages (see bottom) + HAS_NETADDR = False +else: + + class mac_linux(netaddr.mac_unix): + pass + + mac_linux.word_fmt = "%.2x" + +DOCUMENTATION = """ + name: ipsubnet + author: Ashwini Mhatre (@amhatre) + version_added: "2.5.0" + short_description: This filter can be used to manipulate network subnets in several ways. + description: + - This filter can be used to manipulate network subnets in several ways. + options: + value: + description: + - subnets or individual address or any other values input for ipsubnet plugin + type: str + required: True + query: + description: | + You can provide query as 1st argument. + To check if a given string is a subnet, pass it through the filter without any arguments. If the given + string is an IP address, it will be converted into a subnet. + If you specify a subnet size as the first parameter of the ipsubnet() filter, and the subnet size is + smaller than the current one, you will get the number of subnets a given subnet can be split into. + type: str + default: '' + index: + description: | + The second argument of the ipsubnet() filter is an index number; by specifying it you can get a new subnet + with the specified index. + type: str + notes: +""" + +EXAMPLES = r""" +#### examples +# Ipsubnet filter plugin with different queries. +vars: + address: '192.168.144.5' + subnet: '192.168.0.0/16' +tasks: + # If the given string is an IP address, it will be converted into a subnet. + - name: convert IP address to subnet + debug: + msg: "{{ address | ansible.utils.ipsubnet }}" + + # check if a given string is a subnet + - name: check if a given string is a subnet + debug: + msg: "{{ subnet | ansible.utils.ipsubnet }}" + + # Get the number of subnets a given subnet can be split into. + - name: Get the number of subnets a given subnet can be split into. + debug: + msg: "{{ subnet | ansible.utils.ipsubnet(20) }}" + + # Get a new subnet with the specified index. + - name: Get a 1st subnet + debug: + msg: "{{ subnet | ansible.utils.ipsubnet(20, 0) }}" + + # Get a new subnet with the specified index. + - name: Get a last subnet + debug: + msg: "{{ subnet | ansible.utils.ipsubnet(20, -1) }}" + + # If you specify an IP address instead of a subnet, and give a subnet size as the first argument, the ipsubnet() | + # filter will instead return the biggest subnet that contains that given IP address. + - name: Get biggest subnet that contains that given IP address. + debug: + msg: "{{ address | ansible.utils.ipsubnet(20) }}" + + # Get smaller and smaller subnets by specifying an index number as a second argument + - name: Get 1st smaller subnet by specifying 0 as index number + debug: + msg: "{{ address | ansible.utils.ipsubnet(18, 0) }}" + + # Get smaller and smaller subnets by specifying an index number as a second argument + - name: Get last subnet + debug: + msg: "{{ address | ansible.utils.ipsubnet(18, -1) }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: The rank of the IP in the subnet (the IP is the 36870nth /32 of the subnet) + debug: + msg: "{{ address | ansible.utils.ipsubnet(subnet) }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: The rank in the /24 that contain the address + debug: + msg: "{{ address | ansible.utils.ipsubnet('192.168.144.0/24') }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: An IP with the subnet in the first /30 in a /24 + debug: + msg: "{{ '192.168.144.1/30' | ansible.utils.ipsubnet('192.168.144.0/24') }}" + + # By specifying another subnet as a second argument, if the second subnet includes the first, you can determine | + # the rank of the first subnet in the second. + - name: he fifth subnet /30 in a /24 + debug: + msg: "{{ '192.168.144.16/30' | ansible.utils.ipsubnet('192.168.144.0/24') }}" + + +# PLAY [Ipsubnet filter plugin with different queries.] **************************************************************** +# TASK [convert IP address to subnet] ************************************************************************* +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:10 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "192.168.144.5/32" +# } +# +# TASK [check if a given string is a subnet] ****************************************************************** +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:15 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "192.168.0.0/16" +# } +# +# TASK [Get the number of subnets a given subnet can be split into.] ****************************************** +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:20 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "16" +# } +# +# TASK [Get a 1st subnet] ************************************************************************************* +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:25 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "192.168.0.0/20" +# } +# +# TASK [Get a last subnet] ************************************************************************************ +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:30 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "192.168.240.0/20" +# } +# +# TASK [Get biggest subnet that contains that given IP address.] ********************************************** +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:35 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "192.168.144.0/20" +# } +# +# TASK [Get 1st smaller subnet by specifying 0 as index number] *********************************************** +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:40 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "192.168.128.0/18" +# } +# +# TASK [Get last subnet] ************************************************************************************** +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:45 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "192.168.144.4/31" +# } +# +# TASK [The rank of the IP in the subnet (the IP is the 36870nth /32 of the subnet)] ************************** +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:50 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "36870" +# } +# +# TASK [The rank in the /24 that contain the address] ********************************************************* +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:55 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "6" +# } +# +# TASK [An IP with the subnet in the first /30 in a /24] ****************************************************** +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:60 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "1" +# } +# +# TASK [he fifth subnet /30 in a /24] ************************************************************************* +# task path: /Users/amhatre/ansible-collections/playbooks/test_ipsubnet.yaml:65 +# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "5" +# } + +""" + +RETURN = """ + data: + type: list + elements: str + description: + - Returns list with values valid for a particular query. +""" + + +@pass_environment +def _ipsubnet(*args, **kwargs): + """Manipulate IPv4/IPv6 subnets""" + keys = ["value", "query", "index"] + data = dict(zip(keys, args[1:])) + data.update(kwargs) + aav = AnsibleArgSpecValidator( + data=data, schema=DOCUMENTATION, name="ipsubnet" + ) + valid, errors, updated_data = aav.validate() + if not valid: + raise AnsibleFilterError(errors) + return ipsubnet(**updated_data) + + +def ipsubnet(value, query="", index="x"): + """ Manipulate IPv4/IPv6 subnets """ + + try: + vtype = ipaddr(value, "type") + if vtype == "address": + v = ipaddr(value, "cidr") + elif vtype == "network": + v = ipaddr(value, "subnet") + + value = netaddr.IPNetwork(v) + except Exception: + return False + query_string = str(query) + if not query: + return str(value) + + elif query_string.isdigit(): + vsize = ipaddr(v, "size") + query = int(query) + + try: + float(index) + index = int(index) + + if vsize > 1: + try: + return str(list(value.subnet(query))[index]) + except Exception: + return False + + elif vsize == 1: + try: + return str(value.supernet(query)[index]) + except Exception: + return False + + except Exception: + if vsize > 1: + try: + return str(len(list(value.subnet(query)))) + except Exception: + return False + + elif vsize == 1: + try: + return str(value.supernet(query)[0]) + except Exception: + return False + + elif query_string: + vtype = ipaddr(query, "type") + if vtype == "address": + v = ipaddr(query, "cidr") + elif vtype == "network": + v = ipaddr(query, "subnet") + else: + msg = "You must pass a valid subnet or IP address; {0} is invalid".format( + query_string + ) + raise AnsibleFilterError(msg) + query = netaddr.IPNetwork(v) + for i, subnet in enumerate(query.subnet(value.prefixlen), 1): + if subnet == value: + return str(i) + msg = "{0} is not in the subnet {1}".format(value.cidr, query.cidr) + raise AnsibleFilterError(msg) + return False + + +class FilterModule(object): + """IP address and network manipulation filters + """ + + filter_map = { + # IP addresses and networks + "ipsubnet": _ipsubnet + } + + def filters(self): + """ ipsubnet filter """ + if HAS_NETADDR: + return self.filter_map + else: + return dict( + (f, partial(_need_netaddr, f)) for f in self.filter_map + ) diff --git a/tests/integration/targets/utils_ipaddr_filter/tasks/ipsubnet.yaml b/tests/integration/targets/utils_ipaddr_filter/tasks/ipsubnet.yaml new file mode 100644 index 0000000..a134c38 --- /dev/null +++ b/tests/integration/targets/utils_ipaddr_filter/tasks/ipsubnet.yaml @@ -0,0 +1,64 @@ +--- +- name: convert address to subnet using ipsubnet + ansible.builtin.set_fact: + result1: "{{ address | ansible.utils.ipsubnet }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result1 == '192.168.144.5/32' }}" + +- name: check if given value is subnet + ansible.builtin.set_fact: + result2: "{{ subnet | ansible.utils.ipsubnet }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result2 == '192.168.0.0/16' }}" + +- name: Get the number of subnets a given subnet can be split into + ansible.builtin.set_fact: + result3: "{{ subnet | ansible.utils.ipsubnet('20') }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result3 == '16' }}" + +- name: Get the 1st subnet + ansible.builtin.set_fact: + result4: "{{ subnet | ansible.utils.ipsubnet('20', '0') }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result4 == '192.168.0.0/20' }}" + +- name: Get the last subnet + ansible.builtin.set_fact: + result5: "{{ subnet | ansible.utils.ipsubnet('20', '-1') }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result5 == '192.168.240.0/20' }}" + +- name: Get biggest subnet that contains that given IP address + ansible.builtin.set_fact: + result6: "{{ address | ansible.utils.ipsubnet('20') }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result6 == '192.168.144.0/20' }}" + +- name: Get the 1st subnet + ansible.builtin.set_fact: + result7: "{{ address | ansible.utils.ipsubnet('18', '0') }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result7 == '192.168.128.0/18' }}" + +- name: The rank of the IP in the subnet (the IP is the 36870nth /32 of the subnet) + ansible.builtin.set_fact: + result8: "{{ address | ansible.utils.ipsubnet(subnet) }}" + +- name: Assert result for ipsubnet. + assert: + that: "{{ result8 == '36870' }}" diff --git a/tests/integration/targets/utils_ipaddr_filter/vars/main.yaml b/tests/integration/targets/utils_ipaddr_filter/vars/main.yaml index f68af6b..c844695 100644 --- a/tests/integration/targets/utils_ipaddr_filter/vars/main.yaml +++ b/tests/integration/targets/utils_ipaddr_filter/vars/main.yaml @@ -1,4 +1,6 @@ --- +address: '192.168.144.5' +subnet: '192.168.0.0/16' result1_val: - "192.24.2.1" - "192.168.32.0/24" diff --git a/tests/unit/plugins/filter/test_ipsubnet.py b/tests/unit/plugins/filter/test_ipsubnet.py new file mode 100644 index 0000000..bb40b89 --- /dev/null +++ b/tests/unit/plugins/filter/test_ipsubnet.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# Copyright 2021 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +Unit test file for ipwrap filter plugin +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import unittest +from ansible_collections.ansible.utils.plugins.filter.ipsubnet import _ipsubnet + + +address = "192.168.144.5" +subnet = "192.168.0.0/16" + + +class TestIpSubnet(unittest.TestCase): + def setUp(self): + pass + + def test_ipvsubnet_address_subnet(self): + """convert address to subnet""" + args = ["", address, ""] + result = _ipsubnet(*args) + self.assertEqual(result, "192.168.144.5/32") + + def test_ipvsubnet_filter_subnet(self): + """check if a given string is a subnet""" + args = ["", subnet, ""] + result = _ipsubnet(*args) + self.assertEqual(result, "192.168.0.0/16") + + def test_ipvsubnet_filter_subnet_size(self): + """Get the number of subnets a given subnet can be split into.""" + args = ["", subnet, "20"] + result = _ipsubnet(*args) + self.assertEqual(result, "16") + + def test_ipvsubnet_filter_subnet_with_1st_index(self): + """Get the 1st subnet""" + args = ["", subnet, "20", 0] + result = _ipsubnet(*args) + self.assertEqual(result, "192.168.0.0/20") + + def test_ipvsubnet_filter_subnet_with_last_index(self): + """Get the last subnet""" + args = ["", subnet, "20", -1] + result = _ipsubnet(*args) + self.assertEqual(result, "192.168.240.0/20") + + def test_ipvsubnet_filter_address_with_size(self): + """Get biggest subnet that contains that given IP address""" + args = ["", address, "20"] + result = _ipsubnet(*args) + self.assertEqual(result, "192.168.144.0/20") + + def test_ipvsubnet_filter_address_with_1st_index(self): + """Get the 1st subnet""" + args = ["", address, "18", 0] + result = _ipsubnet(*args) + self.assertEqual(result, "192.168.128.0/18") + + def test_ipvsubnet_filter_address_with_last_index(self): + """Get the last subnet""" + args = ["", address, "18", -1] + result = _ipsubnet(*args) + self.assertEqual(result, "192.168.144.4/31") + + def test_ipvsubnet_filter_rank_address_in_subnet(self): + """The rank of the IP in the subnet (the IP is the 36870nth /32 of the subnet)""" + args = ["", address, subnet] + result = _ipsubnet(*args) + self.assertEqual(result, "36870") + + def test_ipvsubnet_filter_rank_address_in_subnet1(self): + """The rank of the IP in the 192.168.144.0/24""" + args = ["", address, "192.168.144.0/24"] + result = _ipsubnet(*args) + self.assertEqual(result, "6") + + def test_ipvsubnet_filter_rank_address_in_subnet2(self): + """The rank of the IP in the 192.168.144.0/24""" + args = ["", "192.168.144.1/30", "192.168.144.0/24"] + result = _ipsubnet(*args) + self.assertEqual(result, "1") + + def test_ipvsubnet_filter_rank_address_in_subnet3(self): + """The rank of the IP in the 192.168.144.0/24""" + args = ["", "192.168.144.16/30", "192.168.144.0/24"] + result = _ipsubnet(*args) + self.assertEqual(result, "5")