def __init__(self, snmp_hander=None, logger=None): self._snmp_handler = None self.snmp_handler = snmp_hander self._root = RootElement() self._chassis = None self._ports = {} self._snmp_cache = {} self._logger = logger overridden_config = override_attributes_from_config(AireOSAutoload) self.supported_os = overridden_config.SUPPORTED_OS
def __init__(self, snmp_handler=None, logger=None, config=None, cli_service=None, snmp_community=None): self._content_indexes = None self._if_indexes = None self._logger = logger self._snmp_handler = None self.snmp_handler = snmp_handler self._config = config self._cli_service = cli_service self._snmp_community = snmp_community self._logical_generic_ports = {} self._physical_generic_ports = {} self._generic_physical_ports_by_description = None self._generic_logical_ports_by_description = None self._ports = {} self.sub_modules = {} self._modules = {} self._chassis = {} self._root = RootElement() self._ipv4_table = None self._ipv6_table = None self._if_duplex_table = None self._autoneg = None self._lldp_keys = None """Override attributes from global config""" overridden_config = override_attributes_from_config(JuniperSnmpAutoload, config=self.config) self._supported_os = overridden_config.SUPPORTED_OS
class AireOSAutoload(AutoloadOperationsInterface): PORT_DESCRIPTION_FILTER = [r'[Vv]irtual', r'[Cc]hannel'] SUPPORTED_OS = [r'Controller'] def __init__(self, snmp_hander=None, logger=None): self._snmp_handler = None self.snmp_handler = snmp_hander self._root = RootElement() self._chassis = None self._ports = {} self._snmp_cache = {} self._logger = logger overridden_config = override_attributes_from_config(AireOSAutoload) self.supported_os = overridden_config.SUPPORTED_OS @property def snmp_handler(self): if self._snmp_handler is None: self.snmp_handler = inject.instance(SNMP_HANDLER) return self._snmp_handler @snmp_handler.setter def snmp_handler(self, snmp_handler): if snmp_handler: self._snmp_handler = snmp_handler path = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', 'mibs')) self._snmp_handler.update_mib_sources(path) @property def logger(self): if self._logger is not None: return self._logger return inject.instance(LOGGER) def _snmp_request(self, request_data): if isinstance(request_data, tuple): if request_data in self._snmp_cache: result = self._snmp_cache[request_data] else: if len(request_data) == 2: result = self.snmp_handler.walk(request_data) elif len(request_data) == 3: result = self.snmp_handler.get_property(*request_data) else: raise Exception('_snmp_request', 'Request tuple len has to be 2 or 3') self._snmp_cache[request_data] = result else: raise Exception('_snmp_request', 'Has to be tuple') return result def _get_from_table(self, key, table): if key in table: return table[key] else: return None def _match_pattern_list(self, pattern_list, data): for pattern in pattern_list: if re.search(pattern, data): return True return False def _build_root_elements(self): root_attributes = dict() root_attributes[RootAttributes.CONTACT_NAME] = self._snmp_request( ('SNMPv2-MIB', 'sysContact', '0')) root_attributes[RootAttributes.SYSTEM_NAME] = self._snmp_request( ('SNMPv2-MIB', 'sysName', '0')) root_attributes[RootAttributes.LOCATION] = self._snmp_request( ('SNMPv2-MIB', 'sysLocation', '0')) root_attributes[RootAttributes.OS_VERSION] = self._snmp_request( ('ENTITY-MIB', 'entPhysicalSoftwareRev', '1')) root_attributes[RootAttributes.VENDOR] = self._snmp_request( ('SNMPv2-MIB', 'sysObjectID', '0')) root_attributes[RootAttributes.MODEL] = self._snmp_request( ('ENTITY-MIB', 'entPhysicalDescr', '1')) self._root.build_attributes(root_attributes) def _build_chassis_elements(self): entity_table = self._snmp_request(('ENTITY-MIB', 'entPhysicalTable')) chassis_id = None entity_data = None if entity_table is not None and len(entity_table) > 0: for id, table in entity_table.iteritems(): if re.search(r'[Cc]hassis', table.get('entPhysicalName')) and table.get( 'entPhysicalParentRelPos') == '-1': chassis_id = id entity_data = table break else: raise Exception('_build_chassis_elements', 'Entity table is empty') if chassis_id and entity_data: self._chassis = Chassis(chassis_id) else: raise Exception('_build_chassis_elements', 'Cannot find chassis data in entity table') chassis_attributes = dict() chassis_attributes[ChassisAttributes.MODEL] = self._get_from_table( 'entPhysicalModelName', entity_data) chassis_attributes[ ChassisAttributes.SERIAL_NUMBER] = self._get_from_table( 'entPhysicalSerialNum', entity_data) self._chassis.build_attributes(chassis_attributes) self._root.chassis.append(self._chassis) def _build_ports(self): if_mib_table = self._snmp_request(('IF-MIB', 'ifTable')) for index, table in if_mib_table.iteritems(): port_description = self._get_from_table('ifDescr', table) if self._match_pattern_list(self.PORT_DESCRIPTION_FILTER, port_description): break port_index = self._get_from_table('ifIndex', table) port = Port(port_index, self._convert_port_description(port_description)) port_attributes = dict() port_attributes[ PortAttributes.PORT_DESCRIPTION] = self._snmp_request( ('IF-MIB', 'ifAlias', index)) port_attributes[PortAttributes.L2_PROTOCOL_TYPE] = str( self._get_from_table('ifType', table)).replace("""'""", '') port_attributes[PortAttributes.MAC_ADDRESS] = self._get_from_table( 'ifPhysAddress', table) port_attributes[PortAttributes.MTU] = self._get_from_table( 'ifMtu', table) port_attributes[PortAttributes.BANDWIDTH] = self._get_from_table( 'ifSpeed', table) port_attributes[PortAttributes. IPV4_ADDRESS] = self._find_associated_ipv4(index) port_attributes[PortAttributes. IPV6_ADDRESS] = self._find_associated_ipv6(index) port_attributes[PortAttributes.DUPLEX] = self._get_duplex(index) port_attributes[ PortAttributes.AUTO_NEGOTIATION] = self._get_autonegotiation( index) # port_attributes[PortAttributes.ADJACENT] = self._get_adjacent(index) port.build_attributes(port_attributes) self._ports[port_index] = port self._chassis.ports.append(port) def _build_port_channels(self): if_mib_table = self._snmp_request(('IF-MIB', 'ifTable')) for index, table in if_mib_table.iteritems(): description = table['ifDescr'] if re.search(r'[Cc]hannel', description) and '.' not in description: suitable_description = self._convert_port_description( description) port = PortChannel(self._get_from_table('ifIndex', table), suitable_description) pc_attributes = dict() pc_attributes[PortChannelAttributes. PORT_DESCRIPTION] = self._snmp_request( ('IF-MIB', 'ifAlias', index)) pc_attributes[PortChannelAttributes. PROTOCOL_TYPE] = self._get_from_table( 'ifType', table) pc_attributes[PortChannelAttributes. IPV4_ADDRESS] = self._find_associated_ipv4(index) pc_attributes[PortChannelAttributes. IPV6_ADDRESS] = self._find_associated_ipv6(index) pc_attributes[PortChannelAttributes. ASSOCIATED_PORTS] = self._get_associated_ports( index) port.build_attributes(pc_attributes) self._root.port_channels.append(port) def _get_duplex(self, index): duplex_table = self._snmp_request( ('EtherLike-MIB', 'dot3StatsDuplexStatus')) duplex = None if len(duplex_table) > 0: if index in duplex_table: duplex = duplex_table[index] return duplex def _get_autonegotiation(self, index): """Get Autonegotiation for interface :param index: port id :return: Autonegotiation for interface :rtype string """ autoneg = 'False' try: auto_negotiation = self.snmp_handler.get( ('MAU-MIB', 'ifMauAutoNegAdminStatus', index, 1)).values()[0] if 'enabled' in auto_negotiation.lower(): autoneg = 'True' except Exception as e: self.logger.error( 'Failed to load auto negotiation property for interface {0}'. format(e.message)) return autoneg def _get_adjacent(self, interface_id): """Get connected device interface and device name to the specified port id, using cdp or lldp protocols :param interface_id: port id :return: device's name and port connected to port id :rtype string """ lldp_local_table = self._snmp_request(('LLDP-MIB', 'lldpLocPortDesc')) lldp_remote_table = self._snmp_request(('LLDP-MIB', 'lldpRemTable')) # cdp_index_table = self._snmp_request(('CISCO-CDP-MIB', 'cdpInterface')) cdp_table = self._snmp_request(('CISCO-CDP-MIB', 'cdpCacheTable')) result = '' for key, value in cdp_table.iteritems(): if 'cdpCacheDeviceId' in value and 'cdpCacheDevicePort' in value: if re.search('^\d+', str(key)).group(0) == interface_id: result = '{0} through {1}'.format( value['cdpCacheDeviceId'], value['cdpCacheDevicePort']) if result == '' and lldp_remote_table: for key, value in lldp_local_table.iteritems(): interface_name = self._snmp_request( ('IF-MIB', 'ifTable'))[interface_id]['ifDescr'] if interface_name == '': break if 'lldpLocPortDesc' in value and interface_name in value[ 'lldpLocPortDesc']: if 'lldpRemSysName' in lldp_remote_table and 'lldpRemPortDesc' in lldp_remote_table: result = '{0} through {1}'.format( lldp_remote_table[key]['lldpRemSysName'], lldp_remote_table[key]['lldpRemPortDesc']) return result def _find_associated_ipv4(self, port_index): ip_addr_table = self._snmp_request(('IP-MIB', 'ipAddrTable')) for ip, data in ip_addr_table.iteritems(): if 'ipAdEntIfIndex' in data and port_index == data[ 'ipAdEntIfIndex']: return data['ipAdEntAddr'] return None def _find_associated_ipv6(self, port_index): ipv6_table = self._snmp_request(('IPV6-MIB', 'ipv6AddrEntry')) for ip, data in ipv6_table.iteritems(): if 'ipAdEntIfIndex' in data and port_index == data[ 'ipAdEntIfIndex']: return data['ipAdEntAddr'] return None def _get_associated_ports(self, index): agg_table = self._snmp_request( ('IEEE8023-LAG-MIB', 'dot3adAggPortAttachedAggID')) result = '' for key, value in agg_table.iteritems(): if str(index) in value['dot3adAggPortAttachedAggID']: if key in self._ports: phisical_port = self._ports[key] if result: result += ',' + phisical_port.name else: result = phisical_port.name return result.strip(' \t\n\r') def _convert_port_description(self, description): return description.replace('/', '-').replace(' ', '').replace(':', '-') def _is_valid_device_os(self): """Validate device OS using snmp :return: True or False """ system_description = self._snmp_request(('SNMPv2-MIB', 'sysDescr', 0)) self.logger.debug( 'Detected system description: \'{0}\''.format(system_description)) result = re.search(r"({0})".format("|".join(self.supported_os)), system_description, flags=re.DOTALL | re.IGNORECASE) if result: return True else: error_message = 'Incompatible driver! Please use this driver for \'{0}\' operation system(s)'. \ format(str(tuple(self.supported_os))) self.logger.error(error_message) return False def discover(self): if not self._is_valid_device_os(): raise Exception( self.__class__.__name__, 'Unsupported device OS, see logs for more details') self._build_root_elements() self._build_chassis_elements() self._build_ports() self._build_port_channels() self._root.build_relative_path() autoload_details = AutoLoadDetails(self._root.get_resources(), self._root.get_attributes()) return autoload_details
class JuniperSnmpAutoload(AutoloadOperationsInterface): """ Load inventory by snmp and build device elements and attributes """ FILTER_PORTS_BY_DESCRIPTION = ['bme', 'vme', 'me', 'vlan', 'gr', 'vt', 'mt', 'mams', 'irb', 'lsi', 'tap', 'fxp'] FILTER_PORTS_BY_TYPE = ['tunnel', 'other', 'pppMultilinkBundle', 'mplsTunnel', 'softwareLoopback'] SUPPORTED_OS = [r'[Jj]uniper'] def __init__(self, snmp_handler=None, logger=None, config=None, cli_service=None, snmp_community=None): self._content_indexes = None self._if_indexes = None self._logger = logger self._snmp_handler = None self.snmp_handler = snmp_handler self._config = config self._cli_service = cli_service self._snmp_community = snmp_community self._logical_generic_ports = {} self._physical_generic_ports = {} self._generic_physical_ports_by_description = None self._generic_logical_ports_by_description = None self._ports = {} self.sub_modules = {} self._modules = {} self._chassis = {} self._root = RootElement() self._ipv4_table = None self._ipv6_table = None self._if_duplex_table = None self._autoneg = None self._lldp_keys = None """Override attributes from global config""" overridden_config = override_attributes_from_config(JuniperSnmpAutoload, config=self.config) self._supported_os = overridden_config.SUPPORTED_OS @property def snmp_community(self): if self._snmp_community is None: self._snmp_community = get_attribute_by_name("SNMP Read Community") or "quali" return self._snmp_community def enable_snmp(self): """Enable SNMP Agent on the device and configure community string if needed NOTE: this will work only for devices with Junos OS """ snmp_community_info = self.cli_service.send_config_command('show snmp community "{}"' .format(self.snmp_community)) if "authorization read" not in snmp_community_info: self.logger.debug("SNMP community string '{}' is not present on the device. " "Trying to add it".format(self.snmp_community)) self.cli_service.send_command_list([ enable_disable_snmp.ENTER_EDIT_SNMP.get_command(), enable_disable_snmp.ENABLE_SNMP.get_command(self.snmp_community), enable_disable_snmp.EXIT_EDIT_SNMP.get_command(), ]) self.cli_service.commit() self.logger.debug("SNMP community string '{}' was added to the the device.".format(self.snmp_community)) def disable_snmp(self): """Disable SNMP Agent on the device NOTE: this will work only for devices with Junos OS """ self.logger.debug("Trying to delete SNMP configuration from the device") self.cli_service.send_config_command(enable_disable_snmp.DISABLE_SNMP.get_command()) self.cli_service.commit() self.logger.debug("SNMP configuration was successfully deleted from the device") @property def logger(self): return self._logger or inject.instance(LOGGER) @property def config(self): return self._config or inject.instance(CONFIG) @property def snmp_handler(self): if self._snmp_handler is None: self.snmp_handler = inject.instance(SNMP_HANDLER) return self._snmp_handler @snmp_handler.setter def snmp_handler(self, snmp_handler): if snmp_handler: self._snmp_handler = snmp_handler self._initialize_snmp_handler() @property def cli_service(self): return self._cli_service or inject.instance(CLI_SERVICE) @property def ipv4_table(self): if not self._ipv4_table: self._ipv4_table = sort_elements_by_attributes( self._snmp_handler.walk(('IP-MIB', 'ipAddrTable')), 'ipAdEntIfIndex') return self._ipv4_table @property def ipv6_table(self): if not self._ipv6_table: self._ipv6_table = sort_elements_by_attributes( self._snmp_handler.walk(('IPV6-MIB', 'ipv6AddrEntry')), 'ipAdEntIfIndex') return self._ipv6_table @property def generic_physical_ports_by_description(self): if not self._generic_physical_ports_by_description: self._generic_physical_ports_by_description = {} for index, generic_port in self._physical_generic_ports.iteritems(): self._generic_physical_ports_by_description[generic_port.port_description] = generic_port return self._generic_physical_ports_by_description @property def generic_logical_ports_by_description(self): if not self._generic_logical_ports_by_description: self._generic_logical_ports_by_description = {} for index, generic_port in self._logical_generic_ports.iteritems(): self._generic_logical_ports_by_description[generic_port.port_description] = generic_port return self._generic_logical_ports_by_description def _build_lldp_keys(self): result_dict = {} keys = self.snmp_handler.walk(('LLDP-MIB', 'lldpRemPortId')).keys() for key in keys: key_splited = str(key).split('.') if len(key_splited) == 3: result_dict[key_splited[1]] = key elif len(key_splited) == 1: result_dict[key_splited[0]] = key return result_dict @property def lldp_keys(self): if not self._lldp_keys: self._lldp_keys = self._build_lldp_keys() return self._lldp_keys def _initialize_snmp_handler(self): """ Snmp settings and load specific mibs :return: """ path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'mibs')) self.snmp_handler.update_mib_sources(path) self.logger.info("Loading mibs") self.snmp_handler.load_mib('JUNIPER-MIB') self.snmp_handler.load_mib('JUNIPER-IF-MIB') self.snmp_handler.load_mib('IF-MIB') self.snmp_handler.load_mib('JUNIPER-CHASSIS-DEFINES-MIB') self.snmp_handler.load_mib('IEEE8023-LAG-MIB') self.snmp_handler.load_mib('EtherLike-MIB') self.snmp_handler.load_mib('IP-MIB') self.snmp_handler.load_mib('IPV6-MIB') self.snmp_handler.load_mib('LLDP-MIB') def _build_root(self): """ Collect device root attributes :return: """ self.logger.info("Building Root") vendor = '' model = '' os_version = '' sys_obj_id = self.snmp_handler.get_property('SNMPv2-MIB', 'sysObjectID', 0) model_search = re.search('^(?P<vendor>\w+)-\S+jnxProductName(?P<model>\S+)', sys_obj_id ) if model_search: vendor = model_search.groupdict()['vendor'].capitalize() model = model_search.groupdict()['model'] sys_descr = self.snmp_handler.get_property('SNMPv2-MIB', 'sysDescr', '0') os_version_search = re.search('JUNOS \S+(,)?\s', sys_descr, re.IGNORECASE) if os_version_search: os_version = os_version_search.group(0).replace('JUNOS ', '').replace(',', '').strip(' \t\n\r') root_attributes = dict() root_attributes[RootAttributes.CONTACT_NAME] = self.snmp_handler.get_property('SNMPv2-MIB', 'sysContact', '0') root_attributes[RootAttributes.SYSTEM_NAME] = self.snmp_handler.get_property('SNMPv2-MIB', 'sysName', '0') root_attributes[RootAttributes.LOCATION] = self.snmp_handler.get_property('SNMPv2-MIB', 'sysLocation', '0') root_attributes[RootAttributes.OS_VERSION] = os_version root_attributes[RootAttributes.VENDOR] = vendor root_attributes[RootAttributes.MODEL] = model self._root.build_attributes(root_attributes) def _get_content_indexes(self): container_indexes = self.snmp_handler.walk(('JUNIPER-MIB', 'jnxContentsContainerIndex')) content_indexes = {} for index, value in container_indexes.iteritems(): ct_index = value['jnxContentsContainerIndex'] if ct_index in content_indexes: content_indexes[ct_index].append(index) else: content_indexes[ct_index] = [index] return content_indexes @property def content_indexes(self): if not self._content_indexes: self._content_indexes = self._get_content_indexes() return self._content_indexes @property def if_indexes(self): if not self._if_indexes: self._if_indexes = self.snmp_handler.walk(('JUNIPER-IF-MIB', 'ifChassisPort')).keys() return self._if_indexes def _build_chassis(self): """ Build Chassis resources and attributes :return: """ self.logger.debug('Building Chassis') element_index = '1' chassis_snmp_attributes = {'jnxContentsModel': 'str', 'jnxContentsType': 'str', 'jnxContentsSerialNo': 'str', 'jnxContentsChassisId': 'str'} if element_index in self.content_indexes: for index in self.content_indexes[element_index]: content_data = self.snmp_handler.get_properties('JUNIPER-MIB', index, chassis_snmp_attributes).get( index) index1, index2, index3, index4 = index.split('.')[:4] chassis_id = index2 chassis = Chassis(chassis_id) chassis_attributes = dict() chassis_attributes[ChassisAttributes.MODEL] = self._get_element_model(content_data) chassis_attributes[ChassisAttributes.SERIAL_NUMBER] = content_data.get('jnxContentsSerialNo') chassis.build_attributes(chassis_attributes) self._root.chassis.append(chassis) chassis_id_str = content_data.get('jnxContentsChassisId') if chassis_id_str: self._chassis[chassis_id_str.strip('\'')] = chassis def _build_power_modules(self): """ Build Power modules resources and attributes :return: """ self.logger.debug('Building PowerPorts') power_modules_snmp_attributes = {'jnxContentsModel': 'str', 'jnxContentsType': 'str', 'jnxContentsDescr': 'str', 'jnxContentsSerialNo': 'str', 'jnxContentsRevision': 'str', 'jnxContentsChassisId': 'str'} element_index = '2' if element_index in self.content_indexes: for index in self.content_indexes[element_index]: content_data = self.snmp_handler.get_properties('JUNIPER-MIB', index, power_modules_snmp_attributes).get(index) index1, index2, index3, index4 = index.split('.')[:4] element_id = index2 element = PowerPort(element_id) element_attributes = dict() element_attributes[PowerPortAttributes.MODEL] = self._get_element_model(content_data) element_attributes[PowerPortAttributes.PORT_DESCRIPTION] = content_data.get('jnxContentsDescr') element_attributes[PowerPortAttributes.SERIAL_NUMBER] = content_data.get('jnxContentsSerialNo') element_attributes[PowerPortAttributes.VERSION] = content_data.get('jnxContentsRevision') element.build_attributes(element_attributes) chassis_id_str = content_data.get('jnxContentsChassisId') if chassis_id_str: chassis = self._chassis.get(chassis_id_str.strip('\'')) if chassis: chassis.power_ports.append(element) def _build_modules(self): """ Build Modules resources and attributes :return: """ self.logger.debug('Building Modules') modules_snmp_attributes = {'jnxContentsModel': 'str', 'jnxContentsType': 'str', 'jnxContentsSerialNo': 'str', 'jnxContentsRevision': 'str', 'jnxContentsChassisId': 'str'} element_index = '7' if element_index in self.content_indexes: for index in self.content_indexes[element_index]: content_data = self.snmp_handler.get_properties('JUNIPER-MIB', index, modules_snmp_attributes).get(index) index1, index2, index3, index4 = index.split('.')[:4] element_id = index2 element = Module(element_id) element_attributes = dict() element_attributes[ModuleAttributes.MODEL] = self._get_element_model(content_data) element_attributes[ModuleAttributes.SERIAL_NUMBER] = content_data.get('jnxContentsSerialNo') element_attributes[ModuleAttributes.VERSION] = content_data.get('jnxContentsRevision') element.build_attributes(element_attributes) chassis_id_str = content_data.get('jnxContentsChassisId') if chassis_id_str: chassis = self._chassis.get(chassis_id_str.strip('\'')) if chassis: chassis.modules.append(element) self._modules[element_id] = element def _build_sub_modules(self): """ Build SubModules resources and attributes :return: """ self.logger.debug('Building Sub Modules') sub_modules_snmp_attributes = {'jnxContentsModel': 'str', 'jnxContentsType': 'str', 'jnxContentsSerialNo': 'str', 'jnxContentsRevision': 'str'} element_index = '8' if element_index in self.content_indexes: for index in self.content_indexes[element_index]: content_data = self.snmp_handler.get_properties('JUNIPER-MIB', index, sub_modules_snmp_attributes).get(index) index1, index2, index3, index4 = index.split('.')[:4] parent_id = index2 element_id = index3 element = SubModule(element_id) element_attributes = dict() element_attributes[SubModuleAttributes.MODEL] = self._get_element_model(content_data) element_attributes[SubModuleAttributes.SERIAL_NUMBER] = content_data.get('jnxContentsSerialNo') element_attributes[SubModuleAttributes.VERSION] = content_data.get('jnxContentsRevision') element.build_attributes(element_attributes) if parent_id in self._modules: self._modules[parent_id].sub_modules.append(element) self.sub_modules[element_id] = element @staticmethod def _get_element_model(content_data): model_string = content_data.get('jnxContentsModel') if not model_string: model_string = content_data.get('jnxContentsType').split('::')[-1] return model_string def _build_generic_ports(self): """ Build GenericPort instances :return: """ self.logger.debug("Building generic ports") for index in self.if_indexes: index = int(index) generic_port = GenericPort(index, self.snmp_handler) if not self._port_filtered_by_description(generic_port) and not self._port_filtered_by_type(generic_port): if generic_port.logical_unit == '0': self._physical_generic_ports[index] = generic_port else: self._logical_generic_ports[index] = generic_port def _associate_ipv4_addresses(self): """ Associates ipv4 with generic port :return: """ self.logger.debug("Associate ipv4") for index in self.ipv4_table: if int(index) in self._logical_generic_ports: logical_port = self._logical_generic_ports[int(index)] physical_port = self._get_associated_phisical_port_by_description(logical_port.port_description) ipv4_address = self.ipv4_table[index].get('ipAdEntAddr') if physical_port and ipv4_address: physical_port.ipv4_addresses.append(ipv4_address) def _associate_ipv6_addresses(self): """ Associate ipv6 with generic port :return: """ self.logger.debug("Associate ipv6") for index in self.ipv6_table: if int(index) in self._logical_generic_ports: logical_port = self._logical_generic_ports[int(index)] physical_port = self._get_associated_phisical_port_by_description(logical_port.port_description) ipv6_address = self.ipv6_table[index].get('ipAdEntAddr') if ipv6_address: physical_port.ipv6_addresses.append(ipv6_address) def _associate_portchannels(self): """ Associate physical ports with the portchannel :return: """ self.logger.debug("Associate portchannels") snmp_data = self._snmp_handler.walk(('IEEE8023-LAG-MIB', 'dot3adAggPortAttachedAggID')) for port_index in snmp_data: port_index = int(port_index) if port_index in self._logical_generic_ports: associated_phisical_port = self._get_associated_phisical_port_by_description( self._logical_generic_ports[port_index].port_description) logical_portchannel_index = snmp_data[port_index].get('dot3adAggPortAttachedAggID') if logical_portchannel_index and int(logical_portchannel_index) in self._logical_generic_ports: associated_phisical_portchannel = self._get_associated_phisical_port_by_description( self._logical_generic_ports[int(logical_portchannel_index)].port_description) if associated_phisical_portchannel: associated_phisical_portchannel.is_portchannel = True if associated_phisical_port: associated_phisical_portchannel.associated_port_names.append(associated_phisical_port.name) def _associate_adjacent(self): for index in self.lldp_keys: if int(index) in self._logical_generic_ports: rem_port_descr = self._snmp_handler.get_property('LLDP-MIB', 'lldpRemPortDesc', self.lldp_keys[index]) rem_sys_descr = self._snmp_handler.get_property('LLDP-MIB', 'lldpRemSysDesc', self.lldp_keys[index]) physical_port = self._get_associated_phisical_port_by_description( self._logical_generic_ports[int(index)].port_description) physical_port.port_adjacent = '{0}, {1}'.format(rem_port_descr, rem_sys_descr) def _get_associated_phisical_port_by_description(self, description): """ Associate physical port by description :param description: :return: """ for port_description in self.generic_physical_ports_by_description: if port_description in description: return self.generic_physical_ports_by_description[port_description] return None def _port_filtered_by_description(self, port): """ Filter ports by description :param port: :return: """ for pattern in self.FILTER_PORTS_BY_DESCRIPTION: if re.search(pattern, port.port_description): return True return False def _port_filtered_by_type(self, port): """ Filter ports by type :param port: :return: """ if port.type in self.FILTER_PORTS_BY_TYPE: return True return False def _build_ports(self): """ Associate ports with the structure resources and build Ports and PortChannels :return: """ self.logger.debug("Building ports") self._build_generic_ports() self._associate_ipv4_addresses() self._associate_ipv6_addresses() self._associate_portchannels() self._associate_adjacent() for generic_port in self._physical_generic_ports.values(): if generic_port.is_portchannel: self._root.port_channels.append(generic_port.get_portchannel()) else: port = generic_port.get_port() if generic_port.fpc_id > 0 and generic_port.fpc_id in self._modules: fpc = self._modules.get(generic_port.fpc_id) if fpc and generic_port.pic_id > 0: pic = self._get_pic_by_index(fpc, int(generic_port.pic_id)) if pic: pic.ports.append(port) else: self.logger.info('Port {} is not allowed'.format(port.name)) else: fpc.ports.append(port) else: chassis = self._chassis.values()[0] chassis.ports.append(generic_port.get_port()) def _get_pic_by_index(self, fpc, index): for pic in fpc.sub_modules: if pic.element_id == index: return pic return None def _is_valid_device_os(self): """Validate device OS using snmp :return: True or False """ system_description = self.snmp_handler.get_property('SNMPv2-MIB', 'sysDescr', '0') self.logger.debug('Detected system description: \'{0}\''.format(system_description)) result = re.search(r"({0})".format("|".join(self._supported_os)), system_description, flags=re.DOTALL | re.IGNORECASE) if result: return True else: error_message = 'Incompatible driver! Please use this driver for \'{0}\' operation system(s)'. \ format(str(tuple(self._supported_os))) self.logger.error(error_message) return False def _log_autoload_details(self, autoload_details): """ Logging autoload details :param autoload_details: :return: """ self.logger.debug('-------------------- <RESOURCES> ----------------------') for resource in autoload_details.resources: self.logger.debug('{0}, {1}'.format(resource.relative_address, resource.name)) self.logger.debug('-------------------- </RESOURCES> ----------------------') self.logger.debug('-------------------- <ATTRIBUTES> ---------------------') for attribute in autoload_details.attributes: self.logger.debug('-- {0}, {1}, {2}'.format(attribute.relative_address, attribute.attribute_name, attribute.attribute_value)) self.logger.debug('-------------------- </ATTRIBUTES> ---------------------') def discover(self): """ Call methods in specific order to build resources and attributes :return: """ try: enable_snmp = get_attribute_by_name('Enable SNMP').lower() == 'true' disable_snmp = get_attribute_by_name('Disable SNMP').lower() == 'true' except Exception: enable_snmp = True disable_snmp = False if enable_snmp: self.enable_snmp() if not self._is_valid_device_os(): raise Exception(self.__class__.__name__, 'Unsupported device OS') try: self._build_root() self._build_chassis() self._build_power_modules() self._build_modules() self._build_sub_modules() self._build_ports() autoload_details = self._root.get_autoload_details() self._log_autoload_details(autoload_details) finally: if disable_snmp: self.disable_snmp() return autoload_details