from OvmCommonModule import * import traceback import time import re logger = OvmLogger("OvmNetwork") class Filter: class Network: IFNAME_LO = r'(lo)' IFNAME_PIF = r'(eth\d+$)' IFNAME_VLAN = r'(eth\d+.\d+$)' IFNAME_BRIDGE = r'(xenbr\d+|vlan\d+)' class Parser(object): ''' classdocs ''' def findall(self, pattern, samples): """ @param pattern: search pattern @param result: Parser line execution result @return : list of search find result of Parser which has same pattern findall Parser find all pattern in a string """ result = [] for line in samples: items = re.findall(pattern, line) for item in items: result.append(item) return result def checkPattern(self, pattern, cmd_result): """ @param pattern: search pattern @param cmd_result: Parser line execution result @return : True (if pattern is occurred) """ for line in cmd_result: items = re.findall(pattern, line) if len(items) > 0: return True return False def search(self, cmd_result, pattern): return None class OvmVlanDecoder(json.JSONDecoder): def decode(self, jStr): deDict = asciiLoads(jStr) vlan = OvmVlan() setAttrFromDict(vlan, 'vid', deDict, int) setAttrFromDict(vlan, 'pif', deDict) return vlan class OvmVlanEncoder(json.JSONEncoder): def default(self, obj): if not isinstance(obj, OvmVlan): raise Exception("%s is not instance of OvmVlan"%type(obj)) dct = {} safeDictSet(obj, dct, 'name') safeDictSet(obj, dct, 'vid') safeDictSet(obj, dct, 'pif') return dct def toOvmVlan(jStr): return json.loads(jStr, cls=OvmVlanDecoder) def fromOvmVlan(vlan): return normalizeToGson(json.dumps(vlan, cls=OvmVlanEncoder)) class OvmBridgeDecoder(json.JSONDecoder): def decode(self, jStr): deDic = asciiLoads(jStr) bridge = OvmBridge() setAttrFromDict(bridge, 'name', deDic) setAttrFromDict(bridge, 'attach', deDic) return bridge class OvmBridgeEncoder(json.JSONEncoder): def default(self, obj): if not isinstance(obj, OvmBridge): raise Exception("%s is not instance of OvmBridge"%type(obj)) dct = {} safeDictSet(obj, dct, 'name') safeDictSet(obj, dct, 'attach') safeDictSet(obj, dct, 'interfaces') return dct def toOvmBridge(jStr): return json.loads(jStr, cls=OvmBridgeDecoder) def fromOvmBridge(bridge): return normalizeToGson(json.dumps(bridge, cls=OvmBridgeEncoder)) class OvmInterface(OvmObject): name = '' class OvmVlan(OvmInterface): vid = 0 pif = '' class OvmBridge(OvmInterface): attach = '' interfaces = [] class OvmNetwork(OvmObject): ''' Network ''' @property def pifs(self): return self._getInterfaces("pif") @property def vlans(self): return self._getInterfaces("vlan") @property def bridges(self): return self._getInterfaces("bridge") def __init__(self): self.Parser = Parser() def _createVlan(self, vlan): """ @param jsonString : parameter from client side @return : succ xxxxx ex. jsonString => {vid:100, pif:eth0} ex. return => """ #Pre-condition #check Physical Interface Name if vlan.pif not in self.pifs.keys(): msg = "Physical Interface(%s) does not exist" % vlan.pif logger.debug(self._createVlan, msg) raise Exception(msg) #Pre-condition #check Vlan Interface Name ifName = "%s.%s" % (vlan.pif, vlan.vid) if ifName in self.vlans.keys(): msg = "Vlan Interface(%s) already exist, return it" % ifName logger.debug(self._createVlan, msg) return self.vlans[ifName] doCmd(['vconfig', 'add', vlan.pif, vlan.vid]) self.bringUP(ifName) logger.debug(self._createVlan, "Create vlan %s successfully"%ifName) return self.vlans[ifName] def _deleteVlan(self, name): if name not in self.vlans.keys(): raise Exception("No vlan device %s found"%name) vlan = self.vlans[name] self.bringDown(vlan.name) doCmd(['vconfig', 'rem', vlan.name]) logger.debug(self._deleteVlan, "Delete vlan %s successfully"%vlan.name) def _createBridge(self, bridge): """ @return : success ex. {bridge:xapi100, attach:eth0.100} create bridge interface, and attached it cmd 1: brctl addbr bridge cmd 2: brctl addif brdige attach """ if "xenbr" not in bridge.name and "vlan" not in bridge.name: raise Exception("Invalid bridge name %s. Bridge name must be in partten xenbr/vlan, e.g. xenbr0"%bridge.name) #pre-condition #check Bridge Interface Name if bridge.name in self.bridges.keys(): msg = "Bridge(%s) already exist, return it" % bridge.name logger.debug(self._createBridge, msg) return self.bridges[bridge.name] #pre-condition #check attach must exist #possible to attach in PIF or VLAN if bridge.attach not in self.vlans.keys() and bridge.attach not in self.pifs.keys(): msg = "%s is not either pif or vlan" % bridge.attach logger.error(self._createBridge, msg) raise Exception(msg) doCmd(['brctl', 'addbr', bridge.name]) doCmd(['brctl', 'addif', bridge.name, bridge.attach]) self.bringUP(bridge.name) logger.debug(self._createBridge, "Create bridge %s on %s successfully"%(bridge.name, bridge.attach)) return self.bridges[bridge.name] def _getBridges(self): return self.bridges.keys() def _getVlans(self): return self.vlans.keys() def _deleteBridge(self, name): if name not in self.bridges.keys(): raise Exception("Can not find bridge %s"%name) bridge = self.bridges[name] if bridge.attach in bridge.interfaces: bridge.interfaces.remove(bridge.attach) if len(bridge.interfaces) != 0: logger.debug(self._deleteBridge, "There are still some interfaces(%s) on bridge %s"%(bridge.interfaces, bridge.name)) return False self.bringDown(bridge.name) doCmd(['brctl', 'delbr', bridge.name]) logger.debug(self._deleteBridge, "Delete bridge %s successfully"%bridge.name) return True def _getInterfaces(self, type): """ @param type : ["pif", "bridge", "tap"] @return : dictionary of Interface Objects get All Interfaces based on type """ devices = os.listdir('/sys/class/net') ifs = {} if type == "pif": devs = self.Parser.findall(Filter.Network.IFNAME_PIF, devices) for dev in set(devs): ifInst = OvmInterface() ifInst.name = dev ifs[dev] = ifInst elif type == "vlan": devs = self.Parser.findall(Filter.Network.IFNAME_VLAN, devices) for dev in set(devs): ifInst = OvmVlan() ifInst.name = dev (pif, vid) = dev.split('.') ifInst.pif = pif ifInst.vid = vid ifs[dev] = ifInst elif type == "bridge": devs = self.Parser.findall(Filter.Network.IFNAME_BRIDGE, devices) for dev in set(devs): ifInst = OvmBridge() ifInst.name = dev devs = os.listdir(join('/sys/class/net', dev, 'brif')) ifInst.interfaces = devs attches = self.Parser.findall(Filter.Network.IFNAME_PIF, devs) + self.Parser.findall(Filter.Network.IFNAME_VLAN, devs) if len(attches) > 1: raise Exception("Multiple PIF on bridge %s (%s)"%(dev, attches)) elif len(attches) == 0: ifInst.attach = "null" elif len(attches) == 1: ifInst.attach = attches[0] ifs[dev] = ifInst return ifs def bringUP(self, ifName): doCmd(['ifconfig', ifName, 'up']) def bringDown(self, ifName): doCmd(['ifconfig', ifName, 'down']) @staticmethod def createBridge(jStr): try: network = OvmNetwork() network._createBridge(toOvmBridge(jStr)) return SUCC() except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.createBridge, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.createBridge), errmsg) @staticmethod def deleteBridge(name): try: network = OvmNetwork() network._deleteBridge(name) return SUCC() except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.deleteBridge, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.deleteBridge), errmsg) @staticmethod def getAllBridges(): try: network = OvmNetwork() rs = toGson(network._getBridges()) logger.debug(OvmNetwork.getAllBridges, rs) return rs except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.getAllBridges, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.getAllBridges), errmsg) @staticmethod def getBridgeByIp(ip): try: routes = doCmd(['ip', 'route']).split('\n') brName = None for r in routes: if ip in r and "xenbr" in r or "vlan" in r: brName = r.split(' ')[2] break if not brName: raise Exception("Cannot find bridge with IP %s"%ip) logger.debug(OvmNetwork.getBridgeByIp, "bridge:%s, ip:%s"%(brName, ip)) return toGson({"bridge":brName}) except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.getBridgeByIp, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.getBridgeByIp), errmsg) @staticmethod def getVlans(): try: network = OvmNetwork() rs = toGson(network._getVlans()) logger.debug(OvmNetwork.getVlans, rs) return rs except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.getVlans, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.getVlans), errmsg) @staticmethod def createVlan(jStr): try: network = OvmNetwork() vlan = network._createVlan(toOvmVlan(jStr)) rs = fromOvmVlan(vlan) logger.debug(OvmNetwork.createVlan, rs) return rs except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.createVlan, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.createVlan), errmsg) @staticmethod def createVlanBridge(bridgeDetails, vlanDetails): try: network = OvmNetwork() v = toOvmVlan(vlanDetails) b = toOvmBridge(bridgeDetails) vlan = network._createVlan(v) b.attach = vlan.name network._createBridge(b) return SUCC() except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.createVlanBridge, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.createVlanBridge), errmsg) @staticmethod def deleteVlanBridge(name): try: network = OvmNetwork() if name not in network.bridges.keys(): logger.debug(OvmNetwork.deleteVlanBridge, "No bridge %s found"%name) return SUCC() bridge = network.bridges[name] vlanName = bridge.attach if network._deleteBridge(name): if vlanName != "null": network._deleteVlan(vlanName) else: logger.warning(OvmNetwork.deleteVlanBridge, "Bridge %s has no vlan device"%name) return SUCC() except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.deleteVlanBridge, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.deleteVlanBridge), errmsg) @staticmethod def getBridgeDetails(name): try: network = OvmNetwork() if name not in network.bridges.keys(): raise Exception("No bridge %s found"%name) bridge = network.bridges[name] rs = fromOvmBridge(bridge) logger.debug(OvmNetwork.getBridgeDetails, rs) return rs except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.getBridgeDetails, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.getBridgeDetails), errmsg) @staticmethod def deleteVlan(name): try: network = OvmNetwork() network._deleteVlan(name) return SUCC() except Exception, e: errmsg = fmt_err_msg(e) logger.error(OvmNetwork.deleteVlan, errmsg) raise XmlRpcFault(toErrCode(OvmNetwork, OvmNetwork.deleteVlan), errmsg) if __name__ == "__main__": try: OvmNetwork.getBridgeDetails(sys.argv[1]) #======================================================================= # txt = json.dumps({"vid":104, "pif":"eth0"}) # txt2 = json.dumps({"name":"xapi3", "attach":"eth0.104"}) # print nw.createVlan(txt) # print nw.createBridge(txt2) # # nw.deleteBridge("xapi3") # nw.deleteVlan("eth0.104") #======================================================================= except Exception, e: print e