Merge lp:~niedbalski/charm-helpers/lp1671861 into lp:charm-helpers

Proposed by Jorge Niedbalski
Status: Merged
Merged at revision: 713
Proposed branch: lp:~niedbalski/charm-helpers/lp1671861
Merge into: lp:charm-helpers
Diff against target: 106 lines (+47/-16)
2 files modified
charmhelpers/contrib/network/ip.py (+32/-16)
tests/contrib/network/test_ip.py (+15/-0)
To merge this branch: bzr merge lp:~niedbalski/charm-helpers/lp1671861
Reviewer Review Type Date Requested Status
Felipe Reyes (community) Approve
Review via email: mp+319595@code.launchpad.net

Description of the change

Fix required for solving LP: #1671861.

- Extends the get_address_in_network function
to use a prefix when the netmask comes in the 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff::/128' format.

- Link-local and loopback addresses are skipped
- Added tests to validate the change.

To post a comment you must log in.
714. By Jorge Niedbalski

Additional fix

715. By Jorge Niedbalski

Additional fixes to the _get_address_from_network function

Revision history for this message
Felipe Reyes (freyes) wrote :

the tests are OK, and the code looks code to me.

I tested the code against my local ipv6 address and does the right thing detecting them.

Revision history for this message
Felipe Reyes (freyes) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmhelpers/contrib/network/ip.py'
2--- charmhelpers/contrib/network/ip.py 2017-03-06 23:51:06 +0000
3+++ charmhelpers/contrib/network/ip.py 2017-03-10 18:27:45 +0000
4@@ -67,6 +67,24 @@
5 raise ValueError(errmsg)
6
7
8+def _get_ipv6_network_from_address(address):
9+ """Get an netaddr.IPNetwork for the given IPv6 address
10+ :param address: a dict as returned by netifaces.ifaddresses
11+ :returns netaddr.IPNetwork: None if the address is a link local or loopback
12+ address
13+ """
14+ if address['addr'].startswith('fe80') or address['addr'] == "::1":
15+ return None
16+
17+ prefix = address['netmask'].split("/")
18+ if len(prefix) > 1:
19+ netmask = prefix[1]
20+ else:
21+ netmask = address['netmask']
22+ return netaddr.IPNetwork("%s/%s" % (address['addr'],
23+ netmask))
24+
25+
26 def get_address_in_network(network, fallback=None, fatal=False):
27 """Get an IPv4 or IPv6 address within the network from the host.
28
29@@ -100,11 +118,9 @@
30
31 if network.version == 6 and netifaces.AF_INET6 in addresses:
32 for addr in addresses[netifaces.AF_INET6]:
33- if not addr['addr'].startswith('fe80'):
34- cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
35- addr['netmask']))
36- if cidr in network:
37- return str(cidr.ip)
38+ cidr = _get_ipv6_network_from_address(addr)
39+ if cidr and cidr in network:
40+ return str(cidr.ip)
41
42 if fallback is not None:
43 return fallback
44@@ -180,18 +196,18 @@
45
46 if address.version == 6 and netifaces.AF_INET6 in addresses:
47 for addr in addresses[netifaces.AF_INET6]:
48- if not addr['addr'].startswith('fe80'):
49- network = netaddr.IPNetwork("%s/%s" % (addr['addr'],
50- addr['netmask']))
51- cidr = network.cidr
52- if address in cidr:
53- if key == 'iface':
54- return iface
55- elif key == 'netmask' and cidr:
56- return str(cidr).split('/')[1]
57- else:
58- return addr[key]
59+ network = _get_ipv6_network_from_address(addr)
60+ if not network:
61+ continue
62
63+ cidr = network.cidr
64+ if address in cidr:
65+ if key == 'iface':
66+ return iface
67+ elif key == 'netmask' and cidr:
68+ return str(cidr).split('/')[1]
69+ else:
70+ return addr[key]
71 return None
72
73
74
75=== modified file 'tests/contrib/network/test_ip.py'
76--- tests/contrib/network/test_ip.py 2017-03-06 23:51:06 +0000
77+++ tests/contrib/network/test_ip.py 2017-03-10 18:27:45 +0000
78@@ -34,6 +34,8 @@
79 'netmask': 'ffff:ffff:ffff:ffff::'},
80 {'addr': 'fe80::3e97:eff:fe8b:1cf7%eth0',
81 'netmask': 'ffff:ffff:ffff:ffff::'},
82+ {'netmask': 'ffff:ffff:ffff:ffff::/64',
83+ 'addr': 'fd2d:dec4:cf59:3c16::1'},
84 {'addr': '2001:db8:1::',
85 'netmask': 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'}],
86 17: [{'addr': '3c:97:0e:8b:1c:f7',
87@@ -214,6 +216,19 @@
88 def test_get_address_in_network_not_found_not_fatal(self):
89 self._test_get_address_in_network(None, '172.16.0.0/16', fatal=False)
90
91+ @patch.object(netifaces, 'ifaddresses')
92+ @patch.object(netifaces, 'interfaces')
93+ def test_get_address_in_network_netmask(self, _interfaces, _ifaddresses):
94+ """
95+ Validates that get_address_in_network works with a netmask
96+ that uses the format 'ffff:ffff:ffff::/prefixlen'
97+ """
98+ _interfaces.return_value = DUMMY_ADDRESSES.keys()
99+ _ifaddresses.side_effect = DUMMY_ADDRESSES.__getitem__
100+ self._test_get_address_in_network('fd2d:dec4:cf59:3c16::1',
101+ 'fd2d:dec4:cf59:3c16::/64',
102+ fatal=False)
103+
104 def test_is_address_in_network(self):
105 self.assertTrue(
106 net_ip.is_address_in_network(

Subscribers

People subscribed via source and target branches