def __init__(self, snmp_handler, shell_name, shell_type, resource_name, logger): """Init command. :param snmp_handler: :param shell_name: :param shell_type: :param resource_name: :param logger: """ self.snmp_handler = snmp_handler self.shell_name = shell_name self.shell_type = shell_type self.resource_name = resource_name self.logger = logger self.elements = {} self.resource = GenericResource( shell_name=shell_name, shell_type=shell_type, name=resource_name, unique_id=resource_name, ) self.chassis = GenericChassis( shell_name=self.shell_name, name="Chassis", unique_id="{}.{}".format(self.resource_name, "chassis"), ) self.resource.add_sub_resource("1", self.chassis)
def _get_chassis_attributes(self, chassis_list): """ Get Chassis element attributes """ self.logger.info("Building Chassis") for chassis in chassis_list: chassis_id = self.cisco_entity.relative_address[chassis] chassis_object = GenericChassis( shell_name=self.shell_name, name="Chassis {}".format(chassis_id), unique_id="{}.{}.{}".format(self.resource_name, "chassis", chassis)) chassis_object.model = self.snmp_handler.get_property("ENTITY-MIB", "entPhysicalModelName", chassis) or \ self.entity_table[chassis]["entPhysicalDescr"] chassis_object.serial_number = self.snmp_handler.get_property( "ENTITY-MIB", "entPhysicalSerialNum", chassis) relative_address = "{0}".format(chassis_id) self._add_element(relative_path=relative_address, resource=chassis_object) self.logger.info("Added " + self.entity_table[chassis]["entPhysicalDescr"] + " Chassis") self.logger.info("Building Chassis completed")
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(self.__class__.__name__, 'Entity table is empty') if chassis_id and entity_data: self._chassis = GenericChassis( shell_name=self.shell_name, name="Chassis {}".format(chassis_id), unique_id="{0}.{1}.{2}".format(self._resource_name, "chassis", chassis_id)) else: raise Exception(self.__class__.__name__, 'Cannot find chassis data in entity table') self._chassis.model = self._get_from_table('entPhysicalModelName', entity_data) self._chassis.serial_number = self._get_from_table( 'entPhysicalSerialNum', entity_data) self.resource.add_sub_resource(chassis_id, self._chassis)
def test_add_element(self): uniqe_id = "{}.{}.{}".format(self._resource_name, "chassis", "some_id") relative_path = "0" chassis = GenericChassis(shell_name=self._shell_name, name="Chassis {}".format(0), unique_id="{}.{}.{}".format(self._resource_name, "chassis", uniqe_id)) self.cisco_snmp_autoload._add_element(relative_path, chassis) self.assertTrue(self.cisco_snmp_autoload.elements[relative_path] == chassis) self.assertTrue(self.cisco_snmp_autoload.resource.resources["CH"][relative_path][-1] == chassis) port_relative_path = "0/0" port_uniqe_id = "{}.{}.{}".format(self._resource_name, "port", "some_id") port = GenericPort(shell_name=self._shell_name, name="GigabitEthernet {}".format(port_relative_path), unique_id="{}.{}.{}".format(self._resource_name, "port", port_uniqe_id)) self.cisco_snmp_autoload._add_element(port_relative_path, port) self.assertTrue(self.cisco_snmp_autoload.elements[port_relative_path] == port) self.assertTrue(self.cisco_snmp_autoload.resource.resources["CH"][relative_path][-1].resources["P"][relative_path][-1])
class CgsSNMPAutoload(object): def __init__(self, snmp_handler, shell_name, shell_type, resource_name, logger): """Init command. :param snmp_handler: :param shell_name: :param shell_type: :param resource_name: :param logger: """ self.snmp_handler = snmp_handler self.shell_name = shell_name self.shell_type = shell_type self.resource_name = resource_name self.logger = logger self.elements = {} self.resource = GenericResource( shell_name=shell_name, shell_type=shell_type, name=resource_name, unique_id=resource_name, ) self.chassis = GenericChassis( shell_name=self.shell_name, name="Chassis", unique_id="{}.{}".format(self.resource_name, "chassis"), ) self.resource.add_sub_resource("1", self.chassis) def _load_mibs(self): """Load CGS specific MIBs inside SNMP handler.""" path = os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "mibs")) self.snmp_handler.update_mib_sources(path) def discover(self, supported_os): """General entry point for autoload, read device structure and attributes. Attributes: chassis, modules, submodules, ports, port-channels and power supplies :return: AutoLoadDetails object """ self.logger.info("*" * 70) self.logger.info("Start SNMP discovery process .....") self._load_mibs() self._get_device_details() self._load_snmp_tables() self._build_ports() autoload_details = AutoloadDetailsBuilder( self.resource).autoload_details() self._log_autoload_details(autoload_details) return autoload_details 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:15}, {1:20}, {2}".format( resource.relative_address, resource.name, resource.unique_identifier)) self.logger.debug( "-------------------- </RESOURCES> ----------------------") self.logger.debug( "-------------------- <ATTRIBUTES> ---------------------") for attribute in autoload_details.attributes: self.logger.debug("-- {0:15}, {1:60}, {2}".format( attribute.relative_address, attribute.attribute_name, attribute.attribute_value, )) self.logger.debug( "-------------------- </ATTRIBUTES> ---------------------") def _get_device_model(self): """Get device model from the SNMPv2 mib. :return: device model :rtype: str """ result = "" match_name = re.search( r"::(?P<model>\S+$)", self.snmp_handler.get_property("SNMPv2-MIB", "sysObjectID", "0"), ) if match_name: result = match_name.group("model") return result def _get_device_details(self): """Get root element attributes.""" self.logger.info("Building Root") vendor = "CGS" self.resource.contact_name = self.snmp_handler.get_property( "SNMPv2-MIB", "sysContact", "0") self.resource.system_name = self.snmp_handler.get_property( "SNMPv2-MIB", "sysName", "0") self.resource.location = self.snmp_handler.get_property( "SNMPv2-MIB", "sysLocation", "0") self.resource.model = self.resource.model_name = self._get_device_model( ) self.resource.vendor = vendor def _load_snmp_tables(self): """Load all Cisco required snmp tables. :return: """ self.logger.info("Start loading ifTable MIB") self.if_table = SnmpIfTable(snmp_handler=self.snmp_handler, logger=self.logger) self.logger.info("fTable MIB loaded") def _build_ports(self): """Get resource details and attributes for every port in self.port_list. :return: """ self.logger.info("Loading Ports:") for if_port in self.if_table.if_ports: port = GenericPort( shell_name=self.shell_name, name=if_port.if_name.replace("/", "-"), unique_id="{0}.{1}.{2}".format(self.resource_name, "port", if_port.if_index), ) port.mac_address = if_port.if_mac port.l2_protocol_type = if_port.if_type port.ipv4_address = if_port.ipv4_address port.ipv6_address = if_port.ipv6_address port.port_description = if_port.if_port_description port.bandwidth = if_port.if_speed port.mtu = if_port.if_mtu port.duplex = if_port.duplex port.adjacent = if_port.adjacent port.auto_negotiation = if_port.auto_negotiation self.chassis.add_sub_resource(if_port.if_index, port) self.logger.info("Added port {}".format(if_port.if_index)) self.logger.info("Building Ports completed")
class AireOSAutoload(object): PORT_DESCRIPTION_FILTER = [r'[Vv]irtual', r'[Cc]hannel'] def __init__(self, snmp_handler, shell_name, shell_type, resource_name, logger): self.shell_name = shell_name self.shell_type = shell_type self._content_indexes = None self._if_indexes = None self.logger = logger self.snmp_handler = snmp_handler self._resource_name = resource_name self.resource = GenericResource(shell_name=shell_name, shell_type=shell_type, name=resource_name, unique_id=resource_name) self._chassis = None self._ports = {} self._snmp_cache = {} 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): self.resource.contact_name = self._snmp_request( ('SNMPv2-MIB', 'sysContact', '0')) self.resource.system_name = self._snmp_request( ('SNMPv2-MIB', 'sysName', '0')) self.resource.location = self._snmp_request( ('SNMPv2-MIB', 'sysLocation', '0')) self.resource.os_version = self._snmp_request( ('ENTITY-MIB', 'entPhysicalSoftwareRev', '1')) self.resource.vendor = self._snmp_request( ('SNMPv2-MIB', 'sysObjectID', '0')) self.resource.model = self._snmp_request( ('ENTITY-MIB', 'entPhysicalDescr', '1')) 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(self.__class__.__name__, 'Entity table is empty') if chassis_id and entity_data: self._chassis = GenericChassis( shell_name=self.shell_name, name="Chassis {}".format(chassis_id), unique_id="{0}.{1}.{2}".format(self._resource_name, "chassis", chassis_id)) else: raise Exception(self.__class__.__name__, 'Cannot find chassis data in entity table') self._chassis.model = self._get_from_table('entPhysicalModelName', entity_data) self._chassis.serial_number = self._get_from_table( 'entPhysicalSerialNum', entity_data) self.resource.add_sub_resource(chassis_id, 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 = GenericPort( shell_name=self.shell_name, name=self._convert_port_description(port_description), unique_id='{0}.{1}.{2}'.format(self._resource_name, 'port', port_index)) # port = Port(port_index, self._convert_port_description(port_description)) # port_attributes = dict() port.port_description = self._snmp_request( ('IF-MIB', 'ifAlias', index)) port.l2_protocol_type = str(self._get_from_table('ifType', table)).replace( """'""", '') port.mac_address = self._get_from_table('ifPhysAddress', table) port.mtu = self._get_from_table('ifMtu', table) port.bandwidth = self._get_from_table('ifSpeed', table) port.ipv4_address = self._find_associated_ipv4(index) port.ipv6_address = self._find_associated_ipv6(index) port.duplex = self._get_duplex(index) port.auto_negotiation = self._get_autonegotiation(index) self._ports[port_index] = port self._chassis.add_sub_resource(port_index, 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_channel_index = self._get_from_table('ifIndex', table) port_channel = GenericPortChannel( shell_name=self.shell_name, name=suitable_description, unique_id='{0}.{1}.{2}'.format(self._resource_name, 'port_channel', port_channel_index)) # port = PortChannel(self._get_from_table('ifIndex', table), suitable_description) # pc_attributes = dict() port_channel.port_description = self._snmp_request( ('IF-MIB', 'ifAlias', index)) # pc_attributes[PortChannelAttributes.PROTOCOL_TYPE] = self._get_from_table('ifType', table) port_channel.ipv4_address = self._find_associated_ipv4(index) port_channel.ipv6_address = self._find_associated_ipv6(index) port_channel.associated_ports = self._get_associated_ports( index) self.resource.add_sub_resource(port_channel_index, port_channel) 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): match_port = re.search("[Pp]ort[-:]\s*\d+", description, re.IGNORECASE) if match_port: port = match_port.group() else: port = description.replace('/', '-') return port.replace(':', '-').replace(' ', '') def _is_valid_device_os(self, supported_os): """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(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(supported_os))) self.logger.error(error_message) return False def discover(self, supported_os): if not self._is_valid_device_os(supported_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 = AutoloadDetailsBuilder( self.resource).autoload_details() # autoload_details = AutoLoadDetails(self._root.get_resources(), self._root.get_attributes()) return autoload_details