Mark Wu has uploaded a new change for review. Change subject: WIP: refactor configNetwork ......................................................................
WIP: refactor configNetwork Change-Id: I66710fdf8fd73beb06124f72ef9857df7393a602 Signed-off-by: Mark Wu <[email protected]> --- M vdsm/configNetwork.py 1 file changed, 324 insertions(+), 288 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/14/7714/1 diff --git a/vdsm/configNetwork.py b/vdsm/configNetwork.py index 74d19c7..a4675db 100755 --- a/vdsm/configNetwork.py +++ b/vdsm/configNetwork.py @@ -817,120 +817,6 @@ else: _validateInterNetworkCompatibility(_netinfo, vlan, nic, bridged) -def addNetwork(network, vlan=None, bonding=None, nics=None, ipaddr=None, - netmask=None, mtu=None, gateway=None, force=False, - configWriter=None, bondingOptions=None, bridged=True, **options): - nics = nics or () - _netinfo = netinfo.NetInfo() - bridged = utils.tobool(bridged) - - if mtu: - mtu = int(mtu) - - # Validation - if not utils.tobool(force): - logging.debug('validating network...') - _addNetworkValidation(_netinfo, network=network, - vlan=vlan, bonding=bonding, nics=nics, ipaddr=ipaddr, - netmask=netmask, gateway=gateway, bondingOptions=bondingOptions, - bridged=bridged, **options) - - logging.info("Adding network %s with vlan=%s, bonding=%s, nics=%s," - " bondingOptions=%s, mtu=%s, bridged=%s, options=%s", - network, vlan, bonding, nics, bondingOptions, - mtu, bridged, options) - - if configWriter is None: - configWriter = ConfigWriter() - - prevmtu = None - if mtu: - prevmtu = configWriter.getMaxMtu(nics, mtu) - - nic = nics[0] if nics else None - iface = bonding or nic - - # take down nics that need to be changed - vlanedIfaces = [v['iface'] for v in _netinfo.vlans.values()] - if bonding not in vlanedIfaces: - for nic in nics: - if nic not in vlanedIfaces: - ifdown(nic) - - if bridged: - configWriter.addBridge(network, ipaddr=ipaddr, netmask=netmask, - mtu=mtu, gateway=gateway, **options) - ifdown(network) - # We need to define (if requested) ip, mask & gateway on ifcfg-* - # only on most top device according to following order: - # bridge -> vlan -> bond -> nic - # For lower level devices we should ignore it. - # reset ip, netmask, gateway for lower level devices - ipaddr = netmask = gateway = None - - # For VLAN we should attach bridge only to the VLAN device - # rather than to underlying NICs or bond - brName = network if bridged else None - bridgeForNic = None if vlan else brName - - # We want to create config files (ifcfg-*) in top-down order - # (bridge->vlan->bond->nic) to be able to handle IP/NETMASK - # correctly for bridgeless networks - if vlan: - # don't ifup VLAN interface here, it should be done last, - # after the bond and nic up - configWriter.addVlan(vlan, iface, network=brName, - mtu=mtu, bridged=bridged, - ipaddr=ipaddr, netmask=netmask, - gateway=gateway, **options) - iface += '.' + vlan - # reset ip, netmask, gateway for lower level devices - ipaddr = netmask = gateway = None - - # First we need to prepare all conf files - if bonding: - configWriter.addBonding(bonding, bridge=bridgeForNic, - bondingOptions=bondingOptions, - mtu=max(prevmtu, mtu), - ipaddr=ipaddr, netmask=netmask, - gateway=gateway, **options) - # reset ip, netmask, gateway for lower level devices - ipaddr = netmask = gateway = None - - for nic in nics: - configWriter.addNic(nic, bonding=bonding, - bridge=bridgeForNic if not bonding else None, - mtu=max(prevmtu, mtu), - ipaddr=ipaddr, netmask=netmask, - gateway=gateway, **options) - - # Now we can run ifup for all interfaces - if bonding: - ifup(bonding) - - # NICs must be activated in the same order of boot time - # to expose the correct MAC address. - for nic in nicSort(nics): - ifup(nic) - - # Now we can ifup VLAN interface, because bond and nic already up - if vlan: - ifup(iface) - - if bridged: - if options.get('bootproto') == 'dhcp' and \ - not utils.tobool(options.get('blockingdhcp')): - # wait for dhcp in another thread, - # so vdsm won't get stuck (BZ#498940) - t = threading.Thread(target=ifup, name='ifup-waiting-on-dhcp', - args=(network,)) - t.daemon = True - t.start() - else: - ifup(network) - - # add libvirt network - configWriter.createLibvirtNetwork(network, bridged, iface) def assertBridgeClean(bridge, vlan, bonding, nics): brifs = os.listdir('/sys/class/net/%s/brif/' % bridge) @@ -950,6 +836,324 @@ if brifs: raise ConfigNetworkError(ne.ERR_USED_BRIDGE, 'bridge %s has interfaces %s connected' % (bridge, brifs)) + + +class Configurator(object): + + def addNetwork(self, network, vlan=None, bonding=None, nics=None, + ipaddr=None, netmask=None, mtu=None, gateway=None, + force=False, bondingOptions=None, bridged=True, **options): + pass + + def delNetwork(self, network, vlan=None, bonding=None, nics=None, + force=False, implicitBonding=True, **options): + pass + + def editNetwork(self, oldBridge, newBridge, vlan=None, bonding=None, + nics=None, **options): + pass + +class NativeConfigurator(Configurator): + + def __init__(self): + self.confiWriter = ConfigWriter() + + def addNetwork(self, network, vlan=None, bonding=None, nics=None, + ipaddr=None, netmask=None, mtu=None, gateway=None, + force=False, bondingOptions=None, bridged=True, **options): + nics = nics or () + _netinfo = netinfo.NetInfo() + bridged = utils.tobool(bridged) + + if mtu: + mtu = int(mtu) + + # Validation + if not utils.tobool(force): + logging.debug('validating network...') + _addNetworkValidation(_netinfo, network=network, + vlan=vlan, bonding=bonding, nics=nics, ipaddr=ipaddr, + netmask=netmask, gateway=gateway, bondingOptions=bondingOptions, + bridged=bridged, **options) + + logging.info("Adding network %s with vlan=%s, bonding=%s, nics=%s," + " bondingOptions=%s, mtu=%s, bridged=%s, options=%s", + network, vlan, bonding, nics, bondingOptions, + mtu, bridged, options) + + + prevmtu = None + if mtu: + prevmtu = self.configWriter.getMaxMtu(nics, mtu) + + nic = nics[0] if nics else None + iface = bonding or nic + + # take down nics that need to be changed + vlanedIfaces = [v['iface'] for v in _netinfo.vlans.values()] + if bonding not in vlanedIfaces: + for nic in nics: + if nic not in vlanedIfaces: + ifdown(nic) + + if bridged: + self.configWriter.addBridge(network, ipaddr=ipaddr, netmask=netmask, + mtu=mtu, gateway=gateway, **options) + ifdown(network) + # We need to define (if requested) ip, mask & gateway on ifcfg-* + # only on most top device according to following order: + # bridge -> vlan -> bond -> nic + # For lower level devices we should ignore it. + # reset ip, netmask, gateway for lower level devices + ipaddr = netmask = gateway = None + + # For VLAN we should attach bridge only to the VLAN device + # rather than to underlying NICs or bond + brName = network if bridged else None + bridgeForNic = None if vlan else brName + + # We want to create config files (ifcfg-*) in top-down order + # (bridge->vlan->bond->nic) to be able to handle IP/NETMASK + # correctly for bridgeless networks + if vlan: + # don't ifup VLAN interface here, it should be done last, + # after the bond and nic up + self.configWriter.addVlan(vlan, iface, network=brName, + mtu=mtu, bridged=bridged, + ipaddr=ipaddr, netmask=netmask, + gateway=gateway, **options) + iface += '.' + vlan + # reset ip, netmask, gateway for lower level devices + ipaddr = netmask = gateway = None + + # First we need to prepare all conf files + if bonding: + self.configWriter.addBonding(bonding, bridge=bridgeForNic, + bondingOptions=bondingOptions, + mtu=max(prevmtu, mtu), + ipaddr=ipaddr, netmask=netmask, + gateway=gateway, **options) + # reset ip, netmask, gateway for lower level devices + ipaddr = netmask = gateway = None + + for nic in nics: + self.configWriter.addNic(nic, bonding=bonding, + bridge=bridgeForNic if not bonding else None, + mtu=max(prevmtu, mtu), + ipaddr=ipaddr, netmask=netmask, + gateway=gateway, **options) + + # Now we can run ifup for all interfaces + if bonding: + ifup(bonding) + + # NICs must be activated in the same order of boot time + # to expose the correct MAC address. + for nic in nicSort(nics): + ifup(nic) + + # Now we can ifup VLAN interface, because bond and nic already up + if vlan: + ifup(iface) + + if bridged: + if options.get('bootproto') == 'dhcp' and \ + not utils.tobool(options.get('blockingdhcp')): + # wait for dhcp in another thread, + # so vdsm won't get stuck (BZ#498940) + t = threading.Thread(target=ifup, name='ifup-waiting-on-dhcp', + args=(network,)) + t.daemon = True + t.start() + else: + ifup(network) + + # add libvirt network + self.configWriter.createLibvirtNetwork(network, bridged, iface) + + def delNetwork(self, network, vlan=None, bonding=None, nics=None, force=False, + implicitBonding=True, **options): + _netinfo = netinfo.NetInfo() + + if network not in _netinfo.networks: + logging.info("Network %r: doesn't exist in libvirt database", network) + if network in netinfo.bridges(): + self.configWriter.removeBridge(network) + else: + raise ConfigNetworkError(ne.ERR_BAD_BRIDGE, + "Cannot delete network %r: It doesn't exist " + "in the system" % network) + + if vlan: + self.configWriter.removeVlan(vlan, bonding or nics[0]) + + return + + nics, vlan, bonding = _netinfo.getNicsVlanAndBondingForNetwork(network) + bridged = _netinfo.networks[network]['bridged'] + + logging.info("Removing network %s with vlan=%s, bonding=%s, nics=%s," + "options=%s" % (network, vlan, bonding, nics, options)) + + if not utils.tobool(force): + if bonding: + validateBondingName(bonding) + if set(nics) != set(_netinfo.bondings[bonding]["slaves"]): + raise ConfigNetworkError(ne.ERR_BAD_NIC, + "delNetwork: %s are not all nics enslaved to %s" % \ + (nics, bonding)) + if vlan: + validateVlanId(vlan) + if bridged: + assertBridgeClean(network, vlan, bonding, nics) + + if bridged: + self.configWriter.setNewMtu(network) + + self.configWriter.removeLibvirtNetwork(network) + # We need to gather NetInfo again to refresh networks info from libvirt. + # The deleted bridge should never be up at this stage. + if network in netinfo.NetInfo().networks: + raise ConfigNetworkError(ne.ERR_USED_BRIDGE, + "delNetwork: bridge %s still exists" % network) + + if network and bridged: + self.configWriter.removeBridge(network) + + if vlan: + self.configWriter.removeVlan(vlan, bonding or nics[0]) + + # When removing bridgeless non-VLANed network + # we need to remove IP/NETMASK from the cfg file + name = None + if not bridged and not vlan: + name = bonding if bonding else nics[0] + # Just edit the bond/nic cfg file + cf = self.configWriter.NET_CONF_PREF + name + for key in ('IPADDR', 'NETMASK', 'GATEWAY', 'BOOTPROTO'): + self.configWriter._updateConfigValue(cf, key, '', True) + + # The (relatively) new setupNetwork verb allows to remove a network + # defined on top of an bonding device without break the bond itself. + if implicitBonding: + if bonding and not bondingOtherUsers(network, vlan, bonding): + ifdown(bonding) + self.configWriter.removeBonding(bonding) + name = None if bonding == name else name + + for nic in nics: + if not nicOtherUsers(network, vlan, bonding, nic): + ifdown(nic) + self.configWriter.removeNic(nic) + name = None if nic == name else name + + # Now we can restart changed interface + if name: + ifdown(name) + ifup(name) + + def editNetwork(self, oldBridge, newBridge, vlan=None, bonding=None, + nics=None, **options): + try: + self.delNetwork(oldBridge, **options) + self.addNetwork(newBridge, vlan=vlan, bonding=bonding, nics=nics, + **options) + except: + self.configWriter.restoreBackups() + raise + if utils.tobool(options.get('connectivityCheck', False)): + if not clientSeen(int(options.get('connectivityTimeout', CONNECTIVITY_TIMEOUT_DEFAULT))): + delNetwork(newBridge, force=True) + self.configWriter.restoreBackups() + return define.errCode['noConPeer']['status']['code'] + + def editBondings(self, bondings): + """ Add/Edit bond interface """ + logger = logging.getLogger("editBondings") + + _netinfo = netinfo.NetInfo() + + for bond, bondAttrs in bondings.iteritems(): + logger.debug("Creating/Editing bond %s with attributes %s", + bond, bondAttrs) + + brNets = list(_netinfo.getBridgedNetworksForIface(bond)) + # Only one bridged-non-VLANed network allowed on same nic/bond + bridge = brNets[0] if brNets else None + + mtu = None + if bond in _netinfo.bondings: + # Save MTU for future set on NICs + confParams = netinfo.getIfaceCfg(bond) + mtu = confParams.get('MTU', None) + if mtu: + mtu = int(mtu) + + ifdown(bond) + # Take down all bond's NICs. + for nic in _netinfo.getNicsForBonding(bond): + ifdown(nic) + self.configWriter.removeNic(nic) + + # Note! In case we have bridge up and connected to the bond + # we will get error in log: + # (ifdown) bridge XXX is still up; can't delete it + # But, we prefer this behaviour instead of taking bridge down + # Anyway, we will not be able to take it down with connected VMs + + # First we need to prepare all conf files + self.configWriter.addBonding(bond, bridge=bridge, mtu=mtu, + bondingOptions=bondAttrs.get('options', None)) + + for nic in bondAttrs['nics']: + self.configWriter.addNic(nic, bonding=bond, mtu=mtu) + + # Now we can run ifup for all interfaces + ifup(bond) + # NICs must be activated in the same order of boot time + # to expose the correct MAC address. + for nic in nicSort(bondAttrs['nics']): + ifup(nic) + + def removeBondings(self, bondings): + """ Remove bond interface """ + logger = logging.getLogger("removeBondings") + + _netinfo = netinfo.NetInfo() + + for bond, bondAttrs in bondings.items(): + if 'remove' in bondAttrs: + nics = _netinfo.getNicsForBonding(bond) + logger.debug("Removing bond %r with nics = %s", bond, nics) + ifdown(bond) + self.configWriter.removeBonding(bond) + + for nic in nics: + ifdown(nic) + self.configWriter.removeNic(nic) + + del bondings[bond] + + +configurator = NativeConfigurator() + + +def addNetwork(network, vlan=None, bonding=None, nics=None, ipaddr=None, + netmask=None, mtu=None, gateway=None, force=False, + bondingOptions=None, bridged=True, **options): + configurator.addNetwork(network, vlan, bonding, nics, ipaddr, netmask, mtu, gateway, + force, bondingOptions, bridged, **options) + + +def delNetwork(network, vlan=None, bonding=None, nics=None, force=False, + implicitBonding=True, **options): + configurator.delNetwork(network, vlan, bonding, nics, force, + implicitBonding, **options) + + +def editNetwork(oldBridge, newBridge, vlan=None, bonding=None, nics=None, **options): + configurator.editNetwork(oldBridge, newBridge, vlan, bonding, nics, **options) + def showNetwork(network): _netinfo = netinfo.NetInfo() @@ -975,6 +1179,7 @@ print "vlan=%s, bonding=%s, nics=%s" % (vlan, bonding, nics) + def listNetworks(): _netinfo = netinfo.NetInfo() print "Networks:", _netinfo.networks.keys() @@ -982,92 +1187,6 @@ print "Nics:", _netinfo.nics.keys() print "Bondings:", _netinfo.bondings.keys() -def delNetwork(network, vlan=None, bonding=None, nics=None, force=False, - configWriter=None, implicitBonding=True, **options): - _netinfo = netinfo.NetInfo() - - if configWriter is None: - configWriter = ConfigWriter() - - if network not in _netinfo.networks: - logging.info("Network %r: doesn't exist in libvirt database", network) - if network in netinfo.bridges(): - configWriter.removeBridge(network) - else: - raise ConfigNetworkError(ne.ERR_BAD_BRIDGE, - "Cannot delete network %r: It doesn't exist " - "in the system" % network) - - if vlan: - configWriter.removeVlan(vlan, bonding or nics[0]) - - return - - nics, vlan, bonding = _netinfo.getNicsVlanAndBondingForNetwork(network) - bridged = _netinfo.networks[network]['bridged'] - - logging.info("Removing network %s with vlan=%s, bonding=%s, nics=%s," - "options=%s" % (network, vlan, bonding, nics, options)) - - if not utils.tobool(force): - if bonding: - validateBondingName(bonding) - if set(nics) != set(_netinfo.bondings[bonding]["slaves"]): - raise ConfigNetworkError(ne.ERR_BAD_NIC, - "delNetwork: %s are not all nics enslaved to %s" % \ - (nics, bonding)) - if vlan: - validateVlanId(vlan) - if bridged: - assertBridgeClean(network, vlan, bonding, nics) - - if bridged: - configWriter.setNewMtu(network) - - configWriter.removeLibvirtNetwork(network) - # We need to gather NetInfo again to refresh networks info from libvirt. - # The deleted bridge should never be up at this stage. - if network in netinfo.NetInfo().networks: - raise ConfigNetworkError(ne.ERR_USED_BRIDGE, - "delNetwork: bridge %s still exists" % network) - - if network and bridged: - configWriter.removeBridge(network) - - name = None - if vlan: - configWriter.removeVlan(vlan, bonding or nics[0]) - else: - name = bonding if bonding else nics[0] - cf = configWriter.NET_CONF_PREF + name - if not bridged: - # When removing bridgeless non-VLANed network - # we need to remove IP/NETMASK from the cfg file - for key in ('IPADDR', 'NETMASK', 'GATEWAY', 'BOOTPROTO'): - configWriter._updateConfigValue(cf, key, '', True) - else: - # When removing bridged non-VLANed network - # we need to remove BRIDGE from the cfg file - configWriter._updateConfigValue(cf, 'BRIDGE', '', True) - - # The (relatively) new setupNetwork verb allows to remove a network - # defined on top of an bonding device without break the bond itself. - if implicitBonding: - if bonding and not bondingOtherUsers(network, vlan, bonding): - ifdown(bonding) - configWriter.removeBonding(bonding) - name = None if bonding == name else name - - for nic in nics: - if not nicOtherUsers(network, vlan, bonding, nic): - ifdown(nic) - configWriter.removeNic(nic) - name = None if nic == name else name - - # Now we can restart changed interface - if name: - ifdown(name) - ifup(name) def clientSeen(timeout): start = time.time() @@ -1078,20 +1197,6 @@ timeout -= 1 return False - -def editNetwork(oldBridge, newBridge, vlan=None, bonding=None, nics=None, **options): - configWriter = ConfigWriter() - try: - delNetwork(oldBridge, configWriter=configWriter, **options) - addNetwork(newBridge, vlan=vlan, bonding=bonding, nics=nics, configWriter=configWriter, **options) - except: - configWriter.restoreBackups() - raise - if utils.tobool(options.get('connectivityCheck', False)): - if not clientSeen(int(options.get('connectivityTimeout', CONNECTIVITY_TIMEOUT_DEFAULT))): - delNetwork(newBridge, force=True) - configWriter.restoreBackups() - return define.errCode['noConPeer']['status']['code'] def _validateNetworkSetup(networks={}, bondings={}): _netinfo = netinfo.NetInfo() @@ -1117,73 +1222,6 @@ if not set(nics).issubset(set(_netinfo.nics)): raise ConfigNetworkError(ne.ERR_BAD_NIC, "Unknown nics in: %r"%list(nics)) - -def _editBondings(bondings, configWriter): - """ Add/Edit bond interface """ - logger = logging.getLogger("_editBondings") - - _netinfo = netinfo.NetInfo() - - for bond, bondAttrs in bondings.iteritems(): - logger.debug("Creating/Editing bond %s with attributes %s", - bond, bondAttrs) - - brNets = list(_netinfo.getBridgedNetworksForIface(bond)) - # Only one bridged-non-VLANed network allowed on same nic/bond - bridge = brNets[0] if brNets else None - - mtu = None - if bond in _netinfo.bondings: - # Save MTU for future set on NICs - confParams = netinfo.getIfaceCfg(bond) - mtu = confParams.get('MTU', None) - if mtu: - mtu = int(mtu) - - ifdown(bond) - # Take down all bond's NICs. - for nic in _netinfo.getNicsForBonding(bond): - ifdown(nic) - configWriter.removeNic(nic) - - # Note! In case we have bridge up and connected to the bond - # we will get error in log: - # (ifdown) bridge XXX is still up; can't delete it - # But, we prefer this behaviour instead of taking bridge down - # Anyway, we will not be able to take it down with connected VMs - - # First we need to prepare all conf files - configWriter.addBonding(bond, bridge=bridge, mtu=mtu, - bondingOptions=bondAttrs.get('options', None)) - - for nic in bondAttrs['nics']: - configWriter.addNic(nic, bonding=bond, mtu=mtu) - - # Now we can run ifup for all interfaces - ifup(bond) - # NICs must be activated in the same order of boot time - # to expose the correct MAC address. - for nic in nicSort(bondAttrs['nics']): - ifup(nic) - -def _removeBondings(bondings, configWriter): - """ Remove bond interface """ - logger = logging.getLogger("_removeBondings") - - _netinfo = netinfo.NetInfo() - - for bond, bondAttrs in bondings.items(): - if 'remove' in bondAttrs: - nics = _netinfo.getNicsForBonding(bond) - logger.debug("Removing bond %r with nics = %s", bond, nics) - ifdown(bond) - configWriter.removeBonding(bond) - - for nic in nics: - ifdown(nic) - configWriter.removeNic(nic) - - del bondings[bond] def setupNetworks(networks={}, bondings={}, **options): @@ -1227,7 +1265,6 @@ try: _netinfo = netinfo.NetInfo() - configWriter = ConfigWriter() networksAdded = set() # keep set netsWithNewBonds to be able remove # a new added network if connectivity check fail. @@ -1251,7 +1288,7 @@ for network, networkAttrs in networks.items(): if network in _netinfo.networks: logger.debug("Removing network %r" % network) - delNetwork(network, configWriter=configWriter, force=force, + delNetwork(network, force=force, implicitBonding=False) if 'remove' in networkAttrs: del networks[network] @@ -1259,10 +1296,10 @@ networksAdded.add(network) # Remove bonds with 'remove' attribute - _removeBondings(bondings, configWriter) + configurator.removeBondings(bondings) # Check whether bonds should be resized - _editBondings(bondings, configWriter) + configurator.editBondings(bondings) # We need to use the newest host info _ni = netinfo.NetInfo() @@ -1291,8 +1328,7 @@ d['force'] = force logger.debug("Adding network %r" % network) - addNetwork(network, configWriter=configWriter, - implicitBonding=True, **d) + addNetwork(network, implicitBonding=True, **d) if utils.tobool(options.get('connectivityCheck', True)): logger.debug('Checking connectivity...') @@ -1305,7 +1341,7 @@ raise ConfigNetworkError(ne.ERR_LOST_CONNECTION, 'connectivity check failed') except: - configWriter.restoreBackups() + configurator.configWriter.restoreBackups() raise except Exception, e: -- To view, visit http://gerrit.ovirt.org/7714 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I66710fdf8fd73beb06124f72ef9857df7393a602 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Mark Wu <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
