コード例 #1
0
ファイル: snmp.py プロジェクト: QualiSystems/cloudshell-cgs
    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)
コード例 #2
0
    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")
コード例 #3
0
    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)
コード例 #4
0
 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])
コード例 #5
0
ファイル: snmp.py プロジェクト: QualiSystems/cloudshell-cgs
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")
コード例 #6
0
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