Example #1
0
class Modules(Plugin):
    """Plugin to collect module and chassis data from devices"""
    def __init__(self, *args, **kwargs):
        super(Modules, self).__init__(*args, **kwargs)
        self.alias_mapping = {}
        self.entitymib = EntityMib(self.agent)
        self.stampcheck = TimestampChecker(self.agent, self.containers,
                                           INFO_VAR_NAME)

    @defer.inlineCallbacks
    def handle(self):
        self._logger.debug("Collecting ENTITY-MIB module data")
        need_to_collect = yield self._need_to_collect()
        if need_to_collect:
            physical_table = (
                yield self.entitymib.get_useful_physical_table_columns())

            alias_mapping = yield self.entitymib.retrieve_column(
                'entAliasMappingIdentifier')
            self.alias_mapping = self._process_alias_mapping(alias_mapping)
            self._process_entities(physical_table)
        self.stampcheck.save()

    @defer.inlineCallbacks
    def _need_to_collect(self):
        yield self.stampcheck.load()
        yield self.stampcheck.collect([self.entitymib.get_last_change_time()])

        result = yield self.stampcheck.is_changed()
        defer.returnValue(result)

    def _device_from_entity(self, ent, chassis=False):
        serial_column = 'entPhysicalSerialNum'
        if serial_column in ent and ent[serial_column] and \
            ent[serial_column].strip():
            serial_number = ent[serial_column].strip()
            device_key = serial_number
        else:
            serial_number = None
            device_key = 'unknown-%s' % ent[0]

        # check whether some plugin already registered a chassis device
        # without knowing its serial. If so, give the device two keys in the
        # container repository
        if chassis and self.containers.get(None, shadows.Device):
            device = self.containers.get(None, shadows.Device)
            self.containers[shadows.Device][device_key] = device
        else:
            device = self.containers.factory(device_key, shadows.Device)
        if serial_number:
            device.serial = serial_number
        if ent['entPhysicalHardwareRev']:
            device.hardware_version = ent['entPhysicalHardwareRev'].strip()
        if ent['entPhysicalSoftwareRev']:
            device.software_version = ent['entPhysicalSoftwareRev'].strip()
        if ent['entPhysicalFirmwareRev']:
            device.firmware_version = ent['entPhysicalFirmwareRev'].strip()
        device.active = True
        return device

    def _module_from_entity(self, ent):
        module = self.containers.factory(ent['entPhysicalSerialNum'],
                                         shadows.Module)
        netbox = self.containers.factory(None, shadows.Netbox)

        module.netbox = netbox
        module.model = ent['entPhysicalModelName'].strip()
        module.description = ent['entPhysicalDescr'].strip()
        module.name = ent['entPhysicalName'].strip()
        if module.name.strip().isdigit():
            module.module_number = int(module.name.strip())
        module.parent = None
        return module

    def _process_modules(self, entities):
        # map entity indexes to module containers
        module_containers = {}
        modules = entities.get_modules()
        for ent in modules:
            entity_index = ent[0]
            device = self._device_from_entity(ent)
            module = self._module_from_entity(ent)
            module.device = device

            module_containers[entity_index] = module
            self._logger.debug("module (entPhysIndex=%s): %r", entity_index,
                               module)

        return module_containers

    def _process_chassis(self, entities):
        chassis = entities.get_chassis()
        if not chassis:
            self._logger.debug('No chassis found')
            return
        elif len(chassis) > 1:
            self._logger.debug('Found multiple chassis')

        # We don't really know how to handle a multiple chassis
        # situation.  Best effort is to use the first one in the list.
        # This should be revised by someone who has stacked chassis
        # devices to test on.
        the_chassis = chassis[0]
        device = self._device_from_entity(the_chassis, chassis=True)
        netbox = self.containers.factory(None, shadows.Netbox)
        netbox.device = device

    def _process_ports(self, entities, module_containers):
        ports = entities.get_ports()
        netbox = self.containers.factory(None, shadows.Netbox)

        # Map interfaces to modules, if possible
        module_ifindex_map = {}  #just for logging debug info
        for port in ports:
            entity_index = port[0]
            if entity_index in self.alias_mapping:
                module_entity = entities.get_nearest_module_parent(port)

                if module_entity and module_entity[0] in module_containers:
                    module = module_containers[module_entity[0]]
                    indices = self.alias_mapping[entity_index]
                    for ifindex in indices:
                        interface = self.containers.factory(
                            ifindex, shadows.Interface)
                        interface.netbox = netbox
                        interface.ifindex = ifindex
                        interface.module = module

                        if module.name in module_ifindex_map:
                            module_ifindex_map[module.name].append(ifindex)
                        else:
                            module_ifindex_map[module.name] = [ifindex]

        if module_ifindex_map:
            self._logger.debug("module/ifindex mapping: %r",
                               module_ifindex_map)

    def _process_entities(self, result):
        """Process the list of collected entities."""
        # be able to look up all entities using entPhysicalIndex
        entities = EntityTable(result)

        module_containers = self._process_modules(entities)
        self._process_chassis(entities)
        self._process_ports(entities, module_containers)

    def _process_alias_mapping(self, alias_mapping):
        mapping = {}
        for (phys_index, _logical), rowpointer in alias_mapping.items():
            # Last element is ifindex. Preceding elements is an OID.
            ifindex = OID(rowpointer)[-1]

            if phys_index not in mapping:
                mapping[phys_index] = []
            mapping[phys_index].append(ifindex)

        self._logger.debug("alias mapping: %r", mapping)
        return mapping
Example #2
0
File: psu.py Project: yytsui/nav
class PowerSupplyUnit(Plugin):
    """Plugin that collect PSUs and FANs,- and their status from netboxes."""
    vendor_id = None

    def __init__(self, *args, **kwargs):
        """ Constructor..."""
        super(PowerSupplyUnit, self).__init__(*args, **kwargs)
        self.entity_mib = EntityMib(self.agent)
        self.entity_fru_control = None
        self.vendor_id = None
        if self.netbox.type:
            self.vendor_id = self.netbox.type.get_enterprise_id()
        if self.vendor_id == VENDOR_ID_CISCOSYSTEMS:
            self.entity_fru_control = CiscoEntityFruControlMib(self.agent)
        elif self.vendor_id == VENDOR_ID_HEWLETT_PACKARD:
            self.entity_fru_control = HpEntityFruControlMib(self.agent)

    @staticmethod
    def _enumerate_entities(entities):
        """Enumerate and annotate entities according to their internal order,
        for looking up the entities in private HP MIBs.

        This makes the very naive assumption that fans and power supplies are
        listed in the same order in entPhysicalTable as in the private HP
        mibs for fans and power supplies.
        """
        entities.sort(key=itemgetter(0))
        for index, ent in enumerate(entities, start=1):
            ent['_internal_index'] = index
        return entities

    def _get_psus_and_fans(self, to_filter):
        """Extracts only fans and power supplies from a list of entities"""
        power_supplies = []
        fans = []
        for unit in to_filter.values():
            if self.is_psu(unit):
                power_supplies.append(unit)
            if self.is_fan(unit):
                fans.append(unit)
        if self.vendor_id and self.vendor_id == VENDOR_ID_HEWLETT_PACKARD:
            # Index-numbers from HP-netboxes need to be re-numbered to match
            # index-numbers in POWERSUPPLY-MIB and FAN-MIB.
            # Index-numbers should in practice start at 1 for both PSUs and
            # FANs to match the corresponding statuses.
            self._enumerate_entities(power_supplies)
            self._enumerate_entities(fans)

        # Create list of all psus and fans.  Add all psus first.
        all_psus_and_fans = power_supplies
        # Then add all fans.
        all_psus_and_fans.extend(fans)
        return all_psus_and_fans

    @staticmethod
    def is_fan(pwr):
        """Determine if this unit is a fan"""
        return pwr.get('entPhysicalClass', None) == 'fan'

    @staticmethod
    def is_psu(pwr):
        """Determine if this unit is a powersupply"""
        return pwr.get('entPhysicalClass', None) == 'powerSupply'

    @defer.inlineCallbacks
    def handle(self):
        """Collect PSUs and FANs,- their corresponding statuses and store
        in database"""
        self._logger.debug("Collecting PSUs and FANs")

        entity_table = yield self.entity_mib.get_useful_physical_table_columns()
        entity_table = EntityTable(entity_table)
        psus_and_fans = self._get_psus_and_fans(entity_table)
        if psus_and_fans:
            for psu_or_fan in psus_and_fans:
                yield self._handle_unit(psu_or_fan)

    @defer.inlineCallbacks
    def _handle_unit(self, psu_or_fan):
        self._logger.debug('PSU:FAN: %s', psu_or_fan)
        internal_index = psu_or_fan.get('_internal_index', psu_or_fan.get(0))
        is_up = 'u'
        sensor_oid = None
        control = self.entity_fru_control
        if not control:
            defer.returnValue(None)

        if self.is_fan(psu_or_fan):
            # locate sensor and get status
            ret = yield control.is_fan_up(internal_index)
            if ret:
                is_up = ret
                sensor_oid = control.get_oid_for_fan_status(internal_index)
            self._logger.debug('FAN: %s: %s', ret, sensor_oid)
        elif self.is_psu(psu_or_fan):
            ret = yield control.is_psu_up(internal_index)
            if ret:
                is_up = ret
                sensor_oid = control.get_oid_for_psu_status(internal_index)
            self._logger.debug('PSU: %s: %s', ret, sensor_oid)
        phys_name = psu_or_fan.get('entPhysicalName', None)

        power_supply = self.containers.factory(phys_name,
                                               shadows.PowerSupplyOrFan)
        # psu info
        power_supply.netbox = self.netbox
        power_supply.name = phys_name
        power_supply.model = psu_or_fan.get('entPhysicalModelName', None)
        power_supply.descr = psu_or_fan.get('entPhysicalDescr', None)
        power_supply.physical_class = psu_or_fan.get('entPhysicalClass', None)
        power_supply.sensor_oid = sensor_oid
        power_supply.up = is_up
        # device info
        serial = psu_or_fan.get('entPhysicalSerialNum', None)
        if serial:
            device = self.containers.factory(serial, shadows.Device)
            device.serial = serial
            device.hardware_version = psu_or_fan.get('entPhysicalHardwareRev',
                                                     None)
            device.firmware_version = psu_or_fan.get('entPhysicalFirmwareRev',
                                                     None)
            device.software_version = psu_or_fan.get('entPhysicalSoftwareRev',
                                                     None)
            power_supply.device = device
Example #3
0
class Modules(Plugin):
    """Plugin to collect module and chassis data from devices"""

    def __init__(self, *args, **kwargs):
        super(Modules, self).__init__(*args, **kwargs)
        self.alias_mapping = {}
        self.entitymib = EntityMib(self.agent)
        self.stampcheck = TimestampChecker(self.agent, self.containers,
                                           INFO_VAR_NAME)

    @defer.inlineCallbacks
    def handle(self):
        self._logger.debug("Collecting ENTITY-MIB module data")
        need_to_collect = yield self._need_to_collect()
        if need_to_collect:
            physical_table = (
                yield self.entitymib.get_useful_physical_table_columns())

            alias_mapping = yield self.entitymib.retrieve_column(
                'entAliasMappingIdentifier')
            self.alias_mapping = self._process_alias_mapping(alias_mapping)
            self._process_entities(physical_table)
        self.stampcheck.save()

    @defer.inlineCallbacks
    def _need_to_collect(self):
        yield self.stampcheck.load()
        yield self.stampcheck.collect([self.entitymib.get_last_change_time()])

        result = yield self.stampcheck.is_changed()
        defer.returnValue(result)

    def _device_from_entity(self, ent, chassis=False):
        serial_column = 'entPhysicalSerialNum'
        if serial_column in ent and ent[serial_column] and \
            ent[serial_column].strip():
            serial_number = ent[serial_column].strip()
            device_key = serial_number
        else:
            serial_number = None
            device_key = 'unknown-%s' % ent[0]

        # check whether some plugin already registered a chassis device
        # without knowing its serial. If so, give the device two keys in the
        # container repository
        if chassis and self.containers.get(None, shadows.Device):
            device = self.containers.get(None, shadows.Device)
            self.containers[shadows.Device][device_key] = device
        else:
            device = self.containers.factory(device_key, shadows.Device)
        if serial_number:
            device.serial = serial_number
        if ent['entPhysicalHardwareRev']:
            device.hardware_version = ent['entPhysicalHardwareRev'].strip()
        if ent['entPhysicalSoftwareRev']:
            device.software_version = ent['entPhysicalSoftwareRev'].strip()
        if ent['entPhysicalFirmwareRev']:
            device.firmware_version = ent['entPhysicalFirmwareRev'].strip()
        device.active = True
        return device

    def _module_from_entity(self, ent):
        module = self.containers.factory(ent['entPhysicalSerialNum'],
                                         shadows.Module)
        netbox = self.containers.factory(None, shadows.Netbox)

        module.netbox = netbox
        module.model = ent['entPhysicalModelName'].strip()
        module.description = ent['entPhysicalDescr'].strip()
        module.name = ent['entPhysicalName'].strip()
        if module.name.strip().isdigit():
            module.module_number = int(module.name.strip())
        module.parent = None
        return module

    def _process_modules(self, entities):
        # map entity indexes to module containers
        module_containers = {}
        modules = entities.get_modules()
        for ent in modules:
            entity_index = ent[0]
            device = self._device_from_entity(ent)
            module = self._module_from_entity(ent)
            module.device = device

            module_containers[entity_index] = module
            self._logger.debug("module (entPhysIndex=%s): %r",
                               entity_index, module)

        return module_containers

    def _process_chassis(self, entities):
        chassis = entities.get_chassis()
        if not chassis:
            self._logger.debug('No chassis found')
            return
        elif len(chassis) > 1:
            self._logger.debug('Found multiple chassis')

        # We don't really know how to handle a multiple chassis
        # situation.  Best effort is to use the first one in the list.
        # This should be revised by someone who has stacked chassis
        # devices to test on.
        the_chassis = chassis[0]
        device = self._device_from_entity(the_chassis, chassis=True)
        netbox = self.containers.factory(None, shadows.Netbox)
        netbox.device = device

    def _process_ports(self, entities, module_containers):
        ports = entities.get_ports()
        netbox = self.containers.factory(None, shadows.Netbox)

        # Map interfaces to modules, if possible
        module_ifindex_map = {} #just for logging debug info
        for port in ports:
            entity_index = port[0]
            if entity_index in self.alias_mapping:
                module_entity = entities.get_nearest_module_parent(port)

                if module_entity and module_entity[0] in module_containers:
                    module = module_containers[ module_entity[0] ]
                    indices = self.alias_mapping[entity_index]
                    for ifindex in indices:
                        interface = self.containers.factory(ifindex,
                                                            shadows.Interface)
                        interface.netbox = netbox
                        interface.ifindex = ifindex
                        interface.module = module

                        if module.name in module_ifindex_map:
                            module_ifindex_map[module.name].append(ifindex)
                        else:
                            module_ifindex_map[module.name] = [ifindex]

        if module_ifindex_map:
            self._logger.debug("module/ifindex mapping: %r",
                              module_ifindex_map)


    def _process_entities(self, result):
        """Process the list of collected entities."""
        # be able to look up all entities using entPhysicalIndex
        entities = EntityTable(result)

        module_containers = self._process_modules(entities)
        self._process_chassis(entities)
        self._process_ports(entities, module_containers)


    def _process_alias_mapping(self, alias_mapping):
        mapping = {}
        for (phys_index, _logical), rowpointer in alias_mapping.items():
            # Last element is ifindex. Preceding elements is an OID.
            ifindex = OID(rowpointer)[-1]

            if phys_index not in mapping:
                mapping[phys_index] = []
            mapping[phys_index].append(ifindex)

        self._logger.debug("alias mapping: %r", mapping)
        return mapping