diff options
Diffstat (limited to 'compass-tasks-base/hdsdiscovery/base.py')
-rw-r--r-- | compass-tasks-base/hdsdiscovery/base.py | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/compass-tasks-base/hdsdiscovery/base.py b/compass-tasks-base/hdsdiscovery/base.py new file mode 100644 index 0000000..77b3b0b --- /dev/null +++ b/compass-tasks-base/hdsdiscovery/base.py @@ -0,0 +1,185 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# Licensed 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. + +""" +Base class extended by specific vendor in vendors directory. +A vendor needs to implement abstract methods of base class. +""" +import logging +import re + +from abc import ABCMeta + +from compass.hdsdiscovery.error import TimeoutError +from compass.hdsdiscovery import utils + + +class BaseVendor(object): + """Basic Vendor object.""" + __metaclass__ = ABCMeta + + def is_this_vendor(self, sys_info, **kwargs): + """Determine if the host is associated with this vendor. + + This function must be implemented by vendor itself + """ + raise NotImplementedError + + +class BaseSnmpVendor(BaseVendor): + """Base SNMP-based vendor plugin. + + .. note:: + It uses MIB-II sysDescr value to determine the vendor of the switch. + """ + + def __init__(self, matched_names): + super(BaseSnmpVendor, self).__init__() + self._matched_names = matched_names + + def is_this_vendor(self, sys_info, **kwargs): + """Determine if the switch belongs to this vendor. + + Matching the system information retrieved from the switch. + :param str sys_info: the system information retrieved from a switch + Return True + """ + if sys_info: + for name in self._matched_names: + if re.search(r"\b" + re.escape(name) + r"\b", sys_info, + re.IGNORECASE): + return True + return False + + +class BasePlugin(object): + """Extended by vendor's plugin. + + This plugin processes request and retrieve info directly from the switch. + """ + __metaclass__ = ABCMeta + + def process_data(self, oper='SCAN', **kwargs): + """Each vendors will have some plugins to do some operations. + + Plugin will process request data and return expected result. + + :param oper: operation function name. + :param kwargs: key-value pairs of arguments + """ + raise NotImplementedError + + # At least one of these three functions below must be implemented. + def scan(self, **kwargs): + """Get multiple records at once.""" + pass + + def set(self, **kwargs): + """Set value to desired variable.""" + pass + + def get(self, **kwargs): + """Get one record from a host.""" + pass + + +class BaseSnmpMacPlugin(BasePlugin): + """Base snmp plugin.""" + + def __init__(self, host, credential, oid='BRIDGE-MIB::dot1dTpFdbPort', + vlan_oid='Q-BRIDGE-MIB::dot1qPvid'): + super(BaseSnmpMacPlugin, self).__init__() + self.host = host + self.credential = credential + self.oid = oid + self.port_oid = 'ifName' + self.vlan_oid = vlan_oid + + def process_data(self, oper='SCAN', **kwargs): + """progress data.""" + func_name = oper.lower() + return getattr(self, func_name)(**kwargs) + + def scan(self, **kwargs): + """scan.""" + results = None + try: + results = utils.snmpwalk_by_cl(self.host, self.credential, + self.oid) + except TimeoutError as error: + logging.debug("PluginMac:scan snmpwalk_by_cl failed: %s", + error.message) + return None + + mac_list = [] + for entity in results: + if_index = entity['value'] + if entity and int(if_index): + tmp = {} + mac_numbers = entity['iid'].split('.') + tmp['mac'] = self.get_mac_address(mac_numbers) + tmp['port'] = self.get_port(if_index) + tmp['vlan'] = self.get_vlan_id(if_index) + mac_list.append(tmp) + + return mac_list + + def get_vlan_id(self, port): + """Get vlan Id.""" + if not port: + return None + + oid = '.'.join((self.vlan_oid, port)) + vlan_id = None + result = None + try: + result = utils.snmpget_by_cl(self.host, self.credential, oid) + except TimeoutError as error: + logging.debug("[PluginMac:get_vlan_id snmpget_by_cl failed: %s]", + error.message) + return None + + vlan_id = result.split()[-1] + return vlan_id + + def get_port(self, if_index): + """Get port number.""" + + if_name = '.'.join((self.port_oid, if_index)) + result = None + try: + result = utils.snmpget_by_cl(self.host, self.credential, if_name) + except TimeoutError as error: + logging.debug("[PluginMac:get_port snmpget_by_cl failed: %s]", + error.message) + return None + + # A result may be like "Value: FasterEthernet1/2/34 + port = result.split()[-1].split('/')[-1] + return port + + def convert_to_hex(self, value): + """Convert the integer from decimal to hex.""" + + return "%0.2x" % int(value) + + def get_mac_address(self, mac_numbers): + """Assemble mac address from the list.""" + if len(mac_numbers) != 6: + logging.error("[PluginMac:get_mac_address] MAC address must be " + "6 digitals") + return None + + mac_in_hex = [self.convert_to_hex(num) for num in mac_numbers] + return ":".join(mac_in_hex) |