| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| from OvmCommonModule import * |
| import traceback |
| import time |
| import re |
| |
| logger = OvmLogger("OvmNetwork") |
| |
| class Filter: |
| class Network: |
| IFNAME_LO = r'(lo)' |
| IFNAME_BRIDGE = r'(xenbr\d+|vlan\d+)' |
| IFNAME_PIF = r'(eth\d+$|bond\d+$)' |
| IFNAME_VLAN = r'(eth\d+.\d+$|bond\d+.\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 |