ac7d03
From 8d88b50c3f79e054a039d123fdaf6aa3a5339135 Mon Sep 17 00:00:00 2001
ac7d03
From: Martin Basti <mbasti@redhat.com>
ac7d03
Date: Wed, 14 Jun 2017 14:47:23 +0200
ac7d03
Subject: [PATCH] refactor CheckedIPAddress class
ac7d03
ac7d03
Make methods without side effects (setting mask)
ac7d03
ac7d03
https://pagure.io/freeipa/issue/4317
ac7d03
ac7d03
Reviewed-By: David Kupka <dkupka@redhat.com>
ac7d03
---
ac7d03
 ipapython/ipautil.py | 29 ++++++++++++++++++++++-------
ac7d03
 1 file changed, 22 insertions(+), 7 deletions(-)
ac7d03
ac7d03
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
ac7d03
index 647ee833ae33f246de6d6b13703fac6e20eef7bc..2c020e3ecbf4d8b969511a6dd9b36ee955ba1f15 100644
ac7d03
--- a/ipapython/ipautil.py
ac7d03
+++ b/ipapython/ipautil.py
ac7d03
@@ -62,6 +62,12 @@ PROTOCOL_NAMES = {
ac7d03
     socket.SOCK_DGRAM: 'udp'
ac7d03
 }
ac7d03
 
ac7d03
+InterfaceDetails = collections.namedtuple(
ac7d03
+    'InterfaceDetails', [
ac7d03
+        'name',  # interface name
ac7d03
+        'ifnet'  # network details of interface
ac7d03
+    ])
ac7d03
+
ac7d03
 
ac7d03
 class UnsafeIPAddress(netaddr.IPAddress):
ac7d03
     """Any valid IP address with or without netmask."""
ac7d03
@@ -161,9 +167,12 @@ class CheckedIPAddress(UnsafeIPAddress):
ac7d03
             raise ValueError("cannot use multicast IP address {}".format(addr))
ac7d03
 
ac7d03
         if match_local:
ac7d03
-            if not self.get_matching_interface():
ac7d03
+            intf_details = self.get_matching_interface()
ac7d03
+            if not intf_details:
ac7d03
                 raise ValueError('no network interface matches the IP address '
ac7d03
                                  'and netmask {}'.format(addr))
ac7d03
+            else:
ac7d03
+                self.set_ip_net(intf_details.ifnet)
ac7d03
 
ac7d03
         if self._net is None:
ac7d03
             if self.version == 4:
ac7d03
@@ -193,7 +202,8 @@ class CheckedIPAddress(UnsafeIPAddress):
ac7d03
 
ac7d03
     def get_matching_interface(self):
ac7d03
         """Find matching local interface for address
ac7d03
-        :return: Interface name or None if no interface has this address
ac7d03
+        :return: InterfaceDetails named tuple or None if no interface has
ac7d03
+        this address
ac7d03
         """
ac7d03
         if self.version == 4:
ac7d03
             family = netifaces.AF_INET
ac7d03
@@ -204,7 +214,6 @@ class CheckedIPAddress(UnsafeIPAddress):
ac7d03
                 "Unsupported address family ({})".format(self.version)
ac7d03
             )
ac7d03
 
ac7d03
-        iface = None
ac7d03
         for interface in netifaces.interfaces():
ac7d03
             for ifdata in netifaces.ifaddresses(interface).get(family, []):
ac7d03
 
ac7d03
@@ -218,11 +227,17 @@ class CheckedIPAddress(UnsafeIPAddress):
ac7d03
                 ))
ac7d03
 
ac7d03
                 if ifnet.ip == self:
ac7d03
-                    iface = interface
ac7d03
-                    self._net = ifnet
ac7d03
-                    break
ac7d03
+                    return InterfaceDetails(interface, ifnet)
ac7d03
 
ac7d03
-        return iface
ac7d03
+    def set_ip_net(self, ifnet):
ac7d03
+        """Set IP Network details for this address. IPNetwork is valid only
ac7d03
+        locally, so this should be set only for local IP addresses
ac7d03
+
ac7d03
+        :param ifnet: netaddr.IPNetwork object with information about IP
ac7d03
+        network where particula address belongs locally
ac7d03
+        """
ac7d03
+        assert isinstance(ifnet, netaddr.IPNetwork)
ac7d03
+        self._net = ifnet
ac7d03
 
ac7d03
 
ac7d03
 def valid_ip(addr):
ac7d03
-- 
ac7d03
2.9.4
ac7d03