Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
    def __init__(self, snmp_service, shell_name, shell_type, resource_name, logger):
        """Basic init with injected snmp handler and logger

        :param QualiSnmp snmp_service:
        """

        self.snmp_service = snmp_service
        self.shell_name = shell_name
        self.shell_type = shell_type
        self.resource_name = resource_name
        self.logger = logger
        self.elements = {}
        self.snmp_service.set_snmp_errors(self.SNMP_ERRORS)
        self.resource = GenericResource(shell_name, resource_name, resource_name, shell_type)
    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 __init__(self, snmp_handler, shell_name, shell_type, resource_name,
                 logger):
        """Basic init with injected snmp handler and logger

        :param snmp_handler:
        :param logger:
        :return:
        """

        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.snmp_handler.set_snmp_errors(self.SNMP_ERRORS)
        self.resource = GenericResource(shell_name=shell_name,
                                        shell_type=shell_type,
                                        name=resource_name,
                                        unique_id=resource_name)
Exemplo n.º 5
0
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 SNMPAutoload(object):
    IF_ENTITY = "ifDescr"
    ENTITY_PHYSICAL = "entPhysicalDescr"
    SNMP_ERRORS = [r'No\s+Such\s+Object\s+currently\s+exists']
    DEVICE_NAMES_MAP_FILE = os.path.join(os.path.dirname(__file__), os.pardir,
                                         "mibs", "device_names_map.csv")

    def __init__(self, snmp_handler, shell_name, shell_type, resource_name,
                 logger):
        """Basic init with injected snmp handler and logger

        :param snmp_handler:
        :param logger:
        :return:
        """

        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.snmp_handler.set_snmp_errors(self.SNMP_ERRORS)
        self.resource = GenericResource(shell_name=shell_name,
                                        shell_type=shell_type,
                                        name=resource_name,
                                        unique_id=resource_name)

    def load_cisco_mib(self):
        """
        Loads Cisco 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: chassis, modules, submodules, ports, port-channels and power supplies

        :return: AutoLoadDetails object
        """

        if not self._is_valid_device_os(supported_os):
            raise Exception(self.__class__.__name__, 'Unsupported device OS')

        self.logger.info("*" * 70)
        self.logger.info("Start SNMP discovery process .....")

        self.load_cisco_mib()
        # self.snmp_handler.load_mib(["CISCO-PRODUCTS-MIB", "CISCO-ENTITY-VENDORTYPE-OID-MIB"])
        self._get_device_details()
        self._load_snmp_tables()

        if self.cisco_entity.chassis_list:
            self._get_chassis_attributes(self.cisco_entity.chassis_list)
            self._get_power_ports(self.cisco_entity.power_port_list)
            self._get_module_attributes(self.cisco_entity.module_list)
            self._get_ports_attributes(self.cisco_entity.port_list)
            self._get_port_channels()
        else:
            self.logger.error("Entity table error, no chassis found")

        autoload_details = AutoloadDetailsBuilder(
            self.resource).autoload_details()
        if not self.shell_name:
            root_model_name = [
                x for x in autoload_details.attributes if
                x.relative_address == "" and x.attribute_name == "Model Name"
            ][0]
            if root_model_name:
                autoload_details.attributes.remove(root_model_name)
        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 _is_valid_device_os(self, supported_os):
        """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(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 _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_model_name(self, device_model):
        """Get device model name from the CSV file map

        :param str device_model:  device model
        :return: device model model
        :rtype: str
        """
        return get_device_name(file_name=self.DEVICE_NAMES_MAP_FILE,
                               sys_obj_id=device_model)

    def _get_device_os_version(self):
        """Get device OS Version form snmp SNMPv2 mib

        :return: device model
        :rtype: str
        """

        result = ""
        matched = re.search(
            r"Version (?P<os_version>\S+)[\s,]",
            self.snmp_handler.get_property('SNMPv2-MIB', 'sysDescr', '0'))
        if matched:
            result = matched.groupdict().get("os_version", "")
        return result

    def _get_device_details(self):
        """ Get root element attributes """

        self.logger.info("Building Root")
        vendor = "Cisco"

        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.os_version = self._get_device_os_version()
        self.resource.model = self._get_device_model()
        self.resource.model_name = self._get_device_model_name(
            self.resource.model)
        self.resource.vendor = vendor

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

        :return:
        """

        self.logger.info('Start loading MIB tables:')
        self.if_table = SnmpIfTable(snmp_handler=self.snmp_handler,
                                    logger=self.logger)
        self.logger.info('{0} table loaded'.format(self.IF_ENTITY))
        self.cisco_entity = SNMPEntityTable(self.snmp_handler, self.logger,
                                            self.if_table)
        self.entity_table = self.cisco_entity.get_entity_table()
        self.logger.info('Entity table loaded')

        self.logger.info('MIB Tables loaded successfully')

    def _add_element(self, relative_path, resource, parent_id=""):
        """Add object data to resources and attributes lists

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

        rel_seq = relative_path.split("/")

        if len(rel_seq) == 1:  # Chassis connected directly to root
            self.resource.add_sub_resource(relative_path, resource)
        else:
            if parent_id:
                parent_object = self.elements.get(parent_id, self.resource)
            else:
                parent_object = self.elements.get("/".join(rel_seq[:-1]),
                                                  self.resource)

            rel_path = re.search(r"\d+", rel_seq[-1]).group()
            parent_object.add_sub_resource(rel_path, resource)
            # parent_object.add_sub_resource(rel_seq[-1], resource)

        self.elements.update({relative_path: resource})

    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 _get_module_attributes(self, module_list):
        """ Set attributes for all discovered modules """

        self.logger.info("Building Modules")
        for module in module_list:
            module_id = self.cisco_entity.relative_address.get(module)
            if not module_id:
                continue

            module_index = module_id.split("/")[-1]
            if "/" in module_id and len(module_id.split("/")) < 3:
                module_object = GenericModule(
                    shell_name=self.shell_name,
                    name="Module {}".format(module_index),
                    unique_id="{0}.{1}.{2}".format(self.resource_name,
                                                   "module", module))

            else:
                module_object = GenericSubModule(
                    shell_name=self.shell_name,
                    name="Sub Module {}".format(module_index),
                    unique_id="{0}.{1}.{2}".format(self.resource_name,
                                                   "sub_module", module))

            module_object.model = self.entity_table[module]["entPhysicalDescr"]
            module_object.version = self.snmp_handler.get_property(
                "ENTITY-MIB", "entPhysicalSoftwareRev", module)
            module_object.serial_number = self.snmp_handler.get_property(
                "ENTITY-MIB", "entPhysicalSerialNum", module)

            self._add_element(relative_path=module_id, resource=module_object)
            self.logger.info("Module {} added".format(
                self.entity_table[module]["entPhysicalDescr"]))

        self.logger.info("Building Modules completed")

    def _get_power_ports(self, power_supply_list):
        """Get attributes for power ports provided in self.power_supply_list

        :return:
        """

        self.logger.info("Building PowerPorts")
        for port in power_supply_list:
            port_id = self.entity_table[port]["entPhysicalParentRelPos"]
            parent_index = int(
                self.entity_table[port]["entPhysicalContainedIn"])
            chassis_id = self.cisco_entity.get_relative_address(parent_index)
            relative_address = "{0}/PP{1}".format(chassis_id, port_id)

            power_port = GenericPowerPort(
                shell_name=self.shell_name,
                name="PP{0}".format(power_supply_list.index(port)),
                unique_id="{0}.{1}.{2}".format(self.resource_name,
                                               "power_port", port))

            power_port.model = self.snmp_handler.get_property(
                "ENTITY-MIB", "entPhysicalModelName", port)
            power_port.port_description = self.snmp_handler.get_property(
                "ENTITY-MIB", "entPhysicalDescr", port)
            power_port.version = self.snmp_handler.get_property(
                "ENTITY-MIB", "entPhysicalHardwareRev", port)
            power_port.serial_number = self.snmp_handler.get_property(
                "ENTITY-MIB", "entPhysicalSerialNum", port)

            self._add_element(relative_path=relative_address,
                              resource=power_port,
                              parent_id=chassis_id)

            self.logger.info(
                "Added " +
                self.entity_table[port]["entPhysicalName"].strip(" \t\n\r") +
                " Power Port")
        self.logger.info("Building Power Ports completed")

    def _get_port_channels(self):
        """Get all port channels and set attributes for them

        :return:
        """

        if not self.if_table.if_port_channels:
            return
        self.logger.info("Building Port Channels")
        for if_port_channel in self.if_table.if_port_channels:
            interface_model = if_port_channel.if_name
            match_object = re.search(r"\d+$", interface_model)
            if match_object:
                interface_id = "{0}".format(match_object.group(0))
                associated_ports = ""
                for port in if_port_channel.associated_port_list:
                    if_port_name = self.if_table.get_if_entity_by_index(
                        port).if_name
                    associated_ports = if_port_name.replace('/', '-').replace(
                        ' ', '') + '; '

                port_channel = GenericPortChannel(
                    shell_name=self.shell_name,
                    name=interface_model,
                    unique_id="{0}.{1}.{2}".format(self.resource_name,
                                                   "port_channel",
                                                   interface_id))

                port_channel.associated_ports = associated_ports.strip(
                    ' \t\n\r')
                port_channel.port_description = if_port_channel.if_port_description
                port_channel.ipv4_address = if_port_channel.ipv4_address
                port_channel.ipv6_address = if_port_channel.ipv6_address

                self._add_element(relative_path=interface_id,
                                  resource=port_channel)
                self.logger.info("Added " + interface_model + " Port Channel")

            else:
                self.logger.error(
                    "Adding of {0} failed. Name is invalid".format(
                        interface_model))

        self.logger.info("Building Port Channels completed")

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

        :return:
        """

        self.logger.info("Load Ports:")
        for port in port_list:
            port_if_entity = self.cisco_entity.port_mapping.get(port)
            if not port_if_entity:
                continue
            interface_name = port_if_entity.if_name or self.entity_table[port][
                'entPhysicalName']
            if interface_name == '':
                continue

            port_object = GenericPort(shell_name=self.shell_name,
                                      name=interface_name.replace("/", "-"),
                                      unique_id="{0}.{1}.{2}".format(
                                          self.resource_name, "port", port))
            port_object.mac_address = port_if_entity.if_mac
            port_object.l2_protocol_type = port_if_entity.if_type
            port_object.ipv4_address = port_if_entity.ipv4_address
            port_object.ipv6_address = port_if_entity.ipv6_address
            port_object.port_description = port_if_entity.if_port_description
            port_object.bandwidth = port_if_entity.if_speed
            port_object.mtu = port_if_entity.if_mtu
            port_object.duplex = port_if_entity.duplex
            port_object.adjacent = port_if_entity.adjacent
            port_object.auto_negotiation = port_if_entity.auto_negotiation
            port_object.mac_address = port_if_entity.if_mac

            self._add_element(
                relative_path=self.cisco_entity.relative_address[port],
                resource=port_object)
            self.logger.info("Added " + interface_name + " Port")

        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