def handle(self): if self.netbox.master: self._logger.debug("this is a virtual instance of %s, not polling", self.netbox.master) returnValue(None) poemib = PowerEthernetMib(self.agent) if self.netbox.type and self.netbox.type.vendor.id == 'cisco': cisco_mib = CiscoPowerEthernetExtMib(self.agent) port_phy_index = yield cisco_mib.retrieve_column( "cpeExtPsePortEntPhyIndex") group_phy_index = yield cisco_mib.retrieve_column( "cpeExtMainPseEntPhyIndex") entity_mib = EntityMib(self.agent) alias_mapping = yield entity_mib.get_alias_mapping() port_ifindices = self._resolve_ifindex(port_phy_index, alias_mapping) else: port_ifindices = {} group_phy_index = {} groups = yield poemib.get_groups_table() self._process_groups(groups, group_phy_index) ports = yield poemib.get_ports_table() self._process_ports(ports, port_ifindices) self._log_invalid_portgroups()
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)
def _get_units(func, entity_physical_table): mib = EntityMib(Mock("AgentProxy")) def mock_retrieve(columns): return defer.succeed(entity_physical_table) mib.retrieve_columns = mock_retrieve df = getattr(mib, func)() assert df.called if isinstance(df.result, failure.Failure): df.result.raiseException() return df.result
def test_empty_logical_type_should_not_raise(self): mib = EntityMib(Mock('AgentProxy')) def mock_retrieve(columns): return defer.succeed( {1: {'entLogicalDescr': None, 'entLogicalType': None, 'entLogicalCommunity': None}} ) mib.retrieve_columns = mock_retrieve df = mib.retrieve_alternate_bridge_mibs() self.assertTrue(df.called) if isinstance(df.result, failure.Failure): df.result.raiseException()
def _map_cisco_power_ports_to_ifindex(self): """Uses the Cisco proprietary CISCO-POWER-ETHERNET-EXT-MIB to map the group/port index pairs used exclusively in PORT-ETHERNET-MIB to an actual ifIndex, that most other MIBs (and NAV's Interface model) uses for identification of interfaces/ports. POWER-ETHERNET-MIB provides only a very vague identification of power-enabled ports. These identifiers are not universally and consistently mappable to an ifIndex, for example. A more conclusive mapping to interfaces may be provided on a vendor-by-vendor basis. The only supported vendor for mapping in this codebase so far is Cisco. Cisco's mapping is indirect via the ENTITY-MIB - each entry from the power ethernet tables is mapped to a physical port in ENTITY-MIB::entPhysicalTable via its entPhysicalIndex. This table, in turn, can map physical ports to interface indexes from the IF-MIB::ifTable. """ cisco_mib = CiscoPowerEthernetExtMib(self.agent) port_phy_index = yield cisco_mib.retrieve_column("cpeExtPsePortEntPhyIndex") group_phy_index = yield cisco_mib.retrieve_column("cpeExtMainPseEntPhyIndex") entity_mib = EntityMib(self.agent) alias_mapping = yield entity_mib.get_alias_mapping() port_ifindices = self._resolve_ifindex(port_phy_index, alias_mapping) returnValue((group_phy_index, port_ifindices))
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
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
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)
class EntitySensorMib(mibretriever.MibRetriever): from nav.smidumps.entity_sensor_mib import MIB as mib def __init__(self, agent_proxy): """Good old constructor...""" super(EntitySensorMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy) def _get_sensors(self): """ Collect all sensors.""" df = self.retrieve_columns([ 'entPhySensorType', 'entPhySensorScale', 'entPhySensorPrecision', 'entPhySensorValue', 'entPhySensorOperStatus', 'entPhySensorUnitsDisplay', ]) df.addCallback(reduce_index) return df def _collect_entity_names(self): """ Collect all entity-names on netbox.""" df = self.entity_mib.retrieve_columns([ 'entPhysicalDescr', 'entPhysicalName', ]) df.addCallback(reduce_index) return df @defer.inlineCallbacks def _get_named_table(self, table_name): df = self.retrieve_table(table_name) df.addCallback(self.translate_result) ret_table = yield df named_table = EntityTable(ret_table) defer.returnValue(named_table) @defer.inlineCallbacks def get_phy_sensor_table(self): phy_sensor_table = yield self._get_named_table('entPhySensorTable') defer.returnValue(phy_sensor_table) @defer.inlineCallbacks def get_all_sensors(self): """ Collect all sensors and names on a netbox, and match sensors with names. Return a list with dictionaries, each dictionary represent a sensor.""" sensors = yield self._get_sensors() entity_names = yield self._collect_entity_names() for idx, row in entity_names.items(): if idx in sensors: sensors[idx]['entPhysicalDescr'] = row.get( 'entPhysicalDescr', None) sensors[idx]['entPhysicalName'] = row.get( 'entPhysicalName', None) result = [] for row_id, row in sensors.items(): row_oid = row.get(0, None) mibobject = self.nodes.get('entPhySensorValue', None) oid = str(mibobject.oid) + str(row_oid) unit_of_measurement = row.get('entPhySensorType', 2) precision = row.get('entPhySensorPrecision', 0) scale = row.get('entPhySensorScale', None) op_status = row.get('entPhySensorOperStatus', None) description = row.get('entPhysicalDescr', None) name = row.get('entPhysicalName', None) internal_name = name if op_status == 1: result.append({ 'oid': oid, 'unit_of_measurement': UNITS_OF_MEASUREMENTS.get(unit_of_measurement, None), 'precision': precision, 'scale': DATA_SCALE.get(scale, None), 'description': description, 'name': name, 'internal_name': internal_name, 'mib': self.get_module_name(), }) self._logger.debug('get_all_sensors: result=%s', result) defer.returnValue(result)
class Entity(Plugin): """Plugin to collect physical entity data from devices""" def __init__(self, *args, **kwargs): super(Entity, 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 physical entity data") need_to_collect = yield self._need_to_collect() #if need_to_collect: if True: physical_table = ( yield self.entitymib.get_entity_physical_table()) self._logger.debug("found %d entities", len(physical_table)) 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 _process_entities(self, result): """Process the list of collected entities.""" # be able to look up all entities using entPhysicalIndex entities = EntityTable(result) entities.clean_unicode() containers = [self._container_from_entity(entity) for entity in entities.values()] self._fix_hierarchy(containers) def _fix_hierarchy(self, containers): by_index = {c.index: c for c in containers} ghosts = set() for container in containers: if container.contained_in: parent_id = unicode(container.contained_in) parent = by_index.get(parent_id) if parent: container.contained_in = parent else: ghosts.add(str(container.contained_in)) container.contained_in = None if ghosts: self._logger.info( "kick your device vendor in the shin. entPhysicalContainedIn " "values refer to non-existant entities: %s", ", ".join(ghosts)) field_map = {k: 'entPhysical'+v for k, v in dict( index='Index', descr='Descr', vendor_type='VendorType', contained_in='ContainedIn', physical_class='Class', parent_relpos='ParentRelPos', name='Name', hardware_revision='HardwareRev', firmware_revision='FirmwareRev', software_revision='SoftwareRev', mfg_name='MfgName', model_name='ModelName', alias='Alias', asset_id='AssetID', fru='IsFRU', mfg_date='MfgDate', uris='Uris', serial='SerialNum', ).items()} class_map = {name: value for value, name in manage.NetboxEntity.CLASS_CHOICES} def _container_from_entity(self, ent): device_key = 'ENTITY-MIB:' + str(ent.get(0)) container = self.containers.factory(device_key, NetboxEntity) netbox = self.containers.factory(None, shadows.Netbox) container.netbox = netbox container.index = ent.get(0) container.source = 'ENTITY-MIB' for attr, column in self.field_map.items(): value = ent.get(column) if column == 'entPhysicalClass': value = self.class_map.get(value) if value is not None: setattr(container, attr, value) if getattr(container, 'serial', None): device = self.containers.factory(container.serial, shadows.Device) device.serial = container.serial for key in ('hardware', 'firmware', 'software'): val = getattr(container, key + '_revision') if val: setattr(device, key + '_version', val) device.active = True container.device = device return container
def __init__(self, *args, **kwargs): super(Entity, self).__init__(*args, **kwargs) self.alias_mapping = {} self.entitymib = EntityMib(self.agent) self.stampcheck = TimestampChecker(self.agent, self.containers, INFO_VAR_NAME)
class CiscoEntityFruControlMib(mibretriever.MibRetriever): """A MibRetriever to collect inventory and status information for field-replaceable units (such as power supplies and fans) on Cisco netboxes. """ mib = get_mib("CISCO-ENTITY-FRU-CONTROL-MIB") def __init__(self, agent_proxy): super(CiscoEntityFruControlMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy) self.fan_status_table = None self.psu_status_table = None def _get_fantray_status_table(self): """Retrieve the whole table of fan-sensors.""" return self.retrieve_table("cefcFanTrayStatusTable").addCallback( reduce_index) def _get_power_status_table(self): """Retrieve the whole table of PSU-sensors.""" self.retrieve_table("cefcFRUPowerStatusTable").addCallback( reduce_index) @staticmethod def _translate_fan_status(oper_status): """Translates the fan status value from the MIB to a NAV PSU status value. :returns: A state value from nav.models.manage.PowerSupplyOrFan.STATE_CHOICES """ return FAN_STATUS_MAP.get(oper_status, PowerSupplyOrFan.STATE_UNKNOWN) @staticmethod def _translate_power_supply_status_value(oper_status): """Translates the PSU status value from the MIB to a NAV PSU status value. :returns: A state value from nav.models.manage.PowerSupplyOrFan.STATE_CHOICES """ return PSU_STATUS_MAP.get(oper_status, PowerSupplyOrFan.STATE_UNKNOWN) @defer.inlineCallbacks def get_fan_status(self, internal_id): """Returns the operational status for a fan with the given internal id.""" oper_status = yield self.retrieve_column_by_index( "cefcFanTrayOperStatus", (int(internal_id), )) self._logger.debug("cefcFanTrayOperStatus.%s = %r", internal_id, oper_status) defer.returnValue(self._translate_fan_status(oper_status)) @defer.inlineCallbacks def get_power_supply_status(self, internal_id): """Returns the operational status for a PSU with the given internal id.""" oper_status = yield self.retrieve_column_by_index( "cefcFRUPowerOperStatus", (int(internal_id), )) self._logger.debug("cefcFRUPowerOperStatus.%s = %r", internal_id, oper_status) defer.returnValue( self._translate_power_supply_status_value(oper_status)) @defer.inlineCallbacks def get_fan_status_table(self): """Retrieve the whole table of fan-sensors and cache the result.""" if not self.fan_status_table: self.fan_status_table = yield self._get_fantray_status_table() defer.returnValue(self.fan_status_table) @defer.inlineCallbacks def get_psu_status_table(self): """Retrieve the whole table of PSU-sensors and cache the result.""" if not self.psu_status_table: self.psu_status_table = yield self._get_power_status_table() defer.returnValue(self.psu_status_table) def get_power_supplies(self): """Retrieves a list of power supply objects""" return self.entity_mib.get_power_supplies() @defer.inlineCallbacks def get_fans(self): """Retrieves a list of fan objects. A Cisco device reports fan trays and individual fans in entPhysicalTable, but only the status of entire fan trays can be queried from this MIB, so this filters away any non-FRU units. """ fans = yield self.entity_mib.get_fans() status = yield self.get_fan_status_table() self._logger.debug("found %d/%d field-replaceable fan entities", len(status), len(fans)) fans = [fan for fan in fans if fan.internal_id in status] defer.returnValue(fans)
def __init__(self, agent_proxy): super(CiscoEntityFruControlMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy) self.fan_status_table = None self.psu_status_table = None
def __init__(self, agent_proxy): """Good old constructor...""" super(EntitySensorMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy)
class CiscoEntitySensorMib(mibretriever.MibRetriever): """This MIB should collect all present sensors from Cisco NEXUS boxes.""" from nav.smidumps.cisco_entity_sensor_mib import MIB as mib def __init__(self, agent_proxy): """Good old constructor...""" super(CiscoEntitySensorMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy) def get_module_name(self): """Get the name of this MIB""" return self.mib.get('moduleName', None) def _get_sensors(self): """ Collect all sensors from the box.""" df = self.retrieve_columns([ 'entSensorType', 'entSensorScale', 'entSensorPrecision', 'entSensorValue', 'entSensorStatus', 'entSensorValueTimeStamp', 'entSensorValueUpdateRate', 'entSensorMeasuredEntity', ]) df.addCallback(reduce_index) return df def _collect_entity_names(self): """ Collect all entity-names in netbox.""" df = self.entity_mib.retrieve_columns([ 'entPhysicalDescr', 'entPhysicalName', ]) df.addCallback(reduce_index) return df @defer.inlineCallbacks def get_all_sensors(self): """ Collect all sensors and names on a netbox, and match sensors with names. Return a list with dictionaries, each dictionary represent a sensor.""" self._logger.debug('get_all_sensors: Called....') sensors = yield self._get_sensors() entity_names = yield self._collect_entity_names() for idx, row in entity_names.items(): if idx in sensors: sensors[idx]['entPhysicalDescr'] = row.get( 'entPhysicalDescr', None) sensors[idx]['entPhysicalName'] = row.get( 'entPhysicalName', None) result = [] for row_id, row in sensors.items(): row_oid = row.get(0, None) mibobject = self.nodes.get('entSensorValue', None) oid = str(mibobject.oid) + str(row_oid) unit_of_measurement = row.get('entSensorType', 2) precision = row.get('entSensorPrecision', 0) scale = row.get('entSensorScale', None) op_status = row.get('entSensorStatus', None) description = row.get('entPhysicalDescr', None) name = row.get('entPhysicalName', None) internal_name = name if op_status == 1: result.append({ 'oid': oid, 'unit_of_measurement': UNITS_OF_MEASUREMENTS.get(unit_of_measurement, None), 'precision': precision, 'scale': DATA_SCALE.get(scale, None), 'description': description, 'name': name, 'internal_name': internal_name, 'mib': self.get_module_name(), }) self._logger.debug('get_all_sensors: result=%s' % str(result)) defer.returnValue(result)
class EntitySensorMib(mibretriever.MibRetriever): from nav.smidumps.entity_sensor_mib import MIB as mib def __init__(self, agent_proxy): """Good old constructor...""" super(EntitySensorMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy) def get_module_name(self): """Return this MIB-name""" return self.mib.get('moduleName', None) def _get_sensors(self): """ Collect all sensors.""" df = self.retrieve_columns([ 'entPhySensorType', 'entPhySensorScale', 'entPhySensorPrecision', 'entPhySensorValue', 'entPhySensorOperStatus', 'entPhySensorUnitsDisplay', ]) df.addCallback(reduce_index) return df def _collect_entity_names(self): """ Collect all entity-names on netbox.""" df = self.entity_mib.retrieve_columns([ 'entPhysicalDescr', 'entPhysicalName', ]) df.addCallback(reduce_index) return df @defer.inlineCallbacks def _get_named_table(self, table_name): df = self.retrieve_table(table_name) df.addCallback(self.translate_result) ret_table = yield df named_table = EntityTable(ret_table) defer.returnValue(named_table) @defer.inlineCallbacks def get_phy_sensor_table(self): phy_sensor_table = yield self._get_named_table('entPhySensorTable') defer.returnValue(phy_sensor_table) @defer.inlineCallbacks def get_all_sensors(self): """ Collect all sensors and names on a netbox, and match sensors with names. Return a list with dictionaries, each dictionary represent a sensor.""" sensors = yield self._get_sensors() entity_names = yield self._collect_entity_names() for idx, row in entity_names.items(): if idx in sensors: sensors[idx]['entPhysicalDescr'] = row.get( 'entPhysicalDescr',None) sensors[idx]['entPhysicalName'] = row.get( 'entPhysicalName', None) result = [] for row_id, row in sensors.items(): row_oid = row.get(0, None) mibobject = self.nodes.get('entPhySensorValue', None) oid = str(mibobject.oid) + str(row_oid) unit_of_measurement = row.get('entPhySensorType', 2) precision = row.get('entPhySensorPrecision', 0) scale = row.get('entPhySensorScale', None) op_status = row.get('entPhySensorOperStatus', None) description = row.get('entPhysicalDescr', None) name = row.get('entPhysicalName', None) internal_name = name if op_status == 1: result.append({ 'oid': oid, 'unit_of_measurement': UNITS_OF_MEASUREMENTS.get( unit_of_measurement, None), 'precision': precision, 'scale': DATA_SCALE.get(scale, None), 'description': description, 'name': name, 'internal_name': internal_name, 'mib': self.get_module_name(), }) self._logger.debug('get_all_sensors: result=%s', result) defer.returnValue(result)
class Modules(Plugin): """Plugin to collect module 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_entity_physical_table()) self.alias_mapping = yield self.entitymib.get_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): 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] 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_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_ports(entities, module_containers)
def __init__(self, agent_proxy): super(HpIcfFanMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(agent_proxy) self.fan_status_table = None
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
class EntitySensorMib(mibretriever.MibRetriever): from nav.smidumps.entity_sensor_mib import MIB as mib TYPE_COLUMN = 'entPhySensorType' SCALE_COLUMN = 'entPhySensorScale' PRECISION_COLUMN = 'entPhySensorPrecision' VALUE_COLUMN = 'entPhySensorValue' STATUS_COLUMN = 'entPhySensorOperStatus' def __init__(self, agent_proxy): """Good old constructor...""" super(EntitySensorMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy) def _get_sensors(self): """ Collect all sensors from the box.""" df = self.retrieve_columns([ self.TYPE_COLUMN, self.SCALE_COLUMN, self.PRECISION_COLUMN, self.VALUE_COLUMN, self.STATUS_COLUMN, ]) df.addCallback(reduce_index) return df @defer.inlineCallbacks def get_all_sensors(self): """ Collect all sensors and names on a netbox, and match sensors with names. Return a list with dictionaries, each dictionary represent a sensor.""" sensors = yield self._get_sensors() entities = yield self.entity_mib.get_entity_physical_table() aliases = yield self.entity_mib.get_alias_mapping() for idx, row in entities.items(): if idx in sensors: sensors[idx]['entPhysicalDescr'] = row.get( 'entPhysicalDescr', None) sensors[idx]['entPhysicalName'] = row.get( 'entPhysicalName', None) port = entities.get_nearest_port_parent(row) if port and port.index[-1] in aliases: ifindices = aliases[port.index[-1]] if len(ifindices) == 1: sensors[idx]['ifindex'] = ifindices[0] result = [] for row_id, row in sensors.items(): row_oid = row.get(0, None) mibobject = self.nodes.get(self.VALUE_COLUMN, None) oid = str(mibobject.oid) + str(row_oid) unit_of_measurement = row.get(self.TYPE_COLUMN, 2) precision = row.get(self.PRECISION_COLUMN, 0) scale = row.get(self.SCALE_COLUMN, None) op_status = row.get(self.STATUS_COLUMN, None) description = row.get('entPhysicalDescr', None) name = row.get('entPhysicalName', None) ifindex = row.get('ifindex') internal_name = name if op_status == 1: result.append({ 'oid': oid, 'unit_of_measurement': UNITS_OF_MEASUREMENTS.get(unit_of_measurement, None), 'precision': precision, 'scale': DATA_SCALE.get(scale, None), 'description': description, 'name': name, 'internal_name': internal_name, 'mib': self.get_module_name(), 'ifindex': ifindex, }) self._logger.debug('get_all_sensors: result=%s', result) defer.returnValue(result)
class HpIcfPowerSupplyMib(mibretriever.MibRetriever): """A MibRetriever for collecting power supply states from HP netboxes.""" mib = get_mib("POWERSUPPLY-MIB") def __init__(self, agent_proxy): super(HpIcfPowerSupplyMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(agent_proxy) self.psu_status_table = None @defer.inlineCallbacks def _get_psu_status_table(self): """Returns the power supply status table from this netbox.""" df = self.retrieve_table("hpicfPsTable") df.addCallback(self.translate_result) df.addCallback(reduce_index) psu_table = yield df self._logger.debug("psu_table: %r", psu_table) defer.returnValue(psu_table) @staticmethod def _translate_psu_status(psu_status): """Translates the PSU status value from the MIB to a NAV PSU status value. :returns: A state value from nav.models.manage.PowerSupplyOrFan.STATE_CHOICES """ return PSU_STATUS_MAP.get(psu_status, PSU.STATE_UNKNOWN) @defer.inlineCallbacks def get_power_supply_status(self, internal_id): """Returns the status of the powersupply with the given internal id.""" if not self.psu_status_table: self.psu_status_table = yield self._get_psu_status_table() index = _psu_index_from_internal_id(internal_id) psu_status_row = self.psu_status_table.get(index, {}) psu_status = psu_status_row.get("hpicfPsState") self._logger.debug("hpicfPsState.%s = %r", index, psu_status) defer.returnValue(self._translate_psu_status(psu_status)) @defer.inlineCallbacks def get_power_supplies(self): """Retrieves a list of power supply objects""" hp_psus = yield self._get_psu_status_table() entities = yield self.entity_mib.get_power_supplies() if len(hp_psus) != len(entities): self._logger.warning( "Number of power supplies in ENTITY-MIB (%d) and POWERSUPPLY-MIB (%d) " "do not match", len(entities), len(hp_psus), ) # Power supplies are always numbered from 1 and up in POWERSUPPLY-MIB, # and there is no official way to map their IDs to # ENTITY-MIB::entPhysicalTable - therefore, this code naively assumes they at # least appear in the same order in the two MIBS for index, ent in enumerate(sorted(entities, key=attrgetter("internal_id")), start=1): ent.internal_id = "{}:{}".format(ent.internal_id, index) defer.returnValue(entities)
def __init__(self, agent_proxy): super(HpIcfPowerSupplyMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(agent_proxy) self.psu_status_table = None
class CiscoEntitySensorMib(mibretriever.MibRetriever): """This MIB should collect all present sensors from Cisco NEXUS boxes.""" from nav.smidumps.cisco_entity_sensor_mib import MIB as mib def __init__(self, agent_proxy): """Good old constructor...""" super(CiscoEntitySensorMib, self).__init__(agent_proxy) self.entity_mib = EntityMib(self.agent_proxy) def get_module_name(self): """Get the name of this MIB""" return self.mib.get('moduleName', None) def _get_sensors(self): """ Collect all sensors from the box.""" df = self.retrieve_columns([ 'entSensorType', 'entSensorScale', 'entSensorPrecision', 'entSensorValue', 'entSensorStatus', 'entSensorValueTimeStamp', 'entSensorValueUpdateRate', 'entSensorMeasuredEntity', ]) df.addCallback(reduce_index) return df def _collect_entity_names(self): """ Collect all entity-names in netbox.""" df = self.entity_mib.retrieve_columns([ 'entPhysicalDescr', 'entPhysicalName', ]) df.addCallback(reduce_index) return df @defer.inlineCallbacks def get_all_sensors(self): """ Collect all sensors and names on a netbox, and match sensors with names. Return a list with dictionaries, each dictionary represent a sensor.""" self._logger.debug('get_all_sensors: Called....') sensors = yield self._get_sensors() entity_names = yield self._collect_entity_names() for idx, row in entity_names.items(): if idx in sensors: sensors[idx]['entPhysicalDescr'] = row.get( 'entPhysicalDescr',None) sensors[idx]['entPhysicalName'] = row.get( 'entPhysicalName', None) result = [] for row_id, row in sensors.items(): row_oid = row.get(0, None) mibobject = self.nodes.get('entSensorValue', None) oid = str(mibobject.oid) + str(row_oid) unit_of_measurement = row.get('entSensorType', 2) precision = row.get('entSensorPrecision', 0) scale = row.get('entSensorScale', None) op_status = row.get('entSensorStatus', None) description = row.get('entPhysicalDescr', None) name = row.get('entPhysicalName', None) internal_name = name if op_status == 1: result.append({ 'oid': oid, 'unit_of_measurement': UNITS_OF_MEASUREMENTS.get( unit_of_measurement, None), 'precision': precision, 'scale': DATA_SCALE.get(scale, None), 'description': description, 'name': name, 'internal_name': internal_name, 'mib': self.get_module_name(), }) self._logger.debug('get_all_sensors: result=%s' % str(result)) defer.returnValue(result)