Change in vdsm[master]: net: Clean netinfo.__init__ and migrate to cache

edwardh at redhat.com edwardh at redhat.com
Tue Feb 2 20:54:07 UTC 2016


Edward Haas has uploaded a new change for review.

Change subject: net: Clean netinfo.__init__ and migrate to cache
......................................................................

net: Clean netinfo.__init__ and migrate to cache

When stand alone modules under the netinfo package are being used by other
modules, __init__ is being processed and cause import loops.
This patch migrates most __init__ content to cache.

Change-Id: I892bb86fe9a8580d9028ca7759d27967e55d85f7
Signed-off-by: Edward Haas <edwardh at redhat.com>
---
M debian/vdsm-python.install
M lib/vdsm/netinfo/Makefile.am
M lib/vdsm/netinfo/__init__.py
A lib/vdsm/netinfo/cache.py
M lib/vdsm/network/api.py
M lib/vdsm/network/configurators/dhclient.py
M lib/vdsm/network/configurators/ifcfg.py
M lib/vdsm/network/configurators/iproute2.py
M lib/vdsm/network/configurators/qos.py
M lib/vdsm/network/models.py
M lib/vdsm/tool/unified_persistence.py
M tests/configNetworkTests.py
M tests/functional/networkTests.py
M tests/functional/utils.py
M tests/netinfoTests.py
M tests/netmodelsTests.py
M vdsm.spec.in
M vdsm/caps.py
M vdsm/vdsm-restore-net-config
M vdsm_hooks/ovs/ovs_before_network_setup_ovs.py
20 files changed, 372 insertions(+), 341 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/53007/1

diff --git a/debian/vdsm-python.install b/debian/vdsm-python.install
index 9650d9d..e641d84 100644
--- a/debian/vdsm-python.install
+++ b/debian/vdsm-python.install
@@ -23,6 +23,7 @@
 ./usr/lib/python2.7/dist-packages/vdsm/netinfo/addresses.py
 ./usr/lib/python2.7/dist-packages/vdsm/netinfo/bonding.py
 ./usr/lib/python2.7/dist-packages/vdsm/netinfo/bridges.py
+./usr/lib/python2.7/dist-packages/vdsm/netinfo/cache.py
 ./usr/lib/python2.7/dist-packages/vdsm/netinfo/dhcp.py
 ./usr/lib/python2.7/dist-packages/vdsm/netinfo/dns.py
 ./usr/lib/python2.7/dist-packages/vdsm/netinfo/misc.py
diff --git a/lib/vdsm/netinfo/Makefile.am b/lib/vdsm/netinfo/Makefile.am
index bac2915..f757e14 100644
--- a/lib/vdsm/netinfo/Makefile.am
+++ b/lib/vdsm/netinfo/Makefile.am
@@ -25,6 +25,7 @@
 	addresses.py \
 	bonding.py \
 	bridges.py \
+	cache.py \
 	dhcp.py \
 	dns.py \
 	misc.py \
diff --git a/lib/vdsm/netinfo/__init__.py b/lib/vdsm/netinfo/__init__.py
index b73bea6..64a7d0b 100644
--- a/lib/vdsm/netinfo/__init__.py
+++ b/lib/vdsm/netinfo/__init__.py
@@ -18,165 +18,16 @@
 # Refer to the README and COPYING files for full details of the license
 #
 
-from __future__ import absolute_import
-from itertools import chain
-import logging
-import os
-import errno
-import six
+
 import xml.etree.cElementTree as etree
 
-from ..ipwrapper import getLinks, DUMMY_BRIDGE
+from ..ipwrapper import DUMMY_BRIDGE
 from .. import libvirtconnection
-from ..netconfpersistence import RunningConfig
-from ..netlink import link as nl_link
-
-from .addresses import getIpAddrs, getIpInfo
-from . import bonding
-from . import bridges
-from .dhcp import (get_dhclient_ifaces, propose_updates_to_reported_dhcp,
-                   update_reported_dhcp, dhcp_used)
-from .dns import get_host_nameservers
-from .misc import getIfaceCfg, ipv6_supported
-from .mtus import getMtu
-from . import nics
-from . import vlans
-from .routes import get_routes, get_gateway
-from .qos import report_network_qos
-
-
-NET_PATH = '/sys/class/net'
-
-LIBVIRT_NET_PREFIX = 'vdsm-'
 
 
 DUMMY_BRIDGE  # Appease flake8 since dummy bridge should be exported from here
 
-
-def _get(vdsmnets=None):
-    """
-    Generate a networking report for all devices, including data managed by
-    libvirt.
-    In case vdsmnets is provided, it is used in the report instead of
-    retrieving data from libvirt.
-    :return: Dict of networking devices with all their details.
-    """
-    networking = {'bondings': {}, 'bridges': {}, 'networks': {}, 'nics': {},
-                  'vlans': {}, 'dnss': get_host_nameservers()}
-    paddr = bonding.permanent_address()
-    ipaddrs = getIpAddrs()
-    dhcpv4_ifaces, dhcpv6_ifaces = get_dhclient_ifaces()
-    routes = get_routes()
-    running_config = RunningConfig()
-
-    if vdsmnets is None:
-        libvirt_nets = networks()
-        networking['networks'] = libvirtNets2vdsm(libvirt_nets, running_config,
-                                                  routes, ipaddrs,
-                                                  dhcpv4_ifaces, dhcpv6_ifaces)
-    else:
-        networking['networks'] = vdsmnets
-
-    for dev in (link for link in getLinks() if not link.isHidden()):
-        if dev.isBRIDGE():
-            devinfo = networking['bridges'][dev.name] = bridges.info(dev)
-        elif dev.isNICLike():
-            devinfo = networking['nics'][dev.name] = nics.info(dev, paddr)
-        elif dev.isBOND():
-            devinfo = networking['bondings'][dev.name] = bonding.info(dev)
-        elif dev.isVLAN():
-            devinfo = networking['vlans'][dev.name] = vlans.info(dev)
-        else:
-            continue
-        devinfo.update(_devinfo(dev, routes, ipaddrs, dhcpv4_ifaces,
-                                dhcpv6_ifaces))
-        if dev.isBOND():
-            bonding.bondOptsCompat(devinfo)
-
-    for network_name, network_info in six.iteritems(networking['networks']):
-        if network_info['bridged']:
-            network_info['cfg'] = networking['bridges'][network_name]['cfg']
-        updates = propose_updates_to_reported_dhcp(network_info, networking)
-        update_reported_dhcp(updates, networking)
-
-    report_network_qos(networking)
-    networking['supportsIPv6'] = ipv6_supported()
-
-    return networking
-
-
-def get(vdsmnets=None, compatibility=None):
-    if compatibility is None:
-        return _get(vdsmnets)
-    elif compatibility < 30700:
-        # REQUIRED_FOR engine < 3.7
-        return _stringify_mtus(_get(vdsmnets))
-
-    return _get(vdsmnets)
-
-
-def _stringify_mtus(netinfo_data):
-    for devtype in ('bondings', 'bridges', 'networks', 'nics', 'vlans'):
-        for dev in six.itervalues(netinfo_data[devtype]):
-            dev['mtu'] = str(dev['mtu'])
-    return netinfo_data
-
-
-def libvirtNets2vdsm(nets, running_config=None, routes=None, ipAddrs=None,
-                     dhcpv4_ifaces=None, dhcpv6_ifaces=None):
-    if running_config is None:
-        running_config = RunningConfig()
-    if routes is None:
-        routes = get_routes()
-    if ipAddrs is None:
-        ipAddrs = getIpAddrs()
-    if dhcpv4_ifaces is None or dhcpv6_ifaces is None:
-        dhcpv4_ifaces, dhcpv6_ifaces = get_dhclient_ifaces()
-    d = {}
-    for net, netAttr in nets.iteritems():
-        try:
-            # Pass the iface if the net is _not_ bridged, the bridge otherwise
-            d[net] = _getNetInfo(netAttr.get('iface', net), netAttr['bridged'],
-                                 routes, ipAddrs, dhcpv4_ifaces, dhcpv6_ifaces,
-                                 running_config.networks.get(net, None))
-        except KeyError:
-            continue  # Do not report missing libvirt networks.
-    return d
-
-
-def _devinfo(link, routes, ipaddrs, dhcpv4_ifaces, dhcpv6_ifaces):
-    gateway = get_gateway(routes, link.name)
-    ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(
-        link.name, ipaddrs, gateway)
-    info = {'addr': ipv4addr,
-            'cfg': getIfaceCfg(link.name),
-            'ipv4addrs': ipv4addrs,
-            'ipv6addrs': ipv6addrs,
-            'gateway': gateway,
-            'ipv6gateway': get_gateway(routes, link.name, family=6),
-            'dhcpv4': link.name in dhcpv4_ifaces,  # to be refined if a network
-            'dhcpv6': link.name in dhcpv6_ifaces,  # is not configured for DHCP
-            'mtu': link.mtu,
-            'netmask': ipv4netmask}
-    if 'BOOTPROTO' not in info['cfg']:
-        info['cfg']['BOOTPROTO'] = 'dhcp' if info['dhcpv4'] else 'none'
-    return info
-
-
-def ifaceUsed(iface):
-    """Lightweight implementation of bool(Netinfo.ifaceUsers()) that does not
-    require a NetInfo object."""
-    if os.path.exists(os.path.join(NET_PATH, iface, 'brport')):  # Is it a port
-        return True
-    for linkDict in nl_link.iter_links():
-        if linkDict['name'] == iface and 'master' in linkDict:  # Is it a slave
-            return True
-        if linkDict.get('device') == iface and linkDict.get('type') == 'vlan':
-            return True  # it backs a VLAN
-    for net_attr in six.itervalues(networks()):
-        if net_attr.get('iface') == iface:
-            return True
-    return False
+LIBVIRT_NET_PREFIX = 'vdsm-'
 
 
 def networks():
@@ -203,170 +54,4 @@
             else:
                 nets[netname]['bridge'] = xml.find('.//bridge').get('name')
                 nets[netname]['bridged'] = True
-    return nets
-
-
-def _getNetInfo(iface, bridged, routes, ipaddrs, dhcpv4_ifaces, dhcpv6_ifaces,
-                net_attrs):
-    """Returns a dictionary of properties about the network's interface status.
-    Raises a KeyError if the iface does not exist."""
-    data = {}
-    try:
-        if bridged:
-            data.update({'ports': bridges.ports(iface),
-                         'stp': bridges.stp_state(iface)})
-        else:
-            # ovirt-engine-3.1 expects to see the "interface" attribute iff the
-            # network is bridgeless. Please remove the attribute and this
-            # comment when the version is no longer supported.
-            data['interface'] = iface
-
-        gateway = get_gateway(routes, iface)
-        ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(
-            iface, ipaddrs, gateway)
-        data.update({'iface': iface, 'bridged': bridged,
-                     'addr': ipv4addr, 'netmask': ipv4netmask,
-                     'dhcpv4': dhcp_used(iface, dhcpv4_ifaces, net_attrs),
-                     'dhcpv6': dhcp_used(iface, dhcpv6_ifaces, net_attrs,
-                                         family=6),
-                     'ipv4addrs': ipv4addrs,
-                     'ipv6addrs': ipv6addrs,
-                     'gateway': gateway,
-                     'ipv6gateway': get_gateway(routes, iface, family=6),
-                     'mtu': getMtu(iface)})
-    except (IOError, OSError) as e:
-        if e.errno == errno.ENOENT:
-            logging.info('Obtaining info for net %s.', iface, exc_info=True)
-            raise KeyError('Network %s was not found' % iface)
-        else:
-            raise
-    return data
-
-
-class CachingNetInfo(object):
-    def __init__(self, _netinfo=None):
-        if _netinfo is None:
-            _netinfo = get()
-
-        self.networks = _netinfo['networks']
-        self.vlans = _netinfo['vlans']
-        self.nics = _netinfo['nics']
-        self.bondings = _netinfo['bondings']
-        self.bridges = _netinfo['bridges']
-
-    def updateDevices(self):
-        """Updates the object device information while keeping the cached
-        network information."""
-        _netinfo = get(vdsmnets=self.networks)
-        self.networks = _netinfo['networks']
-        self.vlans = _netinfo['vlans']
-        self.nics = _netinfo['nics']
-        self.bondings = _netinfo['bondings']
-        self.bridges = _netinfo['bridges']
-
-    def del_network(self, network):
-        del self.networks[network]
-
-    def del_bonding(self, bonding):
-        del self.bondings[bonding]
-
-    def getNetworksAndVlansForIface(self, iface):
-        """ Returns tuples of (bridge/network, vlan) connected to  nic/bond """
-        return chain(self._getBridgedNetworksAndVlansForIface(iface),
-                     self._getBridgelessNetworksAndVlansForIface(iface))
-
-    def _getBridgedNetworksAndVlansForIface(self, iface):
-        """ Returns tuples of (bridge, vlan) connected to nic/bond """
-        for network, netdict in self.networks.iteritems():
-            if netdict['bridged']:
-                for interface in netdict['ports']:
-                    if iface == interface:
-                        yield (network, None)
-                    elif interface.startswith(iface + '.'):
-                        yield (network, vlans.vlan_id(interface))
-
-    def _getBridgelessNetworksAndVlansForIface(self, iface):
-        """ Returns tuples of (network, vlan) connected to nic/bond """
-        for network, netdict in self.networks.iteritems():
-            if not netdict['bridged']:
-                if iface == netdict['iface']:
-                    yield (network, None)
-                elif netdict['iface'].startswith(iface + '.'):
-                    yield (network, vlans.vlan_id(netdict['iface']))
-
-    def getVlansForIface(self, iface):
-        for vlandict in six.itervalues(self.vlans):
-            if iface == vlandict['iface']:
-                yield vlandict['vlanid']
-
-    def getNetworkForIface(self, iface):
-        """ Return the network attached to nic/bond """
-        for network, netdict in self.networks.iteritems():
-            if ('ports' in netdict and iface in netdict['ports'] or
-                    'iface' in netdict and iface == netdict['iface']):
-                return network
-
-    def getBridgedNetworkForIface(self, iface):
-        """ Return all bridged networks attached to nic/bond """
-        for bridge, netdict in self.networks.iteritems():
-            if netdict['bridged'] and iface in netdict['ports']:
-                return bridge
-
-    def getNicsForBonding(self, bond):
-        bondAttrs = self.bondings[bond]
-        return bondAttrs['slaves']
-
-    def getBondingForNic(self, nic):
-        bondings = [b for (b, attrs) in self.bondings.iteritems() if
-                    nic in attrs['slaves']]
-        if bondings:
-            assert len(bondings) == 1, \
-                "Unexpected configuration: More than one bonding per nic"
-            return bondings[0]
-        return None
-
-    def getNicsVlanAndBondingForNetwork(self, network):
-        vlan = None
-        vlanid = None
-        bonding = None
-        lnics = []
-
-        if self.networks[network]['bridged']:
-            ports = self.networks[network]['ports']
-        else:
-            ports = []
-            interface = self.networks[network]['iface']
-            ports.append(interface)
-
-        for port in ports:
-            if port in self.vlans:
-                assert vlan is None
-                nic = vlans.vlan_device(port)
-                vlanid = vlans.vlan_id(port)
-                vlan = port  # vlan devices can have an arbitrary name
-                assert self.vlans[port]['iface'] == nic
-                port = nic
-            if port in self.bondings:
-                assert bonding is None
-                bonding = port
-                lnics += self.bondings[bonding]['slaves']
-            elif port in self.nics:
-                lnics.append(port)
-
-        return lnics, vlan, vlanid, bonding
-
-    def ifaceUsers(self, iface):
-        "Returns a list of entities using the interface"
-        users = set()
-        for n, ndict in self.networks.iteritems():
-            if ndict['bridged'] and iface in ndict['ports']:
-                users.add(n)
-            elif not ndict['bridged'] and iface == ndict['iface']:
-                users.add(n)
-        for b, bdict in self.bondings.iteritems():
-            if iface in bdict['slaves']:
-                users.add(b)
-        for v, vdict in self.vlans.iteritems():
-            if iface == vdict['iface']:
-                users.add(v)
-        return users
+    return nets
\ No newline at end of file
diff --git a/lib/vdsm/netinfo/cache.py b/lib/vdsm/netinfo/cache.py
new file mode 100644
index 0000000..467440b
--- /dev/null
+++ b/lib/vdsm/netinfo/cache.py
@@ -0,0 +1,339 @@
+#
+# Copyright 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+from __future__ import absolute_import
+from itertools import chain
+import logging
+import os
+import errno
+import six
+
+from ..ipwrapper import getLinks
+from ..netconfpersistence import RunningConfig
+from ..netlink import link as nl_link
+
+from vdsm import netinfo
+from .addresses import getIpAddrs, getIpInfo
+from . import bonding
+from . import bridges
+from .dhcp import (get_dhclient_ifaces, propose_updates_to_reported_dhcp,
+                   update_reported_dhcp, dhcp_used)
+from .dns import get_host_nameservers
+from .misc import getIfaceCfg, ipv6_supported
+from .mtus import getMtu
+from . import nics
+from . import vlans
+from .routes import get_routes, get_gateway
+from .qos import report_network_qos
+
+
+NET_PATH = '/sys/class/net'
+
+
+def _get(vdsmnets=None):
+    """
+    Generate a networking report for all devices, including data managed by
+    libvirt.
+    In case vdsmnets is provided, it is used in the report instead of
+    retrieving data from libvirt.
+    :return: Dict of networking devices with all their details.
+    """
+    networking = {'bondings': {}, 'bridges': {}, 'networks': {}, 'nics': {},
+                  'vlans': {}, 'dnss': get_host_nameservers()}
+    paddr = bonding.permanent_address()
+    ipaddrs = getIpAddrs()
+    dhcpv4_ifaces, dhcpv6_ifaces = get_dhclient_ifaces()
+    routes = get_routes()
+    running_config = RunningConfig()
+
+    if vdsmnets is None:
+        libvirt_nets = netinfo.networks()
+        networking['networks'] = libvirtNets2vdsm(libvirt_nets, running_config,
+                                                  routes, ipaddrs,
+                                                  dhcpv4_ifaces, dhcpv6_ifaces)
+    else:
+        networking['networks'] = vdsmnets
+
+    for dev in (link for link in getLinks() if not link.isHidden()):
+        if dev.isBRIDGE():
+            devinfo = networking['bridges'][dev.name] = bridges.info(dev)
+        elif dev.isNICLike():
+            devinfo = networking['nics'][dev.name] = nics.info(dev, paddr)
+        elif dev.isBOND():
+            devinfo = networking['bondings'][dev.name] = bonding.info(dev)
+        elif dev.isVLAN():
+            devinfo = networking['vlans'][dev.name] = vlans.info(dev)
+        else:
+            continue
+        devinfo.update(_devinfo(dev, routes, ipaddrs, dhcpv4_ifaces,
+                                dhcpv6_ifaces))
+        if dev.isBOND():
+            bonding.bondOptsCompat(devinfo)
+
+    for network_name, network_info in six.iteritems(networking['networks']):
+        if network_info['bridged']:
+            network_info['cfg'] = networking['bridges'][network_name]['cfg']
+        updates = propose_updates_to_reported_dhcp(network_info, networking)
+        update_reported_dhcp(updates, networking)
+
+    report_network_qos(networking)
+    networking['supportsIPv6'] = ipv6_supported()
+
+    return networking
+
+
+def get(vdsmnets=None, compatibility=None):
+    if compatibility is None:
+        return _get(vdsmnets)
+    elif compatibility < 30700:
+        # REQUIRED_FOR engine < 3.7
+        return _stringify_mtus(_get(vdsmnets))
+
+    return _get(vdsmnets)
+
+
+def _stringify_mtus(netinfo_data):
+    for devtype in ('bondings', 'bridges', 'networks', 'nics', 'vlans'):
+        for dev in six.itervalues(netinfo_data[devtype]):
+            dev['mtu'] = str(dev['mtu'])
+    return netinfo_data
+
+
+def libvirtNets2vdsm(nets, running_config=None, routes=None, ipAddrs=None,
+                     dhcpv4_ifaces=None, dhcpv6_ifaces=None):
+    if running_config is None:
+        running_config = RunningConfig()
+    if routes is None:
+        routes = get_routes()
+    if ipAddrs is None:
+        ipAddrs = getIpAddrs()
+    if dhcpv4_ifaces is None or dhcpv6_ifaces is None:
+        dhcpv4_ifaces, dhcpv6_ifaces = get_dhclient_ifaces()
+    d = {}
+    for net, netAttr in nets.iteritems():
+        try:
+            # Pass the iface if the net is _not_ bridged, the bridge otherwise
+            d[net] = _getNetInfo(netAttr.get('iface', net), netAttr['bridged'],
+                                 routes, ipAddrs, dhcpv4_ifaces, dhcpv6_ifaces,
+                                 running_config.networks.get(net, None))
+        except KeyError:
+            continue  # Do not report missing libvirt networks.
+    return d
+
+
+def _devinfo(link, routes, ipaddrs, dhcpv4_ifaces, dhcpv6_ifaces):
+    gateway = get_gateway(routes, link.name)
+    ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(
+        link.name, ipaddrs, gateway)
+    info = {'addr': ipv4addr,
+            'cfg': getIfaceCfg(link.name),
+            'ipv4addrs': ipv4addrs,
+            'ipv6addrs': ipv6addrs,
+            'gateway': gateway,
+            'ipv6gateway': get_gateway(routes, link.name, family=6),
+            'dhcpv4': link.name in dhcpv4_ifaces,  # to be refined if a network
+            'dhcpv6': link.name in dhcpv6_ifaces,  # is not configured for DHCP
+            'mtu': link.mtu,
+            'netmask': ipv4netmask}
+    if 'BOOTPROTO' not in info['cfg']:
+        info['cfg']['BOOTPROTO'] = 'dhcp' if info['dhcpv4'] else 'none'
+    return info
+
+
+def ifaceUsed(iface):
+    """Lightweight implementation of bool(Netinfo.ifaceUsers()) that does not
+    require a NetInfo object."""
+    if os.path.exists(os.path.join(NET_PATH, iface, 'brport')):  # Is it a port
+        return True
+    for linkDict in nl_link.iter_links():
+        if linkDict['name'] == iface and 'master' in linkDict:  # Is it a slave
+            return True
+        if linkDict.get('device') == iface and linkDict.get('type') == 'vlan':
+            return True  # it backs a VLAN
+    for net_attr in six.itervalues(netinfo.networks()):
+        if net_attr.get('iface') == iface:
+            return True
+    return False
+
+
+def _getNetInfo(iface, bridged, routes, ipaddrs, dhcpv4_ifaces, dhcpv6_ifaces,
+                net_attrs):
+    """Returns a dictionary of properties about the network's interface status.
+    Raises a KeyError if the iface does not exist."""
+    data = {}
+    try:
+        if bridged:
+            data.update({'ports': bridges.ports(iface),
+                         'stp': bridges.stp_state(iface)})
+        else:
+            # ovirt-engine-3.1 expects to see the "interface" attribute iff the
+            # network is bridgeless. Please remove the attribute and this
+            # comment when the version is no longer supported.
+            data['interface'] = iface
+
+        gateway = get_gateway(routes, iface)
+        ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = getIpInfo(
+            iface, ipaddrs, gateway)
+        data.update({'iface': iface, 'bridged': bridged,
+                     'addr': ipv4addr, 'netmask': ipv4netmask,
+                     'dhcpv4': dhcp_used(iface, dhcpv4_ifaces, net_attrs),
+                     'dhcpv6': dhcp_used(iface, dhcpv6_ifaces, net_attrs,
+                                         family=6),
+                     'ipv4addrs': ipv4addrs,
+                     'ipv6addrs': ipv6addrs,
+                     'gateway': gateway,
+                     'ipv6gateway': get_gateway(routes, iface, family=6),
+                     'mtu': getMtu(iface)})
+    except (IOError, OSError) as e:
+        if e.errno == errno.ENOENT:
+            logging.info('Obtaining info for net %s.', iface, exc_info=True)
+            raise KeyError('Network %s was not found' % iface)
+        else:
+            raise
+    return data
+
+
+class CachingNetInfo(object):
+    def __init__(self, _netinfo=None):
+        if _netinfo is None:
+            _netinfo = get()
+
+        self.networks = _netinfo['networks']
+        self.vlans = _netinfo['vlans']
+        self.nics = _netinfo['nics']
+        self.bondings = _netinfo['bondings']
+        self.bridges = _netinfo['bridges']
+
+    def updateDevices(self):
+        """Updates the object device information while keeping the cached
+        network information."""
+        _netinfo = get(vdsmnets=self.networks)
+        self.networks = _netinfo['networks']
+        self.vlans = _netinfo['vlans']
+        self.nics = _netinfo['nics']
+        self.bondings = _netinfo['bondings']
+        self.bridges = _netinfo['bridges']
+
+    def del_network(self, network):
+        del self.networks[network]
+
+    def del_bonding(self, bonding):
+        del self.bondings[bonding]
+
+    def getNetworksAndVlansForIface(self, iface):
+        """ Returns tuples of (bridge/network, vlan) connected to  nic/bond """
+        return chain(self._getBridgedNetworksAndVlansForIface(iface),
+                     self._getBridgelessNetworksAndVlansForIface(iface))
+
+    def _getBridgedNetworksAndVlansForIface(self, iface):
+        """ Returns tuples of (bridge, vlan) connected to nic/bond """
+        for network, netdict in self.networks.iteritems():
+            if netdict['bridged']:
+                for interface in netdict['ports']:
+                    if iface == interface:
+                        yield (network, None)
+                    elif interface.startswith(iface + '.'):
+                        yield (network, vlans.vlan_id(interface))
+
+    def _getBridgelessNetworksAndVlansForIface(self, iface):
+        """ Returns tuples of (network, vlan) connected to nic/bond """
+        for network, netdict in self.networks.iteritems():
+            if not netdict['bridged']:
+                if iface == netdict['iface']:
+                    yield (network, None)
+                elif netdict['iface'].startswith(iface + '.'):
+                    yield (network, vlans.vlan_id(netdict['iface']))
+
+    def getVlansForIface(self, iface):
+        for vlandict in six.itervalues(self.vlans):
+            if iface == vlandict['iface']:
+                yield vlandict['vlanid']
+
+    def getNetworkForIface(self, iface):
+        """ Return the network attached to nic/bond """
+        for network, netdict in self.networks.iteritems():
+            if ('ports' in netdict and iface in netdict['ports'] or
+                    'iface' in netdict and iface == netdict['iface']):
+                return network
+
+    def getBridgedNetworkForIface(self, iface):
+        """ Return all bridged networks attached to nic/bond """
+        for bridge, netdict in self.networks.iteritems():
+            if netdict['bridged'] and iface in netdict['ports']:
+                return bridge
+
+    def getNicsForBonding(self, bond):
+        bondAttrs = self.bondings[bond]
+        return bondAttrs['slaves']
+
+    def getBondingForNic(self, nic):
+        bondings = [b for (b, attrs) in self.bondings.iteritems() if
+                    nic in attrs['slaves']]
+        if bondings:
+            assert len(bondings) == 1, \
+                "Unexpected configuration: More than one bonding per nic"
+            return bondings[0]
+        return None
+
+    def getNicsVlanAndBondingForNetwork(self, network):
+        vlan = None
+        vlanid = None
+        bonding = None
+        lnics = []
+
+        if self.networks[network]['bridged']:
+            ports = self.networks[network]['ports']
+        else:
+            ports = []
+            interface = self.networks[network]['iface']
+            ports.append(interface)
+
+        for port in ports:
+            if port in self.vlans:
+                assert vlan is None
+                nic = vlans.vlan_device(port)
+                vlanid = vlans.vlan_id(port)
+                vlan = port  # vlan devices can have an arbitrary name
+                assert self.vlans[port]['iface'] == nic
+                port = nic
+            if port in self.bondings:
+                assert bonding is None
+                bonding = port
+                lnics += self.bondings[bonding]['slaves']
+            elif port in self.nics:
+                lnics.append(port)
+
+        return lnics, vlan, vlanid, bonding
+
+    def ifaceUsers(self, iface):
+        "Returns a list of entities using the interface"
+        users = set()
+        for n, ndict in self.networks.iteritems():
+            if ndict['bridged'] and iface in ndict['ports']:
+                users.add(n)
+            elif not ndict['bridged'] and iface == ndict['iface']:
+                users.add(n)
+        for b, bdict in self.bondings.iteritems():
+            if iface in bdict['slaves']:
+                users.add(b)
+        for v, vdict in self.vlans.iteritems():
+            if iface == vdict['iface']:
+                users.add(v)
+        return users
diff --git a/lib/vdsm/network/api.py b/lib/vdsm/network/api.py
index 7c5d1a4..381f6a5 100755
--- a/lib/vdsm/network/api.py
+++ b/lib/vdsm/network/api.py
@@ -34,10 +34,10 @@
 from vdsm import hooks
 from vdsm import kernelconfig
 from vdsm import netconfpersistence
-from vdsm.netinfo import (addresses, libvirtNets2vdsm, bridges,
-                          get as netinfo_get, CachingNetInfo, mtus,
-                          networks as netinfo_networks, nics as netinfo_nics,
-                          NET_PATH)
+from vdsm.netinfo import (addresses, bridges, mtus, nics as netinfo_nics,
+                          networks as netinfo_networks)
+from vdsm.netinfo.cache import (libvirtNets2vdsm, get as netinfo_get,
+                                CachingNetInfo, NET_PATH)
 from vdsm import udevadm
 from vdsm import utils
 from vdsm import ipwrapper
diff --git a/lib/vdsm/network/configurators/dhclient.py b/lib/vdsm/network/configurators/dhclient.py
index 3e8f1fc..f74116e 100644
--- a/lib/vdsm/network/configurators/dhclient.py
+++ b/lib/vdsm/network/configurators/dhclient.py
@@ -55,7 +55,7 @@
 
     def _dhclient(self):
         # Ask dhclient to stop any dhclient running for the device
-        if os.path.exists(os.path.join(netinfo.NET_PATH, self.iface)):
+        if os.path.exists(os.path.join(netinfo.cache.NET_PATH, self.iface)):
             kill_dhclient(self.iface, self.family)
         cmd = [self.DHCLIENT.cmd, '-%s' % self.family, '-1', '-pf',
                self.pidFile, '-lf', self.leaseFile, self.iface]
diff --git a/lib/vdsm/network/configurators/ifcfg.py b/lib/vdsm/network/configurators/ifcfg.py
index 69e1d68..5c29288 100644
--- a/lib/vdsm/network/configurators/ifcfg.py
+++ b/lib/vdsm/network/configurators/ifcfg.py
@@ -41,8 +41,8 @@
 from vdsm import dsaversion
 from vdsm import hooks
 from vdsm import ipwrapper
-from vdsm.netinfo import (bonding as netinfo_bonding, mtus, nics, vlans,
-                          ifaceUsed, NET_PATH, misc)
+from vdsm.netinfo import (bonding as netinfo_bonding, mtus, nics, vlans, misc)
+from vdsm.netinfo.cache import (ifaceUsed, NET_PATH)
 from vdsm import sysctl
 from vdsm import utils
 from vdsm.netconfpersistence import RunningConfig, PersistentConfig
diff --git a/lib/vdsm/network/configurators/iproute2.py b/lib/vdsm/network/configurators/iproute2.py
index df48314..ba652bd 100644
--- a/lib/vdsm/network/configurators/iproute2.py
+++ b/lib/vdsm/network/configurators/iproute2.py
@@ -20,8 +20,8 @@
 from __future__ import absolute_import
 import logging
 
-from vdsm.netinfo import bonding, ifaceUsed, vlans, bridges, mtus
-from vdsm.netinfo import misc
+from vdsm.netinfo import bonding, vlans, bridges, mtus, misc
+from vdsm.netinfo.cache import ifaceUsed
 from vdsm import ipwrapper
 from vdsm.constants import EXT_BRCTL
 from vdsm.ipwrapper import routeAdd, routeDel, ruleAdd, ruleDel, IPRoute2Error
diff --git a/lib/vdsm/network/configurators/qos.py b/lib/vdsm/network/configurators/qos.py
index 303aa8e..73f0e3b 100644
--- a/lib/vdsm/network/configurators/qos.py
+++ b/lib/vdsm/network/configurators/qos.py
@@ -21,7 +21,7 @@
 import os
 from distutils.version import StrictVersion
 
-from vdsm.netinfo import ifaceUsed
+from vdsm.netinfo.cache import ifaceUsed
 from vdsm.netinfo import qos as netinfo_qos
 from vdsm import tc
 
diff --git a/lib/vdsm/network/models.py b/lib/vdsm/network/models.py
index a5609fd..79c9216 100644
--- a/lib/vdsm/network/models.py
+++ b/lib/vdsm/network/models.py
@@ -22,7 +22,8 @@
 import socket
 import struct
 
-from vdsm.netinfo import bonding, ifaceUsed, mtus, nics, CachingNetInfo
+from vdsm.netinfo import bonding, mtus, nics
+from vdsm.netinfo.cache import ifaceUsed, CachingNetInfo
 
 from .errors import ConfigNetworkError
 from . import errors as ne
diff --git a/lib/vdsm/tool/unified_persistence.py b/lib/vdsm/tool/unified_persistence.py
index 1975f9c..01358ba 100644
--- a/lib/vdsm/tool/unified_persistence.py
+++ b/lib/vdsm/tool/unified_persistence.py
@@ -23,7 +23,7 @@
 from .. import utils
 from ..config import config
 from ..netconfpersistence import RunningConfig
-from ..netinfo import CachingNetInfo
+from ..netinfo.cache import CachingNetInfo
 from ..netinfo import misc, routes
 from . import expose
 from .upgrade import apply_upgrade
diff --git a/tests/configNetworkTests.py b/tests/configNetworkTests.py
index fb0cd6f..646efe2 100644
--- a/tests/configNetworkTests.py
+++ b/tests/configNetworkTests.py
@@ -96,7 +96,7 @@
             'bondings': {'bond00': {'slaves': ['eth5', 'eth6']}}
         }
 
-        fakeInfo = netinfo.CachingNetInfo(_netinfo)
+        fakeInfo = netinfo.cache.CachingNetInfo(_netinfo)
         nics = ['eth2']
 
         # Test for already existing bridge.
@@ -165,7 +165,7 @@
             api._buildBondOptions('jamesbond', {}, _netinfo=FakeNetInfo())
         self.assertEquals(cne.exception.errCode, errors.ERR_BAD_PARAMS)
 
-    @MonkeyPatch(netinfo, 'CachingNetInfo', lambda: None)
+    @MonkeyPatch(netinfo.cache, 'CachingNetInfo', lambda: None)
     def testValidateNetSetupRemoveParamValidation(self):
         attrs = dict(nic='dummy', remove=True,
                      bridged=True)
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index 3bfba16..9431eb3 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -408,7 +408,7 @@
 
     def _assert_kernel_config_matches_running_config(self):
         bare_kernel_config = kernelconfig.KernelConfig(
-            vdsm.netinfo.CachingNetInfo())
+            vdsm.netinfo.cache.CachingNetInfo())
         bare_running_config = self.vdsm_net.config
         normalized_running_config = kernelconfig.normalize(bare_running_config)
         # Unify strings to unicode instances so differences are easier to
diff --git a/tests/functional/utils.py b/tests/functional/utils.py
index 021af3a..1e13ef6 100644
--- a/tests/functional/utils.py
+++ b/tests/functional/utils.py
@@ -123,7 +123,7 @@
     def _get_netinfo(self):
         response = self.getVdsCapabilities()
         try:
-            return netinfo.CachingNetInfo(response[2])
+            return netinfo.cache.CachingNetInfo(response[2])
         except IndexError:
             raise Exception('VdsProxy: getVdsCapabilities failed. '
                             'code:%s msg:%s' % (response[0], response[1]))
diff --git a/tests/netinfoTests.py b/tests/netinfoTests.py
index c506674..46b914b 100644
--- a/tests/netinfoTests.py
+++ b/tests/netinfoTests.py
@@ -27,7 +27,8 @@
 
 from vdsm import ipwrapper
 from vdsm import netinfo
-from vdsm.netinfo import addresses, bonding, dns, dhcp, misc, nics, routes, get
+from vdsm.netinfo import addresses, bonding, dns, dhcp, misc, nics, routes
+from vdsm.netinfo.cache import get
 from vdsm.netlink import addr as nl_addr
 from vdsm.utils import random_iface_name
 
@@ -118,7 +119,7 @@
         # it should.
         get()
 
-    @MonkeyPatch(netinfo, 'getLinks', lambda: [])
+    @MonkeyPatch(netinfo.cache, 'getLinks', lambda: [])
     @MonkeyPatch(netinfo, 'networks', lambda: {})
     def testGetEmpty(self):
         result = {}
diff --git a/tests/netmodelsTests.py b/tests/netmodelsTests.py
index 00f1254..ce0b008 100644
--- a/tests/netmodelsTests.py
+++ b/tests/netmodelsTests.py
@@ -21,7 +21,8 @@
 #
 import os
 
-from vdsm.netinfo import bonding, mtus, CachingNetInfo
+from vdsm.netinfo import bonding, mtus
+from vdsm.netinfo.cache import CachingNetInfo
 from vdsm.network import errors
 from vdsm.network.models import Bond, Bridge, IPv4, IPv6, Nic, Vlan
 from vdsm.network.models import hierarchy_backing_device, hierarchy_vlan_tag
diff --git a/vdsm.spec.in b/vdsm.spec.in
index c394d72..636585d 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1104,6 +1104,7 @@
 %{python_sitelib}/%{vdsm_name}/netinfo/addresses.py*
 %{python_sitelib}/%{vdsm_name}/netinfo/bonding.py*
 %{python_sitelib}/%{vdsm_name}/netinfo/bridges.py*
+%{python_sitelib}/%{vdsm_name}/netinfo/cache.py*
 %{python_sitelib}/%{vdsm_name}/netinfo/dhcp.py*
 %{python_sitelib}/%{vdsm_name}/netinfo/dns.py*
 %{python_sitelib}/%{vdsm_name}/netinfo/misc.py*
diff --git a/vdsm/caps.py b/vdsm/caps.py
index 828d83c..de1018d 100644
--- a/vdsm/caps.py
+++ b/vdsm/caps.py
@@ -545,7 +545,7 @@
     caps.update(_getVersionInfo())
 
     # TODO: Version requests by engine to ease handling of compatibility.
-    netinfo_data = netinfo.get(compatibility=30600)
+    netinfo_data = netinfo.cache.get(compatibility=30600)
     caps.update(netinfo_data)
 
     try:
diff --git a/vdsm/vdsm-restore-net-config b/vdsm/vdsm-restore-net-config
index dd230e3..858ab1c 100755
--- a/vdsm/vdsm-restore-net-config
+++ b/vdsm/vdsm-restore-net-config
@@ -30,7 +30,8 @@
 
 from vdsm.config import config
 from vdsm import ipwrapper
-from vdsm.netinfo import nics, misc, CachingNetInfo
+from vdsm.netinfo import nics, misc
+from vdsm.netinfo.cache import CachingNetInfo
 from vdsm import kernelconfig
 from vdsm.constants import P_VDSM_RUN
 from vdsm.netconfpersistence import RunningConfig, PersistentConfig, \
diff --git a/vdsm_hooks/ovs/ovs_before_network_setup_ovs.py b/vdsm_hooks/ovs/ovs_before_network_setup_ovs.py
index c8a9238..cee8df9 100644
--- a/vdsm_hooks/ovs/ovs_before_network_setup_ovs.py
+++ b/vdsm_hooks/ovs/ovs_before_network_setup_ovs.py
@@ -21,7 +21,7 @@
 
 import six
 
-from vdsm.netinfo import CachingNetInfo
+from vdsm.netinfo.cache import CachingNetInfo
 from vdsm.network.configurators import libvirt
 
 import hooking


-- 
To view, visit https://gerrit.ovirt.org/53007
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I892bb86fe9a8580d9028ca7759d27967e55d85f7
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Edward Haas <edwardh at redhat.com>


More information about the vdsm-patches mailing list