Example #1
0
    def get_snmp(self, context, snmp_module_name, miboid):
        """
        :param InitCommandContext context: this is the context passed by cloudshell automatically
        :param str snmp_module_name: MIB name
        :param str miboid: 'management information base object id' test two
        :return:
        """

        session = CloudShellAPISession(
            host=context.connectivity.server_address,
            token_id=context.connectivity.admin_auth_token,
            domain=context.reservation.domain)
        reservation_id = context.reservation.reservation_id
        logger = get_qs_logger()
        address = context.resource.address
        snmp_read_community = session.DecryptPassword(
            context.resource.attributes['LinuxServerShell.SNMP Read Community']
        ).Value
        snmp_v2_parameters = SNMPV2ReadParameters(
            ip=address, snmp_read_community=snmp_read_community)
        snmp_service = QualiSnmp(snmp_v2_parameters, logger)

        for index, info in snmp_service.get_table(snmp_module_name,
                                                  miboid).items():
            session.WriteMessageToReservationOutput(reservation_id,
                                                    "[{0}]".format(index))
            for key, value in info.items():
                session.WriteMessageToReservationOutput(
                    reservation_id, " {0}: {1}".format(key, value))

        return "\nEnd of execution"
 def __get_snmp_handler(self, host, logger):
     path = os.path.abspath(
         os.path.join(os.path.dirname(__file__), ".", "mibs"))
     logger.info(host)
     logger.info(self._snmp_write_community)
     if "3" in self._snmp_version:
         if not self._snmp_v3_user or not self._snmp_v3_password or not self._snmp_v3_private_key:
             raise Exception(
                 self.__class__.__name__,
                 "Cannot create SNMP Version 3, Check configuration")
         snmp_params = SNMPV3Parameters(
             ip=host,
             snmp_user=self._snmp_v3_user,
             snmp_password=self._snmp_v3_password,
             snmp_private_key=self._snmp_v3_private_key)
         logger.info("SNMP V3 Created")
     else:
         if not self._snmp_write_community:
             raise Exception(
                 self.__class__.__name__,
                 "Cannot create SNMP Version 2, Check configuration")
         snmp_params = SNMPV2Parameters(
             ip=host, snmp_community=self._snmp_write_community)
         logger.info("SNMP V2 Created")
     snmp_handler = QualiSnmp(snmp_params, logger)
     snmp_handler.update_mib_sources(path)
     return snmp_handler
    def __init__(self, snmp_params, shell_name, shell_type, resource_name, logger):
        self.logger = logger

        self.snmp = QualiSnmp(snmp_parameters=snmp_params,
                              logger=logger)

        self.resource_name = resource_name
        self.shell_name = shell_name
        self.shell_type = shell_type
        self.resource_model = networking_model

        self.resource = self.resource_model.GenericResource(shell_name=shell_name,
                                                            shell_type=shell_type,
                                                            name=resource_name,
                                                            unique_id=resource_name)

        self._chassis = {}
        self.entity_table_black_list = []
        self.chassis_list = []
        self.module_dict = dict()
        self.module_num = 1
        self.port_exclude_pattern = 'TEST'
        self.port_mapping = {}
        self.port_list = []
        self.power_supply_list = []
    def discover(self, ip, model, vendor, snmp_params):
        """
        :param str ip: The device IP address
        :param str model: The device model in CloudShell
        :param str vendor: The device vendor
        :param SNMPParams snmp_params: The device vendor
        :return: The loaded resources and attributes
        :rtype: AutoLoadDetails
        """

        logger = get_qs_logger()

        self.snmp = QualiSnmp(ip=ip, snmp_version=snmp_params.snmp_version,
                              snmp_user=snmp_params.snmp_v3_user,
                              snmp_password=snmp_params.snmp_v3_password,
                              snmp_community=snmp_params.snmp_read_community,
                              snmp_private_key=snmp_params.snmp_v3_privatekey,
                              logger=logger)


        self.attributes=[]
        self.exclusion_list=[]
        self.chassis_list=[]
        self.port_exclude_pattern='TEST'
        self.port_mapping ={}
        self.port_list =[]
        self.power_supply_list=[]
        self.entity_table_black_list=[]
        self._excluded_models = []
        self.relative_path = {}
        self.module_list = []
        self.resources = []

        self._get_device_details(model, vendor)
        self._load_snmp_tables()

        if(len(self.chassis_list)<1):
            print 'Empty Chasis List Found'
            exit(1)

        for chassis in self.chassis_list:
            if chassis not in self.exclusion_list:
                chassis_id = self._get_resource_id(chassis)
                if chassis_id == '-1':
                    chassis_id = '0'
                self.relative_path[chassis] = chassis_id
        # to add custom MIBSs
        #snmp_handler.update_mib_sources()

        self._filter_lower_bay_containers()
        self.get_module_list()
        self.add_relative_paths()
        self._get_chassis_attributes(self.chassis_list)
        self._get_ports_attributes()
        self._get_module_attributes()

        result = AutoLoadDetails(resources=self.resources, attributes=self.attributes)

        print result #an Object you can play with it
    def retrieving_snmp_table(self, ip):
        logger = get_qs_logger()

        snmp_service = QualiSnmp(ip=ip, snmp_version='2',
                                 snmp_community="Community String",
                                 logger=logger)

        if_table = snmp_service.get_table('IF-MIB', 'ifDescr')
    def retrieving_snmp_properties(self, ip, community_string):

        logger = get_qs_logger()

        snmp_service = QualiSnmp(ip=ip, snmp_version='2',
                              snmp_community=community_string,
                              logger=logger)

        return snmp_service.get_property('SNMPv2-MIB', 'sysName', 0)
    def retrieving_snmp_table(self, ip):
        logger = get_qs_logger()

        snmp_service = QualiSnmp(ip=ip,
                                 snmp_version='2',
                                 snmp_community="Community String",
                                 logger=logger)

        if_table = snmp_service.get_table('IF-MIB', 'ifDescr')
    def retrieving_snmp_properties(self, ip, community_string):

        logger = get_qs_logger()

        snmp_service = QualiSnmp(ip=ip,
                                 snmp_version='2',
                                 snmp_community=community_string,
                                 logger=logger)

        return snmp_service.get_property('SNMPv2-MIB', 'sysName', 0)
Example #9
0
    def get_inventory(self, context):
        """
        Discovers the resource structure and attributes.
        :param AutoLoadCommandContext context: the context the command runs on
        :return Attribute and sub-resource information for the Shell resource you can return an AutoLoadDetails object
        :rtype: AutoLoadDetails
        """
        # See below some example code demonstrating how to return the resource structure and attributes
        # In real life, this code will be preceded by SNMP/other calls to the resource details and will not be static
        # run 'shellfoundry generate' in order to create classes that represent your data model
        self._logger = self._get_logger(context)

        resource = LinuxServerShell.create_from_context(context)
        session = CloudShellAPISession(
            host=context.connectivity.server_address,
            token_id=context.connectivity.admin_auth_token,
            domain='Global')

        logger = get_qs_logger()
        address = context.resource.address
        snmp_read_community = session.DecryptPassword(
            context.resource.attributes['LinuxServerShell.SNMP Read Community']
        ).Value
        snmp_v2_parameters = SNMPV2ReadParameters(
            ip=address, snmp_read_community=snmp_read_community)
        snmp_service = QualiSnmp(snmp_v2_parameters, logger)

        for if_table in snmp_service.get_table('IF-MIB', 'ifTable').values():
            port = ResourcePort(if_table['ifDescr'])
            port.model_name = if_table['ifType']
            port.mac_address = if_table['ifPhysAddress']
            port.port_speed = if_table['ifSpeed']
            for ip_table in snmp_service.get_table('IP-MIB',
                                                   'ipAddrTable').values():
                if ip_table['ipAdEntIfIndex'] == if_table['ifIndex']:
                    port.ipv4_address = ip_table['ipAdEntAddr']
            resource.add_sub_resource(if_table['ifIndex'], port)

        autoload_details = resource.create_autoload_details()
        self._logger.info(
            'autoload attributes: ' +
            ','.join([str(vars(x)) for x in autoload_details.attributes]))
        self._logger.info(
            'autoload resources: ' +
            ','.join([str(vars(x)) for x in autoload_details.resources]))
        return autoload_details
 def __enter__(self):
     """
     Execute enable flow and create snmp service
     :return:
     :rtype: QualiSnmp
     """
     if self._enable_flow:
         self._enable_flow.execute_flow(self._snmp_parameters)
     return QualiSnmp(self._snmp_parameters, self._logger)
 def create_snmp_handler(self):
     kwargs = {}
     for key, value in QUALISNMP_INIT_PARAMS.iteritems():
         if callable(value):
             kwargs[key] = value()
         else:
             kwargs[key] = value
     # snmp_instance = SaveCachedChanges(**kwargs)
     snmp_instance = QualiSnmp(**kwargs)
     return snmp_instance
    def _handler(self, action):
        """
        Sets up an SNMP handler with the current SNMPHandler state

        :rtype: QualiSnmp
        """
        mib_path = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'mibs'))
        snmp_parameters = self._snmp_parameters(action)

        try:
            handler = QualiSnmp(snmp_parameters, self.logger)
        except Exception as e:
            if action.lower() == 'get':
                error = '''Unable to communicate via SNMP read to resource
                Please verify the SNMP read community and that the device is accessible'''
            elif action.lower() == 'set':
                error = '''Unable to communicate via SNMP write to resource
                Please verify the SNMP write community and that the device is accessible'''
            else:
                error = '''Unable to communicate via SNMP to resource
                Please verify the SNMP communities and that the device is accessible'''
            raise Exception(error + '\nDownstream error: ' + str(e))
        handler.update_mib_sources(mib_path)
        handler.load_mib(['Sentry3-MIB'])

        return handler
    def _get_handler(self, action):
        mib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'mibs'))
        snmp_parameters = self._get_snmp_parameters(action)

        handler = QualiSnmp(snmp_parameters, self.logger)
        handler.update_mib_sources(mib_path)
        handler.load_mib(['Sentry3-MIB'])

        return handler
Example #14
0
def do_geist_power(context, f, portstr):
    logger = get_logger(context)
    snmp_parameters = get_snmp_parameters_from_command_context(context,
                                                               write=True)
    snmp = QualiSnmp(snmp_parameters, logger)
    path = os.path.abspath(
        os.path.join(os.path.dirname(__file__), '..', 'mibs'))
    snmp.update_mib_sources(path)
    snmp.load_mib(['GEIST-MIB-V3'])
    logger.info('geist power called with port "%s"' % portstr)
    f(snmp, portstr)
    def _get_snmp_handler(self, device_ip, snmp_comunity_strings):
        """Get SNMP Handler and valid community string for the device

        :param str device_ip:
        :param list[str] snmp_comunity_strings:
        :return: tuple with QualiSnmp instance and valid SNMP community string
        :rtype: (QualiSnmp, str)
        """
        for snmp_community in snmp_comunity_strings:
            self.logger.info(
                "Trying community string '{}' for device with IP {}".format(
                    snmp_community, device_ip))
            snmp_parameters = SNMPV2Parameters(ip=device_ip,
                                               snmp_community=snmp_community)

            try:
                return QualiSnmp(snmp_parameters, self.logger), snmp_community
            except Exception:
                self.logger.warning(
                    "SNMP Community string '{}' is not valid for device with IP {}"
                    .format(snmp_community, device_ip))

        raise ReportableException("SNMP timeout - no resource detected")
def create_snmp_handler():
    kwargs = {}
    for key, value in QUALISNMP_INIT_PARAMS.iteritems():
        if callable(value):
            kwargs[key] = value()
    return QualiSnmp(**kwargs)
from cloudshell.snmp.quali_snmp import ObjectIdentity, ObjectType, QualiSnmp
from cloudshell.core.logger import qs_logger
from cloudshell.snmp.snmp_parameters import SNMPV2ReadParameters


class SNMP_data():
    def __init__(self, oid, type, value):
        self.oid = oid
        self.type = type
        self.value = value


logger = qs_logger.get_qs_logger()
qsnmp_params = SNMPV2ReadParameters(ip='192.168.105.4',
                                    snmp_read_community='publi')

filename = r"C:\Users\yoav.e\AppData\Roaming\Quali\Recordings\192.168.105.4\192.168.105.4.snmp"
with open(filename, "r") as f:
    all_lines = f.readlines()
snmp_all_data = []
qsnmp_instance = QualiSnmp(snmp_parameters=qsnmp_params, logger=logger)
for line in all_lines:
    split_line = line.split(',')
    snmp_all_data.append(SNMP_data(split_line[0], split_line[1],
                                   split_line[2]))
for q in snmp_all_data:
    Otype = ObjectType(ObjectIdentity(q.oid), q.value)
    Otype.resolveWithMib(qsnmp_instance.mib_viewer)
    print Otype
    pass
Example #18
0
def geist_autoload(context):
    logger = get_logger(context)
    snmp_parameters = get_snmp_parameters_from_command_context(context,
                                                               write=False)
    snmp = QualiSnmp(snmp_parameters, logger)
    path = os.path.abspath(
        os.path.join(os.path.dirname(__file__), '..', 'mibs'))
    snmp.update_mib_sources(path)
    snmp.load_mib(['GEIST-MIB-V3'])

    def makeres(name, model, relative_address, unique_identifier):
        r = AutoLoadResource()
        r.name = name
        r.model = model
        r.relative_address = relative_address
        r.unique_identifier = unique_identifier
        return r

    def makeattr(relative_address, attribute_name, attribute_value):
        a = AutoLoadAttribute()
        a.relative_address = relative_address
        a.attribute_name = attribute_name
        a.attribute_value = attribute_value
        return a

    rv = AutoLoadDetails()
    rv.resources = []
    rv.attributes = []

    rv.attributes.append(
        makeattr('', 'Version',
                 snmp.get_property('GEIST-MIB-V3', 'productVersion', 0)))
    rv.attributes.append(
        makeattr('', 'Location',
                 snmp.get_property('SNMPv2-MIB', 'sysLocation', 0)))
    rv.attributes.append(
        makeattr('', 'Vendor',
                 snmp.get_property('GEIST-MIB-V3', 'productHardware', 0)))
    rv.attributes.append(
        makeattr('', 'Model',
                 snmp.get_property('GEIST-MIB-V3', 'productTitle', 0)))

    pduname = snmp.get_property('GEIST-MIB-V3', 'productFriendlyName', 0)

    outlet_table = snmp.get_table('GEIST-MIB-V3', 'ctrlOutletTable')

    for idx, record in outlet_table.iteritems():
        addr = '%d' % idx
        rv.resources.append(
            makeres('Port %d' % idx, 'Generic Power Socket', addr,
                    '%s.%d' % (pduname, idx)))
        rv.attributes.append(
            makeattr(addr, 'Port Description', record['ctrlOutletName']))

    return rv
class GenericSNMPDiscovery:

    def discover(self, ip, model, vendor, snmp_params):
        """
        :param str ip: The device IP address
        :param str model: The device model in CloudShell
        :param str vendor: The device vendor
        :param SNMPParams snmp_params: The device vendor
        :return: The loaded resources and attributes
        :rtype: AutoLoadDetails
        """

        logger = get_qs_logger()

        self.snmp = QualiSnmp(ip=ip, snmp_version=snmp_params.snmp_version,
                              snmp_user=snmp_params.snmp_v3_user,
                              snmp_password=snmp_params.snmp_v3_password,
                              snmp_community=snmp_params.snmp_read_community,
                              snmp_private_key=snmp_params.snmp_v3_privatekey,
                              logger=logger)


        self.attributes=[]
        self.exclusion_list=[]
        self.chassis_list=[]
        self.port_exclude_pattern='TEST'
        self.port_mapping ={}
        self.port_list =[]
        self.power_supply_list=[]
        self.entity_table_black_list=[]
        self._excluded_models = []
        self.relative_path = {}
        self.module_list = []
        self.resources = []

        self._get_device_details(model, vendor)
        self._load_snmp_tables()

        if(len(self.chassis_list)<1):
            print 'Empty Chasis List Found'
            exit(1)

        for chassis in self.chassis_list:
            if chassis not in self.exclusion_list:
                chassis_id = self._get_resource_id(chassis)
                if chassis_id == '-1':
                    chassis_id = '0'
                self.relative_path[chassis] = chassis_id
        # to add custom MIBSs
        #snmp_handler.update_mib_sources()

        self._filter_lower_bay_containers()
        self.get_module_list()
        self.add_relative_paths()
        self._get_chassis_attributes(self.chassis_list)
        self._get_ports_attributes()
        self._get_module_attributes()

        result = AutoLoadDetails(resources=self.resources, attributes=self.attributes)

        print result #an Object you can play with it

    def _get_device_details(self, model, vendor):
        """Get root element attributes
           :param ResourceCommandContext attributes_dictionary:

        """

        result = {'system_name': self.snmp.get_property('SNMPv2-MIB', 'sysName', 0),
                  'vendor': vendor,
                  'model': model,
                  'location': self.snmp.get_property('SNMPv2-MIB', 'sysLocation', 0),
                  'contact': self.snmp.get_property('SNMPv2-MIB', 'sysContact', 0),
                  'version': ''}

        match_version = re.search(r'Version\s+(?P<software_version>\S+)\S*\s+',
                                  self.snmp.get_property('SNMPv2-MIB', 'sysDescr', 0))

        if match_version:
            result['version'] = match_version.groupdict()['software_version'].replace(',', '')

        root = NetworkingStandardRootAttributes(**result)
        self.attributes.extend(root.get_autoload_resource_attributes())

    def _load_snmp_tables(self):
        """ Load all  required snmp tables

        :return:
        """

        self.if_table = self.snmp.get_table('IF-MIB', 'ifDescr')
        self.entity_table = self._get_entity_table()
        if len(self.entity_table.keys()) < 1:
            raise Exception('Cannot load entPhysicalTable. Autoload cannot continue')

        self.lldp_local_table = self.snmp.get_table('LLDP-MIB', 'lldpLocPortDesc')
        self.lldp_remote_table = self.snmp.get_table('LLDP-MIB', 'lldpRemTable')
        self.duplex_table = self.snmp.get_table('EtherLike-MIB', 'dot3StatsIndex')
        self.ip_v4_table = self.snmp.get_table('IP-MIB', 'ipAddrTable')

    def _get_entity_table(self):
        """Read Entity-MIB and filter out device's structure and all it's elements, like ports, modules, chassis, etc.

        :rtype: QualiMibTable
        :return: structured and filtered EntityPhysical table.
        """

        result_dict = QualiMibTable('entPhysicalTable')

        entity_table_critical_port_attr = {'entPhysicalContainedIn': 'str', 'entPhysicalClass': 'str',
                                           'entPhysicalVendorType': 'str'}
        entity_table_optional_port_attr = {'entPhysicalDescr': 'str', 'entPhysicalName': 'str'}

        physical_indexes = self.snmp.get_table('ENTITY-MIB', 'entPhysicalParentRelPos')
        for index in physical_indexes.keys():
            is_excluded = False
            if physical_indexes[index]['entPhysicalParentRelPos'] == '':
                self.exclusion_list.append(index)
                continue
            temp_entity_table = physical_indexes[index].copy()
            temp_entity_table.update(self.snmp.get_properties('ENTITY-MIB', index, entity_table_critical_port_attr)
                                     [index])
            if temp_entity_table['entPhysicalContainedIn'] == '':
                is_excluded = True
                self.exclusion_list.append(index)

            for item in self.entity_table_black_list:
                if item in temp_entity_table['entPhysicalVendorType'].lower():
                    is_excluded = True
                    break

            if is_excluded is True:
                continue

            temp_entity_table.update(self.snmp.get_properties('ENTITY-MIB', index, entity_table_optional_port_attr)
                                     [index])

            if temp_entity_table['entPhysicalClass'] == '':
                vendor_type = self.snmp.get_property('ENTITY-MIB', 'entPhysicalVendorType', index)
                index_entity_class = None
                if vendor_type == '':
                   continue
                if 'cevcontainer' in vendor_type.lower():
                    index_entity_class = 'container'
                elif 'cevchassis' in vendor_type.lower():
                    index_entity_class = 'chassis'
                elif 'cevmodule' in vendor_type.lower():
                    index_entity_class = 'module'
                elif 'cevport' in vendor_type.lower():
                    index_entity_class = 'port'
                elif 'cevpowersupply' in vendor_type.lower():
                    index_entity_class = 'powerSupply'
                if index_entity_class:
                    temp_entity_table['entPhysicalClass'] = index_entity_class
            else:
                temp_entity_table['entPhysicalClass'] = temp_entity_table['entPhysicalClass'].replace("'", "")

            if re.search(r'stack|chassis|module|port|powerSupply|container|backplane',
                         temp_entity_table['entPhysicalClass']):
                result_dict[index] = temp_entity_table

            if temp_entity_table['entPhysicalClass'] == 'chassis':
                self.chassis_list.append(index)
            elif temp_entity_table['entPhysicalClass'] == 'port':
                if not re.search(self.port_exclude_pattern, temp_entity_table['entPhysicalName'], re.IGNORECASE) \
                        and not re.search(self.port_exclude_pattern, temp_entity_table['entPhysicalDescr'],
                                          re.IGNORECASE):
                    port_id = self._get_mapping(index, temp_entity_table['entPhysicalDescr'])
                    if port_id and port_id in self.if_table and port_id not in self.port_mapping.values():
                        self.port_mapping[index] = port_id
                        self.port_list.append(index)
            elif temp_entity_table['entPhysicalClass'] == 'powerSupply':
                self.power_supply_list.append(index)

        self._filter_entity_table(result_dict)
        return result_dict

    def _get_mapping(self, port_index, port_descr):
        """Get mapping from entPhysicalTable to ifTable.
        Build mapping based on ent_alias_mapping_table if exists else build manually based on
        entPhysicalDescr <-> ifDescr mapping.

        :return: simple mapping from entPhysicalTable index to ifTable index:
        |        {entPhysicalTable index: ifTable index, ...}
        """

        port_id = None
        try:
            ent_alias_mapping_identifier = self.snmp.get(('ENTITY-MIB', 'entAliasMappingIdentifier', port_index, 0))
            port_id = int(ent_alias_mapping_identifier['entAliasMappingIdentifier'].split('.')[-1])
        except Exception as e:

            if_table_re = "/".join(re.findall('\d+', port_descr))
            for interface in self.if_table.values():
                if re.search(if_table_re, interface['ifDescr']):
                    port_id = int(interface['suffix'])
                    break
        return port_id

    def _filter_entity_table(self, raw_entity_table):
        """Filters out all elements if their parents, doesn't exist, or listed in self.exclusion_list

        :param raw_entity_table: entity table with unfiltered elements
        """

        elements = raw_entity_table.filter_by_column('ContainedIn').sort_by_column('ParentRelPos').keys()
        for element in reversed(elements):
            parent_id = int(self.entity_table[element]['entPhysicalContainedIn'])

            if parent_id not in raw_entity_table or parent_id in self.exclusion_list:
                self.exclusion_list.append(element)

    def _get_resource_id(self, item_id):
        parent_id = int(self.entity_table[item_id]['entPhysicalContainedIn'])
        if parent_id > 0 and parent_id in self.entity_table:
            if re.search(r'container|backplane', self.entity_table[parent_id]['entPhysicalClass']):
                result = self.entity_table[parent_id]['entPhysicalParentRelPos']
            elif parent_id in self._excluded_models:
                result = self._get_resource_id(parent_id)
            else:
                result = self.entity_table[item_id]['entPhysicalParentRelPos']
        else:
            result = self.entity_table[item_id]['entPhysicalParentRelPos']
        return result

    def _filter_lower_bay_containers(self):

        upper_container = None
        lower_container = None
        containers = self.entity_table.filter_by_column('Class', "container").sort_by_column('ParentRelPos').keys()
        for container in containers:
            vendor_type = self.snmp.get_property('ENTITY-MIB', 'entPhysicalVendorType', container)
            if 'uppermodulebay' in vendor_type.lower():
                upper_container = container
            if 'lowermodulebay' in vendor_type.lower():
                lower_container = container
        if lower_container and upper_container:
            child_upper_items_len = len(self.entity_table.filter_by_column('ContainedIn', str(upper_container)
                                                                           ).sort_by_column('ParentRelPos').keys())
            child_lower_items = self.entity_table.filter_by_column('ContainedIn', str(lower_container)
                                                                   ).sort_by_column('ParentRelPos').keys()
            for child in child_lower_items:
                self.entity_table[child]['entPhysicalContainedIn'] = upper_container
                self.entity_table[child]['entPhysicalParentRelPos'] = str(child_upper_items_len + int(
                    self.entity_table[child]['entPhysicalParentRelPos']))

    def get_module_list(self):
        """Set list of all modules from entity mib table for provided list of ports

        :return:
        """

        for port in self.port_list:
            modules = []
            modules.extend(self._get_module_parents(port))
            for module in modules:
                if module in self.module_list:
                    continue
                vendor_type = self.snmp.get_property('ENTITY-MIB', 'entPhysicalVendorType', module)
                if not re.search(self.module_exclude_pattern, vendor_type.lower()):
                    if module not in self.exclusion_list and module not in self.module_list:
                        self.module_list.append(module)
                else:
                    self._excluded_models.append(module)

    def add_relative_paths(self):
        """Build dictionary of relative paths for each module and port

        :return:
        """

        port_list = list(self.port_list)
        module_list = list(self.module_list)
        for module in module_list:
            if module not in self.exclusion_list:
                self.relative_path[module] = self.get_relative_path(module) + '/' + self._get_resource_id(module)
            else:
                self.module_list.remove(module)
        for port in port_list:
            if port not in self.exclusion_list:
                self.relative_path[port] = self._get_port_relative_path(
                    self.get_relative_path(port) + '/' + self._get_resource_id(port))
            else:
                self.port_list.remove(port)

    def get_relative_path(self, item_id):
        """Build relative path for received item

        :param item_id:
        :return:
        """

        result = ''
        if item_id not in self.chassis_list:
            parent_id = int(self.entity_table[item_id]['entPhysicalContainedIn'])
            if parent_id not in self.relative_path.keys():
                if parent_id in self.module_list:
                    result = self._get_resource_id(parent_id)
                if result != '':
                    result = self.get_relative_path(parent_id) + '/' + result
                else:
                    result = self.get_relative_path(parent_id)
            else:
                result = self.relative_path[parent_id]
        else:
            result = self.relative_path[item_id]

        return result

    def _get_chassis_attributes(self, chassis_list):
        """Get Chassis element attributes

        :param chassis_list: list of chassis to load attributes for
        :return:
        """


        for chassis in chassis_list:
            chassis_id = self.relative_path[chassis]
            chassis_details_map = {
                'chassis_model': self.snmp.get_property('ENTITY-MIB', 'entPhysicalModelName', chassis),
                'serial_number': self.snmp.get_property('ENTITY-MIB', 'entPhysicalSerialNum', chassis)
            }
            if chassis_details_map['chassis_model'] == '':
                chassis_details_map['chassis_model'] = self.entity_table[chassis]['entPhysicalDescr']
            relative_path = '{0}'.format(chassis_id)
            chassis_object = Chassis(relative_path=relative_path, **chassis_details_map)
            self._add_resource(chassis_object)

    def _get_ports_attributes(self):
        """Get resource details and attributes for every port in self.port_list

        :return:
        """


        for port in self.port_list:
            if_table_port_attr = {'ifType': 'str', 'ifPhysAddress': 'str', 'ifMtu': 'int', 'ifSpeed': 'int'}
            if_table = self.if_table[self.port_mapping[port]].copy()
            if_table.update(self.snmp.get_properties('IF-MIB', self.port_mapping[port], if_table_port_attr))
            interface_name = self.if_table[self.port_mapping[port]]['ifDescr'].replace("'", '')
            if interface_name == '':
                interface_name = self.entity_table[port]['entPhysicalName']
            if interface_name == '':
                continue
            interface_type = if_table[self.port_mapping[port]]['ifType'].replace('/', '').replace("'", '')
            attribute_map = {'l2_protocol_type': interface_type,
                             'mac': if_table[self.port_mapping[port]]['ifPhysAddress'],
                             'mtu': if_table[self.port_mapping[port]]['ifMtu'],
                             'bandwidth': if_table[self.port_mapping[port]]['ifSpeed'],
                             'description': self.snmp.get_property('IF-MIB', 'ifAlias', self.port_mapping[port]),
                             'adjacent': self._get_adjacent(self.port_mapping[port])}
            attribute_map.update(self._get_interface_details(self.port_mapping[port]))
            attribute_map.update(self._get_ip_interface_details(self.port_mapping[port]))
            port_object = Port(name=interface_name, relative_path=self.relative_path[port], **attribute_map)
            self._add_resource(port_object)

    def _get_module_attributes(self):
        """Set attributes for all discovered modules

        :return:
        """


        for module in self.module_list:
            module_id = self.relative_path[module]
            module_index = self._get_resource_id(module)
            module_details_map = {
                'module_model': self.entity_table[module]['entPhysicalDescr'],
                'version': self.snmp.get_property('ENTITY-MIB', 'entPhysicalSoftwareRev', module),
                'serial_number': self.snmp.get_property('ENTITY-MIB', 'entPhysicalSerialNum', module)
            }

            if '/' in module_id and len(module_id.split('/')) < 3:
                module_name = 'Module {0}'.format(module_index)
                model = 'Generic Module'
            else:
                module_name = 'Sub Module {0}'.format(module_index)
                model = 'Generic Sub Module'
            module_object = Module(name=module_name, model=model, relative_path=module_id, **module_details_map)
            self._add_resource(module_object)

    def _get_module_parents(self, module_id):
        result = []
        parent_id = int(self.entity_table[module_id]['entPhysicalContainedIn'])
        if parent_id > 0 and parent_id in self.entity_table:
            if re.search(r'module', self.entity_table[parent_id]['entPhysicalClass']):
                result.append(parent_id)
                result.extend(self._get_module_parents(parent_id))
            elif re.search(r'chassis', self.entity_table[parent_id]['entPhysicalClass']):
                return result
            else:
                result.extend(self._get_module_parents(parent_id))
        return result

    def _get_port_relative_path(self, relative_id):
        if relative_id in self.relative_path.values():
            if '/' in relative_id:
                ids = relative_id.split('/')
                ids[-1] = str(int(ids[-1]) + 1000)
                result = '/'.join(ids)
            else:
                result = str(int(relative_id.split()[-1]) + 1000)
            if relative_id in self.relative_path.values():
                result = self._get_port_relative_path(result)
        else:
            result = relative_id
        return result

    def _add_resource(self, resource):
        """Add object data to resources and attributes lists

        :param resource: object which contains all required data for certain resource
        """

        self.resources.append(resource.get_autoload_resource_details())
        self.attributes.extend(resource.get_autoload_resource_attributes())

    def _get_adjacent(self, interface_id):
        """Get connected device interface and device name to the specified port id, using  lldp protocols

        :param interface_id: port id
        :return: device's name and port connected to port id
        :rtype string
        """
        result = ''
        if  self.lldp_remote_table:
            for key, value in self.lldp_local_table.iteritems():
                interface_name = self.if_table[interface_id]['ifDescr']
                if interface_name == '':
                    break
                if 'lldpLocPortDesc' in value and interface_name in value['lldpLocPortDesc']:
                    if 'lldpRemSysName' in self.lldp_remote_table and 'lldpRemPortDesc' in self.lldp_remote_table:
                        result = '{0} through {1}'.format(self.lldp_remote_table[key]['lldpRemSysName'],
                                                          self.lldp_remote_table[key]['lldpRemPortDesc'])
        return result

    def _get_interface_details(self, port_index):
        """Get interface attributes

        :param port_index: port index in ifTable
        :return interface_details: detected info for provided interface dict{'Auto Negotiation': '', 'Duplex': ''}
        """

        interface_details = {'duplex': 'Full', 'auto_negotiation': 'False'}
        try:
            auto_negotiation = self.snmp.get(('MAU-MIB', 'ifMauAutoNegAdminStatus', port_index, 1)).values()[0]
            if 'enabled' in auto_negotiation.lower():
                interface_details['auto_negotiation'] = 'True'
        except Exception as e:
            print('Failed to load auto negotiation property for interface {0}'.format(e.message))
        for key, value in self.duplex_table.iteritems():
            if 'dot3StatsIndex' in value.keys() and value['dot3StatsIndex'] == str(port_index):
                interface_duplex = self.snmp.get_property('EtherLike-MIB', 'dot3StatsDuplexStatus', key)
                if 'halfDuplex' in interface_duplex:
                    interface_details['duplex'] = 'Half'
        return interface_details

    def _get_ip_interface_details(self, port_index):
        """Get IP address details for provided port

        :param port_index: port index in ifTable
        :return interface_details: detected info for provided interface dict{'IPv4 Address': '', 'IPv6 Address': ''}
        """

        interface_details = {'ipv4_address': '', 'ipv6_address': ''}
        if self.ip_v4_table and len(self.ip_v4_table) > 1:
            for key, value in self.ip_v4_table.iteritems():
                if 'ipAdEntIfIndex' in value and int(value['ipAdEntIfIndex']) == port_index:
                    interface_details['ipv4_address'] = key
                break

        return interface_details
class SonicGenericSNMPDiscovery:
    def __init__(self, snmp_params, shell_name, shell_type, resource_name,
                 logger):
        self.logger = logger

        self.snmp = QualiSnmp(snmp_parameters=snmp_params, logger=logger)

        self.resource_name = resource_name
        self.shell_name = shell_name
        self.shell_type = shell_type
        self.resource_model = networking_model

        self.resource = self.resource_model.GenericResource(
            shell_name=shell_name,
            shell_type=shell_type,
            name=resource_name,
            unique_id=resource_name)

        self._chassis = {}
        self.entity_table_black_list = []
        self.chassis_list = []
        self.port_exclude_pattern = 'TEST'
        self.port_mapping = {}
        self.port_list = []
        self.power_supply_list = []

    def discover(self):
        """
        :param str ip: The device IP address
        :param str model: The device model in CloudShell
        :param str vendor: The device vendor
        :param SNMPV2ReadParameters snmp_params: The device vendor
        :return: The loaded resources and attributes
        :rtype: AutoLoadDetails
        """

        self._get_device_details()
        self._load_snmp_tables()

        self._build_chassis()
        self._build_ports()

        autoload_details = AutoloadDetailsBuilder(
            self.resource).autoload_details()
        self._log_autoload_details(autoload_details)
        return autoload_details

    def _get_device_details(self):
        """Get root element attributes
        """
        self.logger.info("Building Root")

        sysDescr = self.snmp.get_property('SNMPv2-MIB', 'sysDescr', '0')

        match_version = re.search(
            r'Version:\s+(?P<software_version>\S+)\S*\s+', sysDescr)
        if match_version:
            match_version = match_version.groupdict(
            )['software_version'].replace(',', '')

        match_vendor_model = re.search(r'HwSku:\s+(?P<vendor_model>\S+)\S*\s+',
                                       sysDescr)
        if match_vendor_model:
            match_vendor_model = match_vendor_model.groupdict(
            )['vendor_model'].replace(',', '')
            vendor, model = match_vendor_model.split('-', 1)
        else:
            vendor = model = None

        self.resource.contact_name = self.snmp.get_property(
            'SNMPv2-MIB', 'sysContact', '0')
        self.resource.system_name = self.snmp.get_property(
            'SNMPv2-MIB', 'sysName', '0')
        self.resource.location = self.snmp.get_property(
            'SNMPv2-MIB', 'sysLocation', '0')
        self.resource.os_version = match_version
        self.resource.vendor = vendor
        self.resource.model = model

    def _log_autoload_details(self, autoload_details):
        """
        Logging autoload details
        :param autoload_details:
        :return:
        """
        self.logger.info(
            '-------------------- <RESOURCES> ----------------------')
        for resource in autoload_details.resources:
            self.logger.info('{0:15}, {1:20}, {2}'.format(
                resource.relative_address, resource.name,
                resource.unique_identifier))
        self.logger.info(
            '-------------------- </RESOURCES> ----------------------')

        self.logger.info(
            '-------------------- <ATTRIBUTES> ---------------------')
        for attribute in autoload_details.attributes:
            self.logger.info('-- {0:15}, {1:60}, {2}'.format(
                attribute.relative_address, attribute.attribute_name,
                attribute.attribute_value))
        self.logger.info(
            '-------------------- </ATTRIBUTES> ---------------------')

    def _load_snmp_tables(self):
        """ Load all  required snmp tables
        :return:
        """

        self.if_table = self.snmp.get_table('IF-MIB', 'ifDescr')
        self.entity_table = self._get_entity_table()
        #if len(self.entity_table.keys()) < 1:
        #raise Exception('Cannot load entPhysicalTable. Autoload cannot continue')

        self.lldp_local_table = self.snmp.get_table('LLDP-MIB',
                                                    'lldpLocPortDesc')
        self.lldp_remote_table = self.snmp.get_table('LLDP-MIB',
                                                     'lldpRemTable')
        self.duplex_table = self.snmp.get_table('EtherLike-MIB',
                                                'dot3StatsIndex')
        self.ip_v4_table = self.snmp.get_table('IP-MIB', 'ipAddrTable')

    def _get_entity_table(self):
        """Read Entity-MIB and filter out device's structure and all it's elements, like ports, modules, chassis, etc.
        :rtype: QualiMibTable
        :return: structured and filtered EntityPhysical table.
        """

        result_dict = QualiMibTable('entPhysicalTable')

        entity_table_critical_port_attr = {
            'entPhysicalContainedIn': 'str',
            'entPhysicalVendorType': 'str'
        }
        entity_table_optional_port_attr = {
            'entPhysicalDescr': 'str',
            'entPhysicalSerialNum': 'str'
        }

        physical_indexes = self.snmp.get_table('ENTITY-MIB',
                                               'entPhysicalClass')
        for index in physical_indexes.keys():
            is_excluded = False
            #if physical_indexes[index]['entPhysicalParentRelPos'] == '':
            #    self.exclusion_list.append(index)
            #    continue
            temp_entity_table = physical_indexes[index].copy()
            #temp_entity_table.update(self.snmp.get_properties('ENTITY-MIB', index, entity_table_critical_port_attr)
            #                         [index])
            #if temp_entity_table['entPhysicalContainedIn'] == '':
            #    is_excluded = True
            #    self.exclusion_list.append(index)

            for item in self.entity_table_black_list:
                if item in temp_entity_table['entPhysicalVendorType'].lower():
                    is_excluded = True
                    break

            if is_excluded is True:
                continue

            temp_entity_table.update(
                self.snmp.get_properties(
                    'ENTITY-MIB', index,
                    entity_table_optional_port_attr)[index])
            '''if temp_entity_table['entPhysicalClass'] == '':
                vendor_type = self.snmp.get_property('ENTITY-MIB', 'entPhysicalVendorType', index)
                index_entity_class = None
                if vendor_type == '':
                   continue
                if 'cevcontainer' in vendor_type.lower():
                    index_entity_class = 'container'
                elif 'cevchassis' in vendor_type.lower():
                    index_entity_class = 'chassis'
                elif 'cevmodule' in vendor_type.lower():
                    index_entity_class = 'module'
                elif 'cevport' in vendor_type.lower():
                    index_entity_class = 'port'
                elif 'cevpowersupply' in vendor_type.lower():
                    index_entity_class = 'powerSupply'
                if index_entity_class:
                    temp_entity_table['entPhysicalClass'] = index_entity_class
            else:'''
            temp_entity_table['entPhysicalClass'] = temp_entity_table[
                'entPhysicalClass'].replace("'", "")

            if re.search(
                    r'stack|chassis|module|port|powerSupply|container|backplane',
                    temp_entity_table['entPhysicalClass']):
                result_dict[index] = temp_entity_table

            if temp_entity_table['entPhysicalClass'] == 'chassis':
                self.chassis_list.append(index)
                break
            #elif temp_entity_table['entPhysicalClass'] == 'port':
            #    if not re.search(self.port_exclude_pattern, temp_entity_table['entPhysicalName'], re.IGNORECASE) \
            #            and not re.search(self.port_exclude_pattern, temp_entity_table['entPhysicalDescr'],
            #                              re.IGNORECASE):
            #        port_id = self._get_mapping(index, temp_entity_table['entPhysicalDescr'])
            #        if port_id and port_id in self.if_table and port_id not in self.port_mapping.values():
            #            self.port_mapping[index] = port_id
            #            self.port_list.append(index)
            #elif temp_entity_table['entPhysicalClass'] == 'powerSupply':
            #    self.power_supply_list.append(index)

        #self._filter_entity_table(result_dict)
        return result_dict

    def _get_mapping(self, port_index, port_descr):
        """Get mapping from entPhysicalTable to ifTable.
        Build mapping based on ent_alias_mapping_table if exists else build manually based on
        entPhysicalDescr <-> ifDescr mapping.
        :return: simple mapping from entPhysicalTable index to ifTable index:
        |        {entPhysicalTable index: ifTable index, ...}
        """

        port_id = None
        try:
            ent_alias_mapping_identifier = self.snmp.get(
                ('ENTITY-MIB', 'entAliasMappingIdentifier', port_index, 0))
            port_id = int(
                ent_alias_mapping_identifier['entAliasMappingIdentifier'].
                split('.')[-1])
        except Exception as e:

            if_table_re = "/".join(re.findall('\d+', port_descr))
            for interface in self.if_table.values():
                if re.search(if_table_re, interface['ifDescr']):
                    port_id = int(interface['suffix'])
                    break
        return port_id

    def _build_chassis(self):
        """
        Build Chassis resources and attributes
        :return:
        """
        self.logger.debug('Building Chassis')
        for index in self.chassis_list:
            chassis = self.resource_model.GenericChassis(
                shell_name=self.shell_name,
                name="Chassis {}".format(index),
                unique_id="{0}.{1}.{2}".format(self.resource_name, "chassis",
                                               index))
            chassis.serial_number = self.snmp.get_property(
                'ENTITY-MIB', 'entPhysicalSerialNum', index)

            self.resource.add_sub_resource(index, chassis)

            self._chassis[index] = chassis

        if self.chassis_list == []:
            chassis = self.resource_model.GenericChassis(
                shell_name=self.shell_name,
                name="Chassis {}".format(1),
                unique_id="{0}.{1}.{2}".format(self.resource_name, "chassis",
                                               '1'))
            self.resource.add_sub_resource('1', chassis)
            self.chassis_list.append('1')
            self._chassis['1'] = chassis

    def _build_ports(self):
        if self.chassis_list == {}:
            chassis = self._chassis['1']
        else:
            chassis = self._chassis[self.chassis_list[0]]

        interface_indexes = self.snmp.get_table('IF-MIB', 'ifDescr')

        for index in interface_indexes.keys():
            interface_name = self.snmp.get_property('IF-MIB',
                                                    'ifDescr', index).replace(
                                                        '/',
                                                        '-').replace(':', '-')

            if interface_name != '' and 'Channel' not in interface_indexes.get(
                    index).get('ifDescr'):
                interface = self.resource_model.GenericPort(
                    shell_name=self.shell_name,
                    name=interface_name,
                    unique_id="{0}.{1}.{2}".format(self.resource_name, "port",
                                                   index))
                interface.l2_protocol_type = self.snmp.get_property(
                    'IF-MIB', 'ifType', index).strip('\'')
                interface.mac_address = self.snmp.get_property(
                    'IF-MIB', 'ifPhysAddress', index)
                interface.mtu = self.snmp.get_property('IF-MIB', 'ifMtu',
                                                       index)
                interface.bandwidth = self.snmp.get_property(
                    'IF-MIB', 'ifHighSpeed', index)

                duplex = None
                snmp_result = self.snmp.get_property('EtherLike-MIB',
                                                     'dot3StatsDuplexStatus',
                                                     index)
                if snmp_result:
                    port_duplex = snmp_result.strip('\'')
                    if re.search(r'[Ff]ull', port_duplex):
                        duplex = 'Full'
                    else:
                        duplex = 'Half'
                interface.duplex = duplex

                interface.adjacent = None
                interface.auto_negotiation = False
                interface.port_description = interface_indexes.get(index).get(
                    'ifDescr')

                chassis.add_sub_resource(index, interface)
            '''if 'Channel' in interface_indexes.get(index).get('ifDescr'):