Fix bugs in Ipaddr filters (#149)

Fix bugs in Ipaddr filters

SUMMARY

ipaddr - Fix input validation issues in ipaddr,ipv4,ipv6,ipwrap filters.
ipaddr - Add valid network for link-local
fixes: #148
fixes: ansible-collections/ansible.netcommon#375
fixes: ansible-collections/ansible.netcommon#350

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME

ADDITIONAL INFORMATION

Reviewed-by: Nilashish Chakraborty <nilashishchakraborty8@gmail.com>
Reviewed-by: Sagar Paul <sagpaul@redhat.com>
pull/150/head
Ashwini Mhatre 2022-03-04 17:13:59 +05:30 committed by GitHub
parent 74ee10cdd6
commit 0716010fe3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 174 additions and 73 deletions

View File

@ -10,8 +10,8 @@ The Ansible ``ansible.utils`` collection includes a variety of plugins that aid
This collection has been tested against following Ansible versions: **>=2.9.10**. This collection has been tested against following Ansible versions: **>=2.9.10**.
For collections that support Ansible 2.9, please ensure you update your `network_os` to use the For collections that support Ansible 2.9, please ensure you update your `network_os` to use the
fully qualified collection name (for example, `cisco.ios.ios`). fully qualified collection name (for example, `cisco.ios.ios`).
Plugins and modules within a collection may be tested with only specific Ansible versions. Plugins and modules within a collection may be tested with only specific Ansible versions.
A collection may contain metadata that identifies these versions. A collection may contain metadata that identifies these versions.
PEP440 is the schema used to describe the versions of Ansible. PEP440 is the schema used to describe the versions of Ansible.

View File

@ -0,0 +1,5 @@
---
bugfixes:
- Fix issue in ipaddr,ipv4,ipv6,ipwrap filters.(https://github.com/ansible-collections/ansible.utils/issues/148).
- ipaddr - Fix issue of breaking ipaddr filter with netcommon 2.6.0(https://github.com/ansible-collections/ansible.netcommon/issues/375).
- ipaddr - Add valid network for link-local (https://github.com/ansible-collections/ansible.netcommon/issues/350).

View File

@ -159,7 +159,7 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">-</span> <span style="color: purple">raw</span>
</div> </div>
</td> </td>
<td></td> <td></td>

View File

@ -78,8 +78,7 @@ Parameters
<b>value</b> <b>value</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
/ <span style="color: red">required</span> / <span style="color: red">required</span>
</div> </div>
</td> </td>
@ -302,13 +301,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns values valid for a particular query.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -166,13 +166,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">string</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns result of IP math/arithmetic.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -280,13 +280,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns values valid for a particular query.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -59,8 +59,7 @@ Parameters
<b>value</b> <b>value</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
/ <span style="color: red">required</span> / <span style="color: red">required</span>
</div> </div>
</td> </td>
@ -156,13 +155,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns values valid for a particular query.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -59,8 +59,7 @@ Parameters
<b>value</b> <b>value</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
/ <span style="color: red">required</span> / <span style="color: red">required</span>
</div> </div>
</td> </td>
@ -172,13 +171,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns values valid for a particular query.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -60,8 +60,7 @@ Parameters
<b>value</b> <b>value</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
/ <span style="color: red">required</span> / <span style="color: red">required</span>
</div> </div>
</td> </td>
@ -170,13 +169,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">raw</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns values valid for a particular query.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -126,13 +126,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">string</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns the next nth usable ip within a network described by value.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -125,13 +125,12 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
<b>data</b> <b>data</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small"> <div style="font-size: small">
<span style="color: purple">list</span> <span style="color: purple">string</span>
/ <span style="color: purple">elements=string</span>
</div> </div>
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns list with values valid for a particular query.</div> <div>Returns the previous nth usable ip within a network described by value.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -118,7 +118,7 @@ Common return values are documented `here <https://docs.ansible.com/ansible/late
</td> </td>
<td></td> <td></td>
<td> <td>
<div>Returns nth host from network</div> <div>Returns the SLAAC address within a network for a given HW/MAC address.</div>
<br/> <br/>
</td> </td>
</tr> </tr>

View File

@ -120,6 +120,7 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: raw
description: description:
- Returns a minified list of subnets or a single subnet that spans all of the inputs. - Returns a minified list of subnets or a single subnet that spans all of the inputs.
""" """

View File

@ -13,6 +13,7 @@ from ansible_collections.ansible.utils.plugins.plugin_utils.base.ipaddr_utils im
_need_netaddr, _need_netaddr,
) )
from ansible.errors import AnsibleFilterError from ansible.errors import AnsibleFilterError
from ansible.errors import AnsibleError
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
AnsibleArgSpecValidator, AnsibleArgSpecValidator,
) )
@ -51,8 +52,7 @@ DOCUMENTATION = """
value: value:
description: description:
- list of subnets or individual address or any other values input for ipaddr plugin - list of subnets or individual address or any other values input for ipaddr plugin
type: list type: raw
elements: str
required: True required: True
query: query:
description: description:
@ -240,10 +240,9 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: list type: raw
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns values valid for a particular query.
""" """
@ -253,6 +252,25 @@ def _ipaddr(*args, **kwargs):
keys = ["value", "query", "version", "alias"] keys = ["value", "query", "version", "alias"]
data = dict(zip(keys, args[1:])) data = dict(zip(keys, args[1:]))
data.update(kwargs) data.update(kwargs)
try:
if isinstance(data["value"], str):
pass
elif isinstance(data["value"], list):
pass
else:
raise AnsibleError(
"Unrecognized type <{0}> for ipaddr filter <{1}>".format(
type(data["value"]), "value"
)
)
except (TypeError, ValueError):
raise AnsibleError(
"Unrecognized type <{0}> for ipaddr filter <{1}>".format(
type(data["value"]), "value"
)
)
aav = AnsibleArgSpecValidator( aav = AnsibleArgSpecValidator(
data=data, schema=DOCUMENTATION, name="ipaddr" data=data, schema=DOCUMENTATION, name="ipaddr"
) )

View File

@ -127,10 +127,9 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: list type: str
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns result of IP math/arithmetic.
""" """

View File

@ -231,10 +231,9 @@ tasks:
RETURN = """ RETURN = """
data: data:
type: list type: raw
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns values valid for a particular query.
""" """

View File

@ -13,6 +13,7 @@ from ansible_collections.ansible.utils.plugins.plugin_utils.base.ipaddr_utils im
_need_netaddr, _need_netaddr,
) )
from ansible.errors import AnsibleFilterError from ansible.errors import AnsibleFilterError
from ansible.errors import AnsibleError
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
AnsibleArgSpecValidator, AnsibleArgSpecValidator,
) )
@ -48,8 +49,7 @@ DOCUMENTATION = """
value: value:
description: description:
- list of subnets or individual address or any other values input for ipv4 plugin - list of subnets or individual address or any other values input for ipv4 plugin
type: list type: raw
elements: str
required: True required: True
query: query:
description: description:
@ -118,10 +118,9 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: list type: raw
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns values valid for a particular query.
""" """
@ -131,6 +130,24 @@ def _ipv4(*args, **kwargs):
keys = ["value", "query"] keys = ["value", "query"]
data = dict(zip(keys, args[1:])) data = dict(zip(keys, args[1:]))
data.update(kwargs) data.update(kwargs)
try:
if isinstance(data["value"], str):
pass
elif isinstance(data["value"], list):
pass
else:
raise AnsibleError(
"Unrecognized type <{0}> for ipv4 filter <{1}>".format(
type(data["value"]), "value"
)
)
except (TypeError, ValueError):
raise AnsibleError(
"Unrecognized type <{0}> for ipv4 filter <{1}>".format(
type(data["value"]), "value"
)
)
aav = AnsibleArgSpecValidator(data=data, schema=DOCUMENTATION, name="ipv4") aav = AnsibleArgSpecValidator(data=data, schema=DOCUMENTATION, name="ipv4")
valid, errors, updated_data = aav.validate() valid, errors, updated_data = aav.validate()
if not valid: if not valid:

View File

@ -13,6 +13,7 @@ from ansible_collections.ansible.utils.plugins.plugin_utils.base.ipaddr_utils im
_need_netaddr, _need_netaddr,
) )
from ansible.errors import AnsibleFilterError from ansible.errors import AnsibleFilterError
from ansible.errors import AnsibleError
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
AnsibleArgSpecValidator, AnsibleArgSpecValidator,
) )
@ -50,8 +51,7 @@ DOCUMENTATION = """
value: value:
description: description:
- list of subnets or individual address or any other values input for ipv6 plugin - list of subnets or individual address or any other values input for ipv6 plugin
type: list type: raw
elements: str
required: True required: True
query: query:
description: description:
@ -136,10 +136,9 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: list type: raw
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns values valid for a particular query.
""" """
@ -149,6 +148,24 @@ def _ipv6(*args, **kwargs):
keys = ["value", "query"] keys = ["value", "query"]
data = dict(zip(keys, args[1:])) data = dict(zip(keys, args[1:]))
data.update(kwargs) data.update(kwargs)
try:
if isinstance(data["value"], str):
pass
elif isinstance(data["value"], list):
pass
else:
raise AnsibleError(
"Unrecognized type <{0}> for ipv6 filter <{1}>".format(
type(data["value"]), "value"
)
)
except (TypeError, ValueError):
raise AnsibleError(
"Unrecognized type <{0}> for ipv6 filter <{1}>".format(
type(data["value"]), "value"
)
)
aav = AnsibleArgSpecValidator(data=data, schema=DOCUMENTATION, name="ipv6") aav = AnsibleArgSpecValidator(data=data, schema=DOCUMENTATION, name="ipv6")
valid, errors, updated_data = aav.validate() valid, errors, updated_data = aav.validate()
if not valid: if not valid:

View File

@ -14,6 +14,7 @@ from ansible_collections.ansible.utils.plugins.plugin_utils.base.ipaddr_utils im
_need_netaddr, _need_netaddr,
) )
from ansible.errors import AnsibleFilterError from ansible.errors import AnsibleFilterError
from ansible.errors import AnsibleError
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
AnsibleArgSpecValidator, AnsibleArgSpecValidator,
) )
@ -53,8 +54,7 @@ DOCUMENTATION = """
description: description:
- list of subnets or individual address or any other values input. Example. ['192.24.2.1', 'host.fqdn', - list of subnets or individual address or any other values input. Example. ['192.24.2.1', 'host.fqdn',
'::1', '192.168.32.0/24', 'fe80::100/10', True, '', '42540766412265424405338506004571095040/64'] '::1', '192.168.32.0/24', 'fe80::100/10', True, '', '42540766412265424405338506004571095040/64']
type: list type: raw
elements: str
required: True required: True
query: query:
description: description:
@ -136,10 +136,9 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: list type: raw
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns values valid for a particular query.
""" """
@ -149,6 +148,26 @@ def _ipwrap(*args, **kwargs):
keys = ["value"] keys = ["value"]
data = dict(zip(keys, args[1:])) data = dict(zip(keys, args[1:]))
data.update(kwargs) data.update(kwargs)
try:
if isinstance(data["value"], str):
pass
elif isinstance(data["value"], list):
pass
elif isinstance(data["value"], bool):
pass
else:
raise AnsibleError(
"Unrecognized type <{0}> for ipwrap filter <{1}>".format(
type(data["value"]), "value"
)
)
except (TypeError, ValueError):
raise AnsibleError(
"Unrecognized type <{0}> for ipwrap filter <{1}>".format(
type(data["value"]), "value"
)
)
aav = AnsibleArgSpecValidator( aav = AnsibleArgSpecValidator(
data=data, schema=DOCUMENTATION, name="ipwrap" data=data, schema=DOCUMENTATION, name="ipwrap"
) )

View File

@ -91,10 +91,9 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: list type: str
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns the next nth usable ip within a network described by value.
""" """

View File

@ -90,10 +90,9 @@ EXAMPLES = r"""
RETURN = """ RETURN = """
data: data:
type: list type: str
elements: str
description: description:
- Returns list with values valid for a particular query. - Returns the previous nth usable ip within a network described by value.
""" """

View File

@ -79,7 +79,7 @@ RETURN = """
data: data:
type: str type: str
description: description:
- Returns nth host from network - Returns the SLAAC address within a network for a given HW/MAC address.
""" """

View File

@ -199,7 +199,7 @@ def _last_usable_query(v, vtype):
def _link_local_query(v, value): def _link_local_query(v, value):
v_ip = netaddr.IPAddress(str(v.ip)) v_ip = netaddr.IPAddress(str(v.ip))
if v.version == 4: if v.version == 4:
if ipaddr(str(v_ip), "169.254.0.0/24"): if ipaddr(str(v_ip), "169.254.0.0/16"):
return value return value
elif v.version == 6: elif v.version == 6:

View File

@ -42,3 +42,19 @@
- name: Assert result for ipaddr network query - name: Assert result for ipaddr network query
assert: assert:
that: "{{ result4 == ipaddr_result4 }}" that: "{{ result4 == ipaddr_result4 }}"
- name: ipaddr filter with network/prefix query
ansible.builtin.set_fact:
result5: "{{ '192.168.0.0/23' | ansible.utils.ipaddr('network/prefix') }}"
- name: Assert result for ipaddr filter with network/prefix query
assert:
that: "{{ result5 == '192.168.0.0/23' }}"
- name: ipaddr filter with chained filters
ansible.builtin.set_fact:
result6: "{{ '192.168.255.0' | ansible.utils.ipaddr('network') | ansible.utils.ipmath(123) }}"
- name: Assert result for ipaddr filter with chained filters
assert:
that: "{{ result6 == '192.168.255.123' }}"

View File

@ -33,3 +33,11 @@
- name: Assert result for ipv4 filter with address query. - name: Assert result for ipv4 filter with address query.
assert: assert:
that: "{{ result3 == result3_val }}" that: "{{ result3 == result3_val }}"
- name: ipv4 filter with single value
ansible.builtin.set_fact:
result4: "{{ '192.24.2.1' | ansible.utils.ipv4('ipv6') }}"
- name: Assert result for ipv4 filter with single value
assert:
that: "{{ result4 == '::ffff:192.24.2.1/128' }}"

View File

@ -33,3 +33,11 @@
- name: Assert result for ipv6 filter with address query. - name: Assert result for ipv6 filter with address query.
assert: assert:
that: "{{ result3 == ipv6_result3 }}" that: "{{ result3 == ipv6_result3 }}"
- name: ipv6 filter with single value
ansible.builtin.set_fact:
result4: "{{ '::ffff:192.168.32.0/120' | ansible.utils.ipv6('ipv4') }}"
- name: Assert result for ipv6 filter with single value
assert:
that: "{{ result4 == '192.168.32.0/24' }}"

View File

@ -17,3 +17,11 @@
- name: Assert result for ipwrap. - name: Assert result for ipwrap.
assert: assert:
that: "{{ result1 == ipwrap_result1 }}" that: "{{ result1 == ipwrap_result1 }}"
- name: ipwrap filter with single value
ansible.builtin.set_fact:
result4: "{{ 'fe80::100/10' | ansible.utils.ipwrap }}"
- name: Assert result for ipv6 filter with single value
assert:
that: "{{ result4 == '[fe80::100]/10' }}"

View File

@ -39,7 +39,7 @@ ipwrap_result1:
- "192.168.32.0/24" - "192.168.32.0/24"
- "[fe80::100]/10" - "[fe80::100]/10"
- "[2001:db8:32c:faad::]/64" - "[2001:db8:32c:faad::]/64"
- "True" - True
ipv6_result1: ipv6_result1:
- "::ffff:192.168.32.0/120" - "::ffff:192.168.32.0/120"

View File

@ -35,7 +35,7 @@ VALID_OUTPUT = [
"192.168.32.0/24", "192.168.32.0/24",
"[fe80::100]/10", "[fe80::100]/10",
"[2001:db8:32c:faad::]/64", "[2001:db8:32c:faad::]/64",
"True", True,
] ]
@ -55,4 +55,4 @@ class TestIpWrap(unittest.TestCase):
args = ["", "::1", ""] args = ["", "::1", ""]
result = _ipwrap(*args) result = _ipwrap(*args)
self.assertEqual(result, ["[::1]"]) self.assertEqual(result, "[::1]")