class Ifcfg(Configurator): # TODO: Do all the configApplier interaction from here. def __init__(self, inRollback=False): self.unifiedPersistence = \ config.get('vars', 'net_persistence') == 'unified' super(Ifcfg, self).__init__(ConfigWriter(self.unifiedPersistence), inRollback) if self.unifiedPersistence: self.runningConfig = RunningConfig() def begin(self): if self.configApplier is None: self.configApplier = ConfigWriter(self.unifiedPersistence) if self.unifiedPersistence and self.runningConfig is None: self.runningConfig = RunningConfig() def rollback(self): """This reimplementation always returns None since Ifcfg can rollback on its own via restoreBackups(). This makes the general mechanism of API.Global._rollback redundant in this case.""" self.configApplier.restoreBackups() self.configApplier = None if self.unifiedPersistence: self.runningConfig = None def commit(self): self.configApplier = None if self.unifiedPersistence: self.runningConfig.save() self.runningConfig = None def configureBridge(self, bridge, **opts): self.configApplier.addBridge(bridge, **opts) ifdown(bridge.name) if bridge.port: bridge.port.configure(**opts) self._addSourceRoute(bridge) _ifup(bridge) if not bridge.ipv6.address and not bridge.ipv6.ipv6autoconf and ( not bridge.ipv6.dhcpv6 and misc.ipv6_supported()): wait_for_device(bridge.name) sysctl.disable_ipv6(bridge.name) def configureVlan(self, vlan, **opts): self.configApplier.addVlan(vlan, **opts) vlan.device.configure(**opts) self._addSourceRoute(vlan) _ifup(vlan) def configureBond(self, bond, **opts): self.configApplier.addBonding(bond, **opts) if not vlans.is_vlanned(bond.name): for slave in bond.slaves: ifdown(slave.name) for slave in bond.slaves: slave.configure(**opts) self._addSourceRoute(bond) _ifup(bond) if self.unifiedPersistence: self.runningConfig.setBonding( bond.name, {'options': bond.options, 'nics': [slave.name for slave in bond.slaves]}) def editBonding(self, bond, _netinfo): """ Modifies the bond so that the bond in the system ends up with the same slave and options configuration that are requested. Makes a best effort not to interrupt connectivity. """ nicsToSet = frozenset(nic.name for nic in bond.slaves) currentNics = frozenset(_netinfo.getNicsForBonding(bond.name)) nicsToAdd = nicsToSet - currentNics # Create bond configuration in case it was a non ifcfg controlled bond. # Needed to be before slave configuration for initscripts to add slave # to bond. bondIfcfgWritten = False isIfcfgControlled = os.path.isfile(NET_CONF_PREF + bond.name) areOptionsApplied = bond.areOptionsApplied() if not isIfcfgControlled or not areOptionsApplied: bridgeName = _netinfo.getBridgedNetworkForIface(bond.name) if isIfcfgControlled and bridgeName: bond.master = Bridge(bridgeName, self, port=bond) self.configApplier.addBonding(bond) bondIfcfgWritten = True for nic in currentNics - nicsToSet: ifdown(nic) # So that no users will be detected for it. Nic(nic, self, _netinfo=_netinfo).remove() for slave in bond.slaves: if slave.name in nicsToAdd: ifdown(slave.name) # nics must be down to join a bond self.configApplier.addNic(slave) _exec_ifup(slave.name) if bondIfcfgWritten: ifdown(bond.name) _restore_default_bond_options(bond.name, bond.options) _exec_ifup(bond.name) if self.unifiedPersistence: self.runningConfig.setBonding( bond.name, {'options': bond.options, 'nics': [slave.name for slave in bond.slaves]}) def configureNic(self, nic, **opts): self.configApplier.addNic(nic, **opts) self._addSourceRoute(nic) if nic.bond is None: if not vlans.is_vlanned(nic.name): ifdown(nic.name) _ifup(nic) def removeBridge(self, bridge): DynamicSourceRoute.addInterfaceTracking(bridge) ifdown(bridge.name) self._removeSourceRoute(bridge, StaticSourceRoute) commands.execCmd([constants.EXT_BRCTL, 'delbr', bridge.name]) self.configApplier.removeBridge(bridge.name) if bridge.port: bridge.port.remove() def removeVlan(self, vlan): DynamicSourceRoute.addInterfaceTracking(vlan) ifdown(vlan.name) self._removeSourceRoute(vlan, StaticSourceRoute) self.configApplier.removeVlan(vlan.name) vlan.device.remove() def _ifaceDownAndCleanup(self, iface, remove_even_if_used=False): """Returns True iff the iface is to be removed.""" DynamicSourceRoute.addInterfaceTracking(iface) to_be_removed = remove_even_if_used or not ifaceUsed(iface.name) if to_be_removed: ifdown(iface.name) self._removeSourceRoute(iface, StaticSourceRoute) return to_be_removed def _addSourceRoute(self, netEnt): """For ifcfg tracking can be done together with route/rule addition""" super(Ifcfg, self)._addSourceRoute(netEnt) DynamicSourceRoute.addInterfaceTracking(netEnt) def removeBond(self, bonding): to_be_removed = self._ifaceDownAndCleanup(bonding) if to_be_removed: self.configApplier.removeBonding(bonding.name) if bonding.destroyOnMasterRemoval: for slave in bonding.slaves: slave.remove() if self.unifiedPersistence: self.runningConfig.removeBonding(bonding.name) else: # Recreate the bond with ip and master info cleared bonding.ipv4 = IPv4() bonding.ipv6 = IPv6() bonding.master = None bonding.configure() else: set_mtu = self._setNewMtu(bonding, vlans.vlan_devs_for_iface(bonding.name)) # Since we are not taking the device up again, ifcfg will not be # read at this point and we need to set the live mtu value. # Note that ip link set dev bondX mtu Y sets Y on all its links if set_mtu is not None: ipwrapper.linkSet(bonding.name, ['mtu', str(set_mtu)]) def removeNic(self, nic, remove_even_if_used=False): to_be_removed = self._ifaceDownAndCleanup(nic, remove_even_if_used) if to_be_removed: self.configApplier.removeNic(nic.name) if nic.name in nics.nics(): _exec_ifup(nic.name) else: logging.warning('host interface %s missing', nic.name) else: set_mtu = self._setNewMtu(nic, vlans.vlan_devs_for_iface(nic.name)) # Since we are not taking the device up again, ifcfg will not be # read at this point and we need to set the live mtu value if set_mtu is not None: ipwrapper.linkSet(nic.name, ['mtu', str(set_mtu)]) def _getFilePath(self, fileType, device): return os.path.join(NET_CONF_DIR, '%s-%s' % (fileType, device)) def _removeSourceRouteFile(self, fileType, device): filePath = self._getFilePath(fileType, device) self.configApplier._backup(filePath) self.configApplier._removeFile(filePath) def _writeConfFile(self, contents, fileType, device): filePath = self._getFilePath(fileType, device) configuration = '' for entry in contents: configuration += str(entry) + '\n' self.configApplier.writeConfFile(filePath, configuration) def configureSourceRoute(self, routes, rules, device): self._writeConfFile(routes, 'route', device) self._writeConfFile(rules, 'rule', device) def removeSourceRoute(self, routes, rules, device): self._removeSourceRouteFile('rule', device) self._removeSourceRouteFile('route', device)
class Iproute2(Configurator): def __init__(self, inRollback=False): super(Iproute2, self).__init__(ConfigApplier(), inRollback) self.runningConfig = RunningConfig() def begin(self): if self.configApplier is None: self.configApplier = ConfigApplier() if self.runningConfig is None: self.runningConfig = RunningConfig() def commit(self): self.configApplier = None self.runningConfig.save() self.runningConfig = None def configureBridge(self, bridge, **opts): self.configApplier.addBridge(bridge) if bridge.port: bridge.port.configure(**opts) self.configApplier.addBridgePort(bridge) DynamicSourceRoute.addInterfaceTracking(bridge) self.configApplier.setIfaceConfigAndUp(bridge) self._addSourceRoute(bridge) if 'custom' in opts and 'bridge_opts' in opts['custom']: self.configApplier._setBridgeOpts(bridge, opts['custom']['bridge_opts']) def configureVlan(self, vlan, **opts): vlan.device.configure(**opts) self.configApplier.addVlan(vlan) DynamicSourceRoute.addInterfaceTracking(vlan) self.configApplier.setIfaceConfigAndUp(vlan) self._addSourceRoute(vlan) def configureBond(self, bond, **opts): self.configApplier.addBond(bond) if not bond.areOptionsApplied(): self.configApplier.ifdown(bond) self.configApplier.addBondOptions(bond) for slave in bond.slaves: if slave.name not in netinfo.slaves(bond.name): self.configApplier.addBondSlave(bond, slave) slave.configure(**opts) DynamicSourceRoute.addInterfaceTracking(bond) self.configApplier.setIfaceConfigAndUp(bond) self._addSourceRoute(bond) self.runningConfig.setBonding( bond.name, {'options': bond.options, 'nics': [slave.name for slave in bond.slaves]}) def editBonding(self, bond, _netinfo): """ Modifies the bond so that the bond in the system ends up with the same slave and options configuration that are requested. Makes a best effort not to interrupt connectivity. """ nicsToSet = frozenset(nic.name for nic in bond.slaves) currentNics = frozenset(_netinfo.getNicsForBonding(bond.name)) nicsToAdd = nicsToSet nicsToRemove = currentNics if bond.areOptionsApplied(): nicsToAdd -= currentNics nicsToRemove -= nicsToSet for nic in nicsToRemove: slave = Nic(nic, self, _netinfo=_netinfo) self.configApplier.removeBondSlave(bond, slave) slave.remove() if not bond.areOptionsApplied(): self.configApplier.ifdown(bond) self.configApplier.addBondOptions(bond) for slave in bond.slaves: if slave.name in nicsToAdd: self.configApplier.addBondSlave(bond, slave) self.configApplier.ifup(bond) self.runningConfig.setBonding( bond.name, {'options': bond.options, 'nics': [slave.name for slave in bond.slaves]}) def configureNic(self, nic, **opts): DynamicSourceRoute.addInterfaceTracking(nic) self.configApplier.setIfaceConfigAndUp(nic) self._addSourceRoute(nic) ethtool_opts = getEthtoolOpts(nic.name) if ethtool_opts: # We ignore ethtool's return code to maintain initscripts' # behaviour. execCmd( [_ETHTOOL_BINARY.cmd, '-K', nic.name] + ethtool_opts.split()) def removeBridge(self, bridge): DynamicSourceRoute.addInterfaceTracking(bridge) self.configApplier.ifdown(bridge) self._removeSourceRoute(bridge, DynamicSourceRoute) self.configApplier.removeBridge(bridge) if bridge.port: bridge.port.remove() def removeVlan(self, vlan): DynamicSourceRoute.addInterfaceTracking(vlan) self.configApplier.ifdown(vlan) self._removeSourceRoute(vlan, DynamicSourceRoute) self.configApplier.removeVlan(vlan) vlan.device.remove() def _destroyBond(self, bonding): for slave in bonding.slaves: self.configApplier.removeBondSlave(bonding, slave) slave.remove() self.configApplier.removeBond(bonding) def removeBond(self, bonding): toBeRemoved = not netinfo.ifaceUsed(bonding.name) if toBeRemoved: if bonding.master is None: self.configApplier.removeIpConfig(bonding) DynamicSourceRoute.addInterfaceTracking(bonding) self._removeSourceRoute(bonding, DynamicSourceRoute) if bonding.destroyOnMasterRemoval: self._destroyBond(bonding) self.runningConfig.removeBonding(bonding.name) else: self.configApplier.setIfaceMtu(bonding.name, netinfo.DEFAULT_MTU) self.configApplier.ifdown(bonding) else: self._setNewMtu(bonding, netinfo.vlanDevsForIface(bonding.name)) def removeNic(self, nic): toBeRemoved = not netinfo.ifaceUsed(nic.name) if toBeRemoved: if nic.master is None: self.configApplier.removeIpConfig(nic) DynamicSourceRoute.addInterfaceTracking(nic) self._removeSourceRoute(nic, DynamicSourceRoute) else: self.configApplier.setIfaceMtu(nic.name, netinfo.DEFAULT_MTU) self.configApplier.ifdown(nic) else: self._setNewMtu(nic, netinfo.vlanDevsForIface(nic.name)) @staticmethod def configureSourceRoute(routes, rules, device): for route in routes: routeAdd(route) for rule in rules: ruleAdd(rule) @staticmethod def removeSourceRoute(routes, rules, device): for route in routes: routeDel(route) for rule in rules: ruleDel(rule)
class Ifcfg(Configurator): # TODO: Do all the configApplier interaction from here. def __init__(self, inRollback=False): self.unifiedPersistence = \ config.get('vars', 'net_persistence') == 'unified' super(Ifcfg, self).__init__(ConfigWriter(self.unifiedPersistence), inRollback) if self.unifiedPersistence: self.runningConfig = RunningConfig() def begin(self): if self.configApplier is None: self.configApplier = ConfigWriter(self.unifiedPersistence) if self.unifiedPersistence and self.runningConfig is None: self.runningConfig = RunningConfig() def rollback(self): self.configApplier.restoreBackups() self.configApplier = None if self.unifiedPersistence: self.runningConfig = None def commit(self): self.configApplier = None if self.unifiedPersistence: self.runningConfig.save() self.runningConfig = None def configureBridge(self, bridge, **opts): self.configApplier.addBridge(bridge, **opts) ifdown(bridge.name) if bridge.port: bridge.port.configure(**opts) self._addSourceRoute(bridge) ifup(bridge.name, bridge.ipConfig. async) def configureVlan(self, vlan, **opts): self.configApplier.addVlan(vlan, **opts) vlan.device.configure(**opts) self._addSourceRoute(vlan) ifup(vlan.name, vlan.ipConfig. async) def configureBond(self, bond, **opts): self.configApplier.addBonding(bond, **opts) if not netinfo.isVlanned(bond.name): for slave in bond.slaves: ifdown(slave.name) for slave in bond.slaves: slave.configure(**opts) self._addSourceRoute(bond) ifup(bond.name, bond.ipConfig. async) if self.unifiedPersistence: self.runningConfig.setBonding( bond.name, { 'options': bond.options, 'nics': [slave.name for slave in bond.slaves] }) def editBonding(self, bond, _netinfo): """ Modifies the bond so that the bond in the system ends up with the same slave and options configuration that are requested. Makes a best effort not to interrupt connectivity. """ nicsToSet = frozenset(nic.name for nic in bond.slaves) currentNics = frozenset(_netinfo.getNicsForBonding(bond.name)) nicsToAdd = nicsToSet - currentNics # Create bond configuration in case it was a non ifcfg controlled bond. # Needed to be before slave configuration for initscripts to add slave # to bond. bondIfcfgWritten = False isIfcfgControlled = os.path.isfile(netinfo.NET_CONF_PREF + bond.name) areOptionsApplied = bond.areOptionsApplied() if not isIfcfgControlled or not areOptionsApplied: bridgeName = _netinfo.getBridgedNetworkForIface(bond.name) if isIfcfgControlled and bridgeName: bond.master = Bridge(bridgeName, self, port=bond) self.configApplier.addBonding(bond) bondIfcfgWritten = True for nic in currentNics - nicsToSet: ifdown(nic) # So that no users will be detected for it. Nic(nic, self, _netinfo=_netinfo).remove() for slave in bond.slaves: if slave.name in nicsToAdd: ifdown(slave.name) # nics must be down to join a bond self.configApplier.addNic(slave) ifup(slave.name) if bondIfcfgWritten: ifdown(bond.name) ifup(bond.name) if self.unifiedPersistence: self.runningConfig.setBonding( bond.name, { 'options': bond.options, 'nics': [slave.name for slave in bond.slaves] }) def configureNic(self, nic, **opts): self.configApplier.addNic(nic, **opts) self._addSourceRoute(nic) if nic.bond is None: if not netinfo.isVlanned(nic.name): ifdown(nic.name) ifup(nic.name, nic.ipConfig. async) def removeBridge(self, bridge): DynamicSourceRoute.addInterfaceTracking(bridge) ifdown(bridge.name) self._removeSourceRoute(bridge, StaticSourceRoute) utils.execCmd([constants.EXT_BRCTL, 'delbr', bridge.name]) self.configApplier.removeBridge(bridge.name) if bridge.port: bridge.port.remove() def removeVlan(self, vlan): DynamicSourceRoute.addInterfaceTracking(vlan) ifdown(vlan.name) self._removeSourceRoute(vlan, StaticSourceRoute) self.configApplier.removeVlan(vlan.name) vlan.device.remove() def _ifaceDownAndCleanup(self, iface): """Returns True iff the iface is to be removed.""" DynamicSourceRoute.addInterfaceTracking(iface) to_be_removed = not netinfo.ifaceUsed(iface.name) if to_be_removed: ifdown(iface.name) self._removeSourceRoute(iface, StaticSourceRoute) return to_be_removed def _addSourceRoute(self, netEnt): """For ifcfg tracking can be done together with route/rule addition""" super(Ifcfg, self)._addSourceRoute(netEnt) DynamicSourceRoute.addInterfaceTracking(netEnt) def removeBond(self, bonding): to_be_removed = self._ifaceDownAndCleanup(bonding) if to_be_removed: self.configApplier.removeBonding(bonding.name) if bonding.destroyOnMasterRemoval: for slave in bonding.slaves: slave.remove() if self.unifiedPersistence: self.runningConfig.removeBonding(bonding.name) else: # Recreate the bond with ip and master info cleared bonding.ip = bonding.master = None bonding.configure() else: set_mtu = self._setNewMtu(bonding, netinfo.vlanDevsForIface(bonding.name)) # Since we are not taking the device up again, ifcfg will not be # read at this point and we need to set the live mtu value. # Note that ip link set dev bondX mtu Y sets Y on all its links if set_mtu is not None: ipwrapper.linkSet(bonding.name, ['mtu', str(set_mtu)]) def removeNic(self, nic): to_be_removed = self._ifaceDownAndCleanup(nic) if to_be_removed: self.configApplier.removeNic(nic.name) if nic.name in netinfo.nics(): ifup(nic.name) else: logging.warning('host interface %s missing', nic.name) else: set_mtu = self._setNewMtu(nic, netinfo.vlanDevsForIface(nic.name)) # Since we are not taking the device up again, ifcfg will not be # read at this point and we need to set the live mtu value if set_mtu is not None: ipwrapper.linkSet(nic.name, ['mtu', str(set_mtu)]) def _getFilePath(self, fileType, device): return os.path.join(netinfo.NET_CONF_DIR, '%s-%s' % (fileType, device)) def _removeSourceRouteFile(self, fileType, device): filePath = self._getFilePath(fileType, device) self.configApplier._backup(filePath) self.configApplier._removeFile(filePath) def _writeConfFile(self, contents, fileType, device): filePath = self._getFilePath(fileType, device) configuration = '' for entry in contents: configuration += str(entry) + '\n' self.configApplier.writeConfFile(filePath, configuration) def configureSourceRoute(self, routes, rules, device): self._writeConfFile(routes, 'route', device) self._writeConfFile(rules, 'rule', device) def removeSourceRoute(self, routes, rules, device): self._removeSourceRouteFile('rule', device) self._removeSourceRouteFile('route', device) def flush(self): super(Ifcfg, self).flush() self.configApplier.flush()
class Iproute2(Configurator): def __init__(self, inRollback=False): super(Iproute2, self).__init__(ConfigApplier(), inRollback) self.runningConfig = RunningConfig() def begin(self): if self.configApplier is None: self.configApplier = ConfigApplier() if self.runningConfig is None: self.runningConfig = RunningConfig() def commit(self): self.configApplier = None self.runningConfig.save() self.runningConfig = None def configureBridge(self, bridge, **opts): self.configApplier.addBridge(bridge) if bridge.port: bridge.port.configure(**opts) self.configApplier.addBridgePort(bridge) DynamicSourceRoute.addInterfaceTracking(bridge) self.configApplier.setIfaceConfigAndUp(bridge) if not bridge.ipv6.address and not bridge.ipv6.ipv6autoconf and ( not bridge.ipv6.dhcpv6 and netinfo.ipv6_supported()): wait_for_device(bridge.name) sysctl.disable_ipv6(bridge.name) self._addSourceRoute(bridge) if 'custom' in opts and 'bridge_opts' in opts['custom']: self.configApplier._setBridgeOpts(bridge, opts['custom']['bridge_opts']) def configureVlan(self, vlan, **opts): vlan.device.configure(**opts) self.configApplier.addVlan(vlan) DynamicSourceRoute.addInterfaceTracking(vlan) self.configApplier.setIfaceConfigAndUp(vlan) self._addSourceRoute(vlan) def configureBond(self, bond, **opts): self.configApplier.addBond(bond) if not bond.areOptionsApplied(): self.configApplier.ifdown(bond) self.configApplier.addBondOptions(bond) for slave in bond.slaves: if slave.name not in netinfo.slaves(bond.name): self.configApplier.addBondSlave(bond, slave) slave.configure(**opts) DynamicSourceRoute.addInterfaceTracking(bond) self.configApplier.setIfaceConfigAndUp(bond) self._addSourceRoute(bond) self.runningConfig.setBonding( bond.name, { 'options': bond.options, 'nics': [slave.name for slave in bond.slaves] }) def editBonding(self, bond, _netinfo): """ Modifies the bond so that the bond in the system ends up with the same slave and options configuration that are requested. Makes a best effort not to interrupt connectivity. """ nicsToSet = frozenset(nic.name for nic in bond.slaves) currentNics = frozenset(_netinfo.getNicsForBonding(bond.name)) nicsToAdd = nicsToSet nicsToRemove = currentNics if bond.areOptionsApplied(): nicsToAdd -= currentNics nicsToRemove -= nicsToSet for nic in nicsToRemove: slave = Nic(nic, self, _netinfo=_netinfo) self.configApplier.removeBondSlave(bond, slave) slave.remove() if not bond.areOptionsApplied(): self.configApplier.ifdown(bond) self.configApplier.addBondOptions(bond) for slave in bond.slaves: if slave.name in nicsToAdd: self.configApplier.addBondSlave(bond, slave) self.configApplier.ifup(bond) self.runningConfig.setBonding( bond.name, { 'options': bond.options, 'nics': [slave.name for slave in bond.slaves] }) def configureNic(self, nic, **opts): DynamicSourceRoute.addInterfaceTracking(nic) self.configApplier.setIfaceConfigAndUp(nic) self._addSourceRoute(nic) ethtool_opts = getEthtoolOpts(nic.name) if ethtool_opts: # We ignore ethtool's return code to maintain initscripts' # behaviour. execCmd([_ETHTOOL_BINARY.cmd, '-K', nic.name] + ethtool_opts.split()) def removeBridge(self, bridge): DynamicSourceRoute.addInterfaceTracking(bridge) self.configApplier.ifdown(bridge) self._removeSourceRoute(bridge, DynamicSourceRoute) self.configApplier.removeBridge(bridge) if bridge.port: bridge.port.remove() def removeVlan(self, vlan): DynamicSourceRoute.addInterfaceTracking(vlan) self.configApplier.ifdown(vlan) self._removeSourceRoute(vlan, DynamicSourceRoute) self.configApplier.removeVlan(vlan) vlan.device.remove() def _destroyBond(self, bonding): for slave in bonding.slaves: self.configApplier.removeBondSlave(bonding, slave) slave.remove() self.configApplier.removeBond(bonding) def removeBond(self, bonding): toBeRemoved = not netinfo.ifaceUsed(bonding.name) if toBeRemoved: if bonding.master is None: self.configApplier.removeIpConfig(bonding) DynamicSourceRoute.addInterfaceTracking(bonding) self._removeSourceRoute(bonding, DynamicSourceRoute) if bonding.destroyOnMasterRemoval: self._destroyBond(bonding) self.runningConfig.removeBonding(bonding.name) else: self.configApplier.setIfaceMtu(bonding.name, netinfo.DEFAULT_MTU) self.configApplier.ifdown(bonding) else: self._setNewMtu(bonding, netinfo.vlanDevsForIface(bonding.name)) def removeNic(self, nic): toBeRemoved = not netinfo.ifaceUsed(nic.name) if toBeRemoved: if nic.master is None: self.configApplier.removeIpConfig(nic) DynamicSourceRoute.addInterfaceTracking(nic) self._removeSourceRoute(nic, DynamicSourceRoute) else: self.configApplier.setIfaceMtu(nic.name, netinfo.DEFAULT_MTU) self.configApplier.ifdown(nic) else: self._setNewMtu(nic, netinfo.vlanDevsForIface(nic.name)) @staticmethod def configureSourceRoute(routes, rules, device): for route in routes: routeAdd(route) for rule in rules: ruleAdd(rule) @staticmethod def removeSourceRoute(routes, rules, device): for route in routes: try: routeDel(route) except IPRoute2Error as e: if 'No such process' in e.message[0]: # The kernel or dhclient has won the race and removed the # route already. We have yet to remove routing rules. pass else: raise for rule in rules: ruleDel(rule)
class Iproute2(Configurator): def __init__(self, inRollback=False): self.unifiedPersistence = True super(Iproute2, self).__init__(ConfigApplier(), inRollback) self.runningConfig = RunningConfig() def begin(self): if self.configApplier is None: self.configApplier = ConfigApplier() if self.runningConfig is None: self.runningConfig = RunningConfig() def commit(self): self.configApplier = None self.runningConfig.save() self.runningConfig = None def configureBridge(self, bridge, **opts): self.configApplier.addBridge(bridge) if bridge.port: bridge.port.configure(**opts) self.configApplier.addBridgePort(bridge) DynamicSourceRoute.addInterfaceTracking(bridge) self.configApplier.setIfaceConfigAndUp(bridge) if not bridge.ipv6.address and not bridge.ipv6.ipv6autoconf and (not bridge.ipv6.dhcpv6): wait_for_device(bridge.name) sysctl.disable_ipv6(bridge.name) self._addSourceRoute(bridge) if "custom" in opts and "bridge_opts" in opts["custom"]: self.configApplier._setBridgeOpts(bridge, opts["custom"]["bridge_opts"]) def configureVlan(self, vlan, **opts): vlan.device.configure(**opts) self.configApplier.addVlan(vlan) DynamicSourceRoute.addInterfaceTracking(vlan) self.configApplier.setIfaceConfigAndUp(vlan) self._addSourceRoute(vlan) def configureBond(self, bond, **opts): self.configApplier.addBond(bond) if not bond.areOptionsApplied(): self.configApplier.ifdown(bond) self.configApplier.addBondOptions(bond) for slave in bond.slaves: if slave.name not in netinfo.slaves(bond.name): self.configApplier.addBondSlave(bond, slave) slave.configure(**opts) DynamicSourceRoute.addInterfaceTracking(bond) self.configApplier.setIfaceConfigAndUp(bond) self._addSourceRoute(bond) self.runningConfig.setBonding( bond.name, {"options": bond.options, "nics": [slave.name for slave in bond.slaves]} ) def editBonding(self, bond, _netinfo): """ Modifies the bond so that the bond in the system ends up with the same slave and options configuration that are requested. Makes a best effort not to interrupt connectivity. """ nicsToSet = frozenset(nic.name for nic in bond.slaves) currentNics = frozenset(_netinfo.getNicsForBonding(bond.name)) nicsToAdd = nicsToSet nicsToRemove = currentNics if bond.areOptionsApplied(): nicsToAdd -= currentNics nicsToRemove -= nicsToSet for nic in nicsToRemove: slave = Nic(nic, self, _netinfo=_netinfo) self.configApplier.removeBondSlave(bond, slave) slave.remove() if not bond.areOptionsApplied(): self.configApplier.ifdown(bond) self.configApplier.addBondOptions(bond) for slave in bond.slaves: if slave.name in nicsToAdd: self.configApplier.addBondSlave(bond, slave) self.configApplier.ifup(bond) self.runningConfig.setBonding( bond.name, {"options": bond.options, "nics": [slave.name for slave in bond.slaves]} ) def configureNic(self, nic, **opts): DynamicSourceRoute.addInterfaceTracking(nic) self.configApplier.setIfaceConfigAndUp(nic) self._addSourceRoute(nic) ethtool_opts = getEthtoolOpts(nic.name) if ethtool_opts: # We ignore ethtool's return code to maintain initscripts' # behaviour. execCmd([_ETHTOOL_BINARY.cmd, "-K", nic.name] + ethtool_opts.split()) def removeBridge(self, bridge): DynamicSourceRoute.addInterfaceTracking(bridge) self.configApplier.ifdown(bridge) self._removeSourceRoute(bridge, DynamicSourceRoute) self.configApplier.removeBridge(bridge) if bridge.port: bridge.port.remove() def removeVlan(self, vlan): DynamicSourceRoute.addInterfaceTracking(vlan) self.configApplier.ifdown(vlan) self._removeSourceRoute(vlan, DynamicSourceRoute) self.configApplier.removeVlan(vlan) vlan.device.remove() def _destroyBond(self, bonding): for slave in bonding.slaves: self.configApplier.removeBondSlave(bonding, slave) slave.remove() self.configApplier.removeBond(bonding) def removeBond(self, bonding): toBeRemoved = not netinfo.ifaceUsed(bonding.name) if toBeRemoved: if bonding.master is None: self.configApplier.removeIpConfig(bonding) DynamicSourceRoute.addInterfaceTracking(bonding) self._removeSourceRoute(bonding, DynamicSourceRoute) if bonding.destroyOnMasterRemoval: self._destroyBond(bonding) self.runningConfig.removeBonding(bonding.name) else: self.configApplier.setIfaceMtu(bonding.name, netinfo.DEFAULT_MTU) self.configApplier.ifdown(bonding) else: self._setNewMtu(bonding, netinfo.vlanDevsForIface(bonding.name)) def removeNic(self, nic): toBeRemoved = not netinfo.ifaceUsed(nic.name) if toBeRemoved: if nic.master is None: self.configApplier.removeIpConfig(nic) DynamicSourceRoute.addInterfaceTracking(nic) self._removeSourceRoute(nic, DynamicSourceRoute) else: self.configApplier.setIfaceMtu(nic.name, netinfo.DEFAULT_MTU) self.configApplier.ifdown(nic) else: self._setNewMtu(nic, netinfo.vlanDevsForIface(nic.name)) @staticmethod def configureSourceRoute(routes, rules, device): for route in routes: routeAdd(route) for rule in rules: ruleAdd(rule) @staticmethod def removeSourceRoute(routes, rules, device): for route in routes: try: routeDel(route) except IPRoute2Error as e: if "No such process" in e.message[0]: # The kernel or dhclient has won the race and removed the # route already. We have yet to remove routing rules. pass else: raise for rule in rules: ruleDel(rule)