Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding an option for the filter ipsubnet and testing #40670

Merged
merged 27 commits into from
Aug 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
887005e
adding an option for the filter ipsubnet
pierremahot May 24, 2018
5928839
merge
pierremahot Aug 11, 2018
e111430
reabasing
pierremahot Aug 11, 2018
95d5d3f
reabasing
pierremahot Aug 11, 2018
1104eee
reabasing
pierremahot Aug 11, 2018
bd38c23
correct tests and do str(query) only once
pierremahot May 25, 2018
875448b
make the @webknjaz recommandation
pierremahot May 29, 2018
9cb115c
correction of the enumerate start
pierremahot May 29, 2018
194843a
update testing and adding negative tests
pierremahot Jun 7, 2018
e355e9a
missing line at end of file
pierremahot Jun 7, 2018
244b46d
reabasing
pierremahot Aug 11, 2018
77f0810
import ipsubnet after rebase
pierremahot Aug 11, 2018
699ffbc
forgeted comma
pierremahot Aug 11, 2018
9692847
update test false input
pierremahot Aug 11, 2018
ca9f709
rmake the validated test
pierremahot Aug 11, 2018
74bdbb9
update documentation, adding documentation exemple to thet tests and …
pierremahot Aug 11, 2018
e9b9cce
remove useless space and move import to better place
pierremahot Aug 11, 2018
eb2db56
adding NETADDR_ERRORS variable all times
pierremahot Aug 12, 2018
0deee6c
adding quote
pierremahot Aug 14, 2018
498191c
add re-raising exception chain as webknjaz tell
pierremahot Aug 14, 2018
b6a199a
adding exception test
pierremahot Aug 14, 2018
30cf9b1
testing assertion
pierremahot Aug 14, 2018
1ed1326
no raise possible
pierremahot Aug 14, 2018
6e6bf9a
update test and code
pierremahot Aug 14, 2018
87fb43a
raise error when out of subnet or wrong subnet input
pierremahot Aug 14, 2018
7e8090e
update doc for raising error
pierremahot Aug 14, 2018
a8f4872
use asserRaisesRegexp
pierremahot Aug 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/docsite/rst/user_guide/playbooks_filters_ipaddr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,28 @@ smaller subnets::
# {{ address | ipsubnet(18, -5) }}
192.168.144.0/27

By specifying an other subnet as a second argument, if the second subnet include
the first you can have the rank of the first subnet in the second ::

# The rank of the ip in the subnet (the ip is the 36870nth /32 of the subnet)
# {{ address | ipsubnet(subnet) }}
36870

# The rank in the /24 that contain the address
# {{ address | ipsubnet('192.168.144.0/24') }}
6

# An IP with the subnet in the first /30 in a /24
# {{ '192.168.144.1/30' | ipsubnet('192.168.144.0/24') }}
1

# The fifth subnet /30 in a /24
# {{ '192.168.144.16/30' | ipsubnet('192.168.144.0/24') }}
5

If the secound subnet doesn't include the first it raise an error


You can use ``ipsubnet()`` filter with ``ipaddr()`` filter to for example split
given ``/48`` prefix into smaller, ``/64`` subnets::

Expand Down
23 changes: 21 additions & 2 deletions lib/ansible/plugins/filter/ipaddr.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from functools import partial
import types
from ansible.module_utils import six

This comment was marked as resolved.

try:
import netaddr
Expand Down Expand Up @@ -736,6 +737,9 @@ def ipv6(value, query=''):
#
# - address | ipsubnet(cidr, index)
# returns next indexed subnet which contains given address
#
# - address/prefix | ipsubnet(subnet/prefix)
# return the index of the subnet in the subnet
def ipsubnet(value, query='', index='x'):
''' Manipulate IPv4/IPv6 subnets '''

Expand All @@ -749,11 +753,11 @@ def ipsubnet(value, query='', index='x'):
value = netaddr.IPNetwork(v)
except:
return False

query_string = str(query)
if not query:
return str(value)

elif str(query).isdigit():
elif query_string.isdigit():
vsize = ipaddr(v, 'size')
query = int(query)

Expand Down Expand Up @@ -786,6 +790,21 @@ def ipsubnet(value, query='', index='x'):
except:
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 errors.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 errors.AnsibleFilterError(msg)
return False


Expand Down
43 changes: 42 additions & 1 deletion test/units/plugins/filter/test_ipaddr.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from ansible.compat.tests import unittest
from ansible.errors import AnsibleFilterError
from ansible.plugins.filter.ipaddr import (ipaddr, _netmask_query, nthhost, next_nth_usable,
from ansible.plugins.filter.ipaddr import (ipaddr, _netmask_query, nthhost, next_nth_usable, ipsubnet,
previous_nth_usable, network_in_usable, network_in_network,
cidr_merge, ipmath)
netaddr = pytest.importorskip('netaddr')
Expand Down Expand Up @@ -502,3 +502,44 @@ def test_ipmath(self):
with self.assertRaises(AnsibleFilterError) as exc:
ipmath('1.2.3.4', 'some_number')
self.assertEqual(exc.exception.message, expected)

def test_ipsubnet(self):
test_cases = (
(('1.1.1.1/24', '30'), '64'),
(('1.1.1.1/25', '24'), '0'),
(('1.12.1.34/32', '1.12.1.34/24'), '35'),
(('192.168.50.0/24', '192.168.0.0/16'), '51'),
(('192.168.144.5', '192.168.0.0/16'), '36870'),
(('192.168.144.5', '192.168.144.5/24'), '6'),
(('192.168.144.5/32', '192.168.144.0/24'), '6'),
(('192.168.144.16/30', '192.168.144.0/24'), '5'),
(('192.168.144.5', ), '192.168.144.5/32'),
(('192.168.0.0/16', ), '192.168.0.0/16'),
(('192.168.144.5', ), '192.168.144.5/32'),
(('192.168.0.0/16', '20'), '16'),
(('192.168.0.0/16', '20', '0'), '192.168.0.0/20'),
(('192.168.0.0/16', '20', '-1'), '192.168.240.0/20'),
(('192.168.0.0/16', '20', '5'), '192.168.80.0/20'),
(('192.168.0.0/16', '20', '-5'), '192.168.176.0/20'),
(('192.168.144.5', '20'), '192.168.144.0/20'),
(('192.168.144.5', '18', '0'), '192.168.128.0/18'),
(('192.168.144.5', '18', '-1'), '192.168.144.4/31'),
(('192.168.144.5', '18', '5'), '192.168.144.0/23'),
(('192.168.144.5', '18', '-5'), '192.168.144.0/27'),
(('span', 'test', 'error'), False),
(('test', ), False),
(('192.168.144.5', '500000', '-5'), False),
(('192.168.144.5', '18', '500000'), False),
(('200000', '18', '-5'), '0.3.13.64/27'),
)
for args, res in test_cases:
self._test_ipsubnet(args, res)

def _test_ipsubnet(self, ipsubnet_args, expected_result):
self.assertEqual(ipsubnet(*ipsubnet_args), expected_result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also add some test cases with assertRaises

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think

vtype = ipaddr(query, 'type')
        if vtype == 'address':
            v = ipaddr(query, 'cidr')
        elif vtype == 'network':
            v = ipaddr(query, 'subnet')
        else:
            return False

Can't raise error on :

query = netaddr.IPNetwork(v)
for i, subnet in enumerate(query.subnet(value.prefixlen), 1)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't find the case

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could mock.patch it to do so :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, look out for netaddr docs for the cases when it'll raise the exception.


with self.assertRaisesRegexp(AnsibleFilterError, 'You must pass a valid subnet or IP address; invalid_subnet is invalid'):
ipsubnet('192.168.144.5', 'invalid_subnet')

with self.assertRaisesRegexp(AnsibleFilterError, '192.168.144.0/30 is not in the subnet 192.168.144.4/30'):
ipsubnet('192.168.144.1/30', '192.168.144.5/30')