diff --git a/README.md b/README.md index 41a986d0..c8a6a0b1 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Name | Description [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.ipv4](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.ipv4_filter.rst)|To filter only Ipv4 addresses Ipv4 filter is used. [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.ipv6form](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.ipv6form_filter.rst)|This filter is designed to convert ipv6 address in different formats. For example expand, compressetc. [ansible.utils.ipwrap](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.ipwrap_filter.rst)|This filter is designed to Wrap IPv6 addresses in [ ] brackets. [ansible.utils.keep_keys](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.keep_keys_filter.rst)|Keep specific keys from a data recursively. [ansible.utils.macaddr](https://github.com/ansible-collections/ansible.utils/blob/main/docs/ansible.utils.macaddr_filter.rst)|macaddr / MAC address filters diff --git a/changelogs/fragments/ipv6form.yaml b/changelogs/fragments/ipv6form.yaml new file mode 100644 index 00000000..4f90b167 --- /dev/null +++ b/changelogs/fragments/ipv6form.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add ipv6form filter plugin.(https://github.com/ansible-collections/ansible.utils/issues/230) diff --git a/docs/ansible.utils.ipv6form_filter.rst b/docs/ansible.utils.ipv6form_filter.rst new file mode 100644 index 00000000..824f3188 --- /dev/null +++ b/docs/ansible.utils.ipv6form_filter.rst @@ -0,0 +1,165 @@ +.. _ansible.utils.ipv6form_filter: + + +********************** +ansible.utils.ipv6form +********************** + +**This filter is designed to convert ipv6 address in different formats. For example expand, compressetc.** + + +Version added: 2.11.0 + +.. contents:: + :local: + :depth: 1 + + +Synopsis +-------- +- This filter is designed to convert ipv6 addresses in different formats. + + + + +Parameters +---------- + +.. raw:: html + + + + + + + + + + + + + + + + + + + + +
ParameterChoices/DefaultsConfigurationComments
+
+ format + +
+ string +
+
+ + +
Different formats example. compress, expand, x509
+
+
+ value + +
+ string + / required +
+
+ + +
individual ipv6 address input for ipv6_format plugin.
+
+
+ + + + +Examples +-------- + +.. code-block:: yaml + + #### examples + # Ipv6form filter plugin with different format. + - name: Expand given Ipv6 address + debug: + msg: "{{ '1234:4321:abcd:dcba::17' | ansible.utils.ipv6form('expand') }}" + + - name: Compress given Ipv6 address + debug: + msg: "{{ '1234:4321:abcd:dcba:0000:0000:0000:0017' | ansible.utils.ipv6form('compress') }}" + + - name: Covert given Ipv6 address in x509 + debug: + msg: "{{ '1234:4321:abcd:dcba::17' | ansible.utils.ipv6form('x509') }}" + + # TASK [Expand given Ipv6 address] ************************************************************************************ + # task path: /home/amhatre/dev/playbook/test_ipform.yaml:7 + # Loading collection ansible.utils from /home/amhatre/dev/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "1234:4321:abcd:dcba:0000:0000:0000:0017" + # } + + # TASK [Compress given Ipv6 address] ********************************************************************************* + # task path: /home/amhatre/dev/playbook/test_ipform.yaml:11 + # Loading collection ansible.utils from /home/amhatre/dev/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "1234:4321:abcd:dcba::17" + # } + + # TASK [Covert given Ipv6 address in x509] **************************************************************************** + # task path: /home/amhatre/dev/playbook/test_ipform.yaml:15 + # Loading collection ansible.utils from /home/amhatre/dev/collections/ansible_collections/ansible/utils + # ok: [localhost] => { + # "msg": "1234:4321:abcd:dcba:0:0:0:17" + # } + + # PLAY RECAP ********************************************************************************************************** + # localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 + + + +Return Values +------------- +Common return values are documented `here `_, the following are the fields unique to this filter: + +.. raw:: html + + + + + + + + + + + + +
KeyReturnedDescription
+
+ data + +
+ string +
+
+
Returns result ipv6 address in expected format.
+
+
+

+ + +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/ipv6form.py b/plugins/filter/ipv6form.py new file mode 100644 index 00000000..66ea5482 --- /dev/null +++ b/plugins/filter/ipv6form.py @@ -0,0 +1,176 @@ +# -*- 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: ipv6form +""" +from __future__ import absolute_import, division, print_function + +from functools import partial + +from ansible.errors import AnsibleFilterError + +from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( + AnsibleArgSpecValidator, +) +from ansible_collections.ansible.utils.plugins.plugin_utils.base.ipaddr_utils import _need_netaddr +from ansible_collections.ansible.utils.plugins.plugin_utils.base.ipaddress_utils import ( + _need_ipaddress, + ip_address, +) + + +__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: ipv6form + author: Ashwini Mhatre (@amhatre) + version_added: "2.11.0" + short_description: This filter is designed to convert ipv6 address in different formats. For example expand, compressetc. + description: + - This filter is designed to convert ipv6 addresses in different formats. + options: + value: + description: + - individual ipv6 address input for ipv6_format plugin. + type: str + required: True + format: + type: str + choice: + ['compress', 'expand', 'x509'] + description: Different formats example. compress, expand, x509 +""" + +EXAMPLES = r""" +#### examples +# Ipv6form filter plugin with different format. +- name: Expand given Ipv6 address + debug: + msg: "{{ '1234:4321:abcd:dcba::17' | ansible.utils.ipv6form('expand') }}" + +- name: Compress given Ipv6 address + debug: + msg: "{{ '1234:4321:abcd:dcba:0000:0000:0000:0017' | ansible.utils.ipv6form('compress') }}" + +- name: Covert given Ipv6 address in x509 + debug: + msg: "{{ '1234:4321:abcd:dcba::17' | ansible.utils.ipv6form('x509') }}" + +# TASK [Expand given Ipv6 address] ************************************************************************************ +# task path: /home/amhatre/dev/playbook/test_ipform.yaml:7 +# Loading collection ansible.utils from /home/amhatre/dev/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "1234:4321:abcd:dcba:0000:0000:0000:0017" +# } + +# TASK [Compress given Ipv6 address] ********************************************************************************* +# task path: /home/amhatre/dev/playbook/test_ipform.yaml:11 +# Loading collection ansible.utils from /home/amhatre/dev/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "1234:4321:abcd:dcba::17" +# } + +# TASK [Covert given Ipv6 address in x509] **************************************************************************** +# task path: /home/amhatre/dev/playbook/test_ipform.yaml:15 +# Loading collection ansible.utils from /home/amhatre/dev/collections/ansible_collections/ansible/utils +# ok: [localhost] => { +# "msg": "1234:4321:abcd:dcba:0:0:0:17" +# } + +# PLAY RECAP ********************************************************************************************************** +# localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 + + +""" + +RETURN = """ + data: + type: str + description: + - Returns result ipv6 address in expected format. +""" + + +@pass_environment +def _ipv6form(*args, **kwargs): + """Convert the given data from json to xml.""" + keys = ["value", "format"] + data = dict(zip(keys, args[1:])) + data.update(kwargs) + aav = AnsibleArgSpecValidator(data=data, schema=DOCUMENTATION, name="ipv6form") + valid, errors, updated_data = aav.validate() + if not valid: + raise AnsibleFilterError(errors) + return ipv6form(**updated_data) + + +@_need_ipaddress +def ipv6form(value, format): + try: + if format == "expand": + return ip_address(value).exploded + elif format == "compress": + return ip_address(value).compressed + elif format == "x509": + return _handle_x509(value) + except ValueError: + msg = "You must pass a valid IP address; {0} is invalid".format(value) + raise AnsibleFilterError(msg) + + if not isinstance(format, str): + msg = ("You must pass valid format; " "{0} is not a valid format").format( + format, + ) + raise AnsibleFilterError(msg) + + +def _handle_x509(value): + """Convert ipv6 address into x509 format""" + ip = netaddr.IPAddress(value) + ipv6_oct = [] + ipv6address = ip.bits().split(":") + for i in ipv6address: + x = hex(int(i, 2)) + ipv6_oct.append(x.replace("0x", "")) + return str(":".join(ipv6_oct)) + + +class FilterModule(object): + """IP address and network manipulation filters""" + + filter_map = { + # This filter is designed to do ipv6 conversion in required format + "ipv6form": _ipv6form, + } + + def filters(self): + """ipv6form 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/ipv6form.yaml b/tests/integration/targets/utils_ipaddr_filter/tasks/ipv6form.yaml new file mode 100644 index 00000000..a5ad87fd --- /dev/null +++ b/tests/integration/targets/utils_ipaddr_filter/tasks/ipv6form.yaml @@ -0,0 +1,32 @@ +--- +- name: Expand ipv6 address + ansible.builtin.set_fact: + result1: "{{ '1234:4321:abcd:dcba::17'|ansible.utils.ipv6form ('expand')}}" + +- name: Assert result for ipv6form. + ansible.builtin.assert: + that: "{{ result1 == '1234:4321:abcd:dcba:0000:0000:0000:0017' }}" + +- name: Compress ipv6 address + ansible.builtin.set_fact: + result1: "{{ '1234:4321:abcd:dcba:0000:0000:0000:0017'|ansible.utils.ipv6form ('compress') }}" + +- name: Assert result for ipv6form. + ansible.builtin.assert: + that: "{{ result1 == '1234:4321:abcd:dcba::17' }}" + +- name: Convert ipv6 address into x509 form used by digital certificate + ansible.builtin.set_fact: + result1: "{{ '1234:4321:abcd:dcba::17'|ansible.utils.ipv6form ('x509') }}" + +- name: Assert result for ipv6form. + ansible.builtin.assert: + that: "{{ result1 == '1234:4321:abcd:dcba:0:0:0:17' }}" + +- name: Convert ipv6 address into x509 form used by digital certificate + ansible.builtin.set_fact: + result1: "{{ '1234:4321:abcd:dcba:0000:0000:0000:0017'|ansible.utils.ipv6form ('x509') }}" + +- name: Assert result for ipv6form. + ansible.builtin.assert: + that: "{{ result1 == '1234:4321:abcd:dcba:0:0:0:17' }}" diff --git a/tests/unit/plugins/filter/test_ipv6form.py b/tests/unit/plugins/filter/test_ipv6form.py new file mode 100644 index 00000000..b094d555 --- /dev/null +++ b/tests/unit/plugins/filter/test_ipv6form.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +Unit test file for ipcut filter plugin +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import unittest + +from ansible_collections.ansible.utils.plugins.filter.ipv6form import _ipv6form + + +class TestIpv6Form(unittest.TestCase): + def setUp(self): + pass + + def test_expand(self): + """Expand given ipv6 address""" + + args = ["", "1234:4321:abcd:dcba::17", "expand"] + result = _ipv6form(*args) + self.assertEqual(result, "1234:4321:abcd:dcba:0000:0000:0000:0017") + + def test_compress(self): + """Compress given ipv6 address""" + + args = ["", "1234:4321:abcd:dcba:0000:0000:0000:0017", "compress"] + result = _ipv6form(*args) + self.assertEqual(result, "1234:4321:abcd:dcba::17") + + def test_x509(self): + """Compress given ipv6 address into x509 form""" + + args = ["", "1234:4321:abcd:dcba::17", "x509"] + result = _ipv6form(*args) + self.assertEqual(result, "1234:4321:abcd:dcba:0:0:0:17")