Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sensors relatable to interfaces #1558

Merged
merged 8 commits into from
Sep 5, 2017
17 changes: 1 addition & 16 deletions python/nav/ipdevpoll/plugins/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ def handle(self):
physical_table = (
yield self.entitymib.get_entity_physical_table())

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

Expand Down Expand Up @@ -156,16 +154,3 @@ def _process_entities(self, result):

module_containers = self._process_modules(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
6 changes: 6 additions & 0 deletions python/nav/ipdevpoll/plugins/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def _store_sensors(self, result):
oid = row.get('oid', None)
internal_name = row.get('internal_name', None)
mib = row.get('mib', None)
ifindex = row.get('ifindex')
# Minimum requirement. Uniq by netbox, internal name and mib
if oid and internal_name and mib:
sensor = self.containers.factory(oid, shadows.Sensor)
Expand All @@ -111,6 +112,11 @@ def _store_sensors(self, result):
sensor.mib = mib
sensor.display_minimum_sys = row.get('minimum', None)
sensor.display_maximum_sys = row.get('maximum', None)
if ifindex:
iface = self.containers.factory(ifindex, shadows.Interface)
iface.netbox = self.netbox
iface.ifindex = ifindex
sensor.interface = iface
sensors.append(sensors)
return sensors

Expand Down
124 changes: 7 additions & 117 deletions python/nav/mibs/cisco_entity_sensor_mib.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,125 +13,15 @@
# more details. You should have received a copy of the GNU General Public
# License along with NAV. If not, see <http://www.gnu.org/licenses/>.
#
"""Implements a MibRetriever for the ENTITY-MIB, as well as helper classes."""

from twisted.internet import defer
from nav.mibs.entity_sensor_mib import EntitySensorMib

from nav.mibs import reduce_index
from nav.mibs.entity_mib import EntityMib
from nav.mibs import mibretriever
from nav.models.manage import Sensor

UNITS_OF_MEASUREMENTS = {
1: Sensor.UNIT_OTHER,
2: Sensor.UNIT_UNKNOWN,
3: Sensor.UNIT_VOLTS_AC,
4: Sensor.UNIT_VOLTS_DC,
5: Sensor.UNIT_AMPERES,
6: Sensor.UNIT_WATTS,
7: Sensor.UNIT_HERTZ,
8: Sensor.UNIT_CELSIUS,
9: Sensor.UNIT_PERCENT_RELATIVE_HUMIDITY,
10: Sensor.UNIT_RPM,
11: Sensor.UNIT_CMM,
12: Sensor.UNIT_TRUTHVALUE,
13: 'specialEnum',
14: Sensor.UNIT_DBM,
}

DATA_SCALE = {
1: 'yocto',
2: 'zepto',
3: 'atto',
4: 'femto',
5: 'pico',
6: 'nano',
7: 'micro',
8: 'milli',
9: None,
10: 'kilo',
11: 'mega',
12: 'giga',
13: 'tera',
14: 'exa',
15: 'peta',
16: 'zetta',
17: 'yotta',
}


class CiscoEntitySensorMib(mibretriever.MibRetriever):
class CiscoEntitySensorMib(EntitySensorMib):
"""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_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)
TYPE_COLUMN = 'entSensorType'
SCALE_COLUMN = 'entSensorScale'
PRECISION_COLUMN = 'entSensorPrecision'
VALUE_COLUMN = 'entSensorValue'
STATUS_COLUMN = 'entSensorStatus'
33 changes: 33 additions & 0 deletions python/nav/mibs/entity_mib.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@ def get_useful_physical_table_columns(self):
])
defer.returnValue(self.translate_result(columns))

@defer.inlineCallbacks
def get_alias_mapping(self):
alias_mapping = yield self.retrieve_column(
'entAliasMappingIdentifier')
defer.returnValue(self._process_alias_mapping(alias_mapping))

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 EntityTable(dict):
"""Represent the contents of the entPhysicalTable as a dictionary"""
Expand Down Expand Up @@ -193,6 +212,20 @@ def get_nearest_module_parent(self, entity):
else:
return self.get_nearest_module_parent(parent)

def get_nearest_port_parent(self, entity):
"""Traverse the entity hierarchy to find a suitable parent port.

Returns a port row if a parent is found, else None is returned.

"""
parent_index = entity['entPhysicalContainedIn']
if parent_index in self:
parent = self[parent_index]
if self.is_port(parent):
return parent
else:
return self.get_nearest_port_parent(parent)

def get_chassis_of(self, entity):
"""Returns the nearest parent chassis of an entity.

Expand Down
87 changes: 40 additions & 47 deletions python/nav/mibs/entity_sensor_mib.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from nav.mibs import reduce_index
from nav.mibs.entity_mib import EntityMib
from nav.mibs.entity_mib import EntityTable
from nav.mibs import mibretriever
from nav.models.manage import Sensor

Expand All @@ -36,6 +35,8 @@
10: Sensor.UNIT_RPM,
11: Sensor.UNIT_CMM,
12: Sensor.UNIT_TRUTHVALUE,
13: 'specialEnum', # cisco extension
14: Sensor.UNIT_DBM, # cisco extension
}

DATA_SCALE = {
Expand All @@ -48,60 +49,44 @@
7: 'micro',
8: 'milli',
9: None,
10: 'kilo',
11: 'mega',
12: 'giga',
13: 'tera',
14: 'exa',
15: 'peta',
16: 'zetta',
17: 'yotta',
}
10: 'kilo',
11: 'mega',
12: 'giga',
13: 'tera',
14: 'exa',
15: 'peta',
16: 'zetta',
17: 'yotta',
}


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'
UNITS_DISPLAY_COLUMN = 'entPhySensorUnitsDisplay'

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."""
""" Collect all sensors from the box."""
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',
self.TYPE_COLUMN,
self.SCALE_COLUMN,
self.PRECISION_COLUMN,
self.VALUE_COLUMN,
self.STATUS_COLUMN,
self.UNITS_DISPLAY_COLUMN,
])
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
Expand All @@ -110,36 +95,44 @@ def get_all_sensors(self):
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():
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('entPhySensorValue', None)
mibobject = self.nodes.get(self.VALUE_COLUMN, 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)
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),
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)
1 change: 1 addition & 0 deletions python/nav/models/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,7 @@ class Sensor(models.Model):

id = models.AutoField(db_column='sensorid', primary_key=True)
netbox = models.ForeignKey(Netbox, db_column='netboxid')
interface = models.ForeignKey(Interface, db_column='interfaceid', null=True)
oid = VarcharField(db_column="oid")
unit_of_measurement = VarcharField(db_column="unit_of_measurement",
choices=UNIT_OF_MEASUREMENTS_CHOICES)
Expand Down