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

Collect Juniper dom threshold values #2513

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
22aa26d
Add metric path for thresholds
stveit Jun 30, 2022
2324494
Add function for getting thresholds in juniper mib
stveit Jun 30, 2022
e2e869b
Collect threshold values
stveit Jun 30, 2022
ebc385d
Give thresholds generic nameing
stveit Jun 30, 2022
2d6f307
Add threshold properties
stveit Feb 8, 2023
b4f2cb8
Add related sensor for threshold sensors
stveit Feb 10, 2023
867376e
Update SQL tables
stveit Feb 10, 2023
ed62f06
Revert "Collect threshold values"
stveit Feb 11, 2023
fd078b6
Change field to refer to oid of other sensor
stveit Feb 11, 2023
9c8a55f
Add property for accessing related sensor
stveit Feb 11, 2023
5eba3e0
Collect threshold values as sensors
stveit Feb 11, 2023
d21aeb9
Access items correctly
stveit Feb 14, 2023
11a5613
Do not access items
stveit Feb 14, 2023
ebcec4f
fixup! Change field to refer to oid of other sensor
stveit Feb 14, 2023
7a93cea
fixup! Add property for accessing related sensor
stveit Feb 14, 2023
f6088cd
Revert "Add metric path for thresholds"
stveit Feb 14, 2023
f768bdf
Add property for getting relevant thresholds
stveit Feb 14, 2023
2a2ce7e
Add test file for juniper dom mib
stveit Feb 15, 2023
1ec98ce
Add tests for creating sensor dicts
stveit Feb 16, 2023
a58dd65
Allow field to be null
stveit Feb 17, 2023
0d5f2b6
Add tests for sensor model changes
stveit Feb 17, 2023
4fd5cf5
fixup! Add tests for sensor model changes
stveit Feb 17, 2023
ab3d427
Make test work with existing stuff in database
stveit Feb 21, 2023
a9a6080
Reference sensor for oid
stveit Feb 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions python/nav/ipdevpoll/plugins/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ def _store_sensors(self, result):
sensor.on_message_sys = row.get('on_message')
sensor.off_message_sys = row.get('off_message')
sensor.on_state_sys = row.get('on_state')
sensor.threshold_type = row.get('threshold_type')
sensor.threshold_alert_type = row.get('threshold_alert_type')
sensor.threshold_for_oid = row.get('threshold_for_oid')
if ifindex:
iface = self.containers.factory(ifindex, shadows.Interface)
iface.netbox = self.netbox
Expand Down
133 changes: 129 additions & 4 deletions python/nav/mibs/juniper_dom_mib.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from nav.mibs.mibretriever import MibRetriever
from nav.models.manage import Sensor

COLUMNS = {
SENSOR_COLUMNS = {
"jnxDomCurrentRxLaserPower": {
"unit_of_measurement": Sensor.UNIT_DBM,
"precision": 2,
Expand Down Expand Up @@ -51,6 +51,97 @@
},
}

THRESHOLD_COLUMNS = {
"jnxDomCurrentRxLaserPower": {
"jnxDomCurrentRxLaserPowerHighAlarmThreshold": {
"name": "{ifc} RX Laser Power High Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentRxLaserPowerLowAlarmThreshold": {
"name": "{ifc} RX Laser Power Low Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentRxLaserPowerHighWarningThreshold": {
"name": "{ifc} RX Laser Power High Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
"jnxDomCurrentRxLaserPowerLowWarningThreshold": {
"name": "{ifc} RX Laser Power Low Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
},
"jnxDomCurrentTxLaserBiasCurrent": {
"jnxDomCurrentTxLaserBiasCurrentHighAlarmThreshold": {
"name": "{ifc} TX Laser Bias Current High Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentTxLaserBiasCurrentLowAlarmThreshold": {
"name": "{ifc} TX Laser Bias Current Low Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentTxLaserBiasCurrentHighWarningThreshold": {
"name": "{ifc} TX Laser Bias Current High Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
"jnxDomCurrentTxLaserBiasCurrentLowWarningThreshold": {
"name": "{ifc} TX Laser Bias Current Low Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
},
"jnxDomCurrentTxLaserOutputPower": {
"jnxDomCurrentTxLaserOutputPowerHighAlarmThreshold": {
"name": "{ifc} TX Laser Output Power High Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentTxLaserOutputPowerLowAlarmThreshold": {
"name": "{ifc} TX Laser Output Power Low Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentTxLaserOutputPowerHighWarningThreshold": {
"name": "{ifc} TX Laser Output Power High Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
"jnxDomCurrentTxLaserOutputPowerLowWarningThreshold": {
"name": "{ifc} TX Laser Output Power Low Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
},
"jnxDomCurrentModuleTemperature": {
"jnxDomCurrentModuleTemperatureHighAlarmThreshold": {
"name": "{ifc} Module Temperature High Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentModuleTemperatureLowAlarmThreshold": {
"name": "{ifc} Module Temperature Low Alarm Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_ALERT,
},
"jnxDomCurrentModuleTemperatureHighWarningThreshold": {
"name": "{ifc} Module Temperature High Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_HIGH,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
"jnxDomCurrentModuleTemperatureLowWarningThreshold": {
"name": "{ifc} Module Temperature Low Warning Threshold",
"threshold_type": Sensor.THRESHOLD_TYPE_LOW,
"threshold_alert_type": Sensor.ALERT_TYPE_WARNING,
},
},
}


class JuniperDomMib(MibRetriever):
"""MibRetriever for Juniper DOM Sensors"""
Expand All @@ -63,12 +154,21 @@ def get_all_sensors(self):
device.
"""
sensors = []
for column, config in COLUMNS.items():
sensors += yield self.handle_column(column, config)
for sensor_column, sensor_config in SENSOR_COLUMNS.items():
sensors += yield self.handle_sensor_column(sensor_column, sensor_config)
for threshold_column, threshold_config in THRESHOLD_COLUMNS[
sensor_column
].items():
sensors += yield self.handle_threshold_column(
threshold_column,
threshold_config,
sensor_column,
sensor_config,
)
returnValue(sensors)

@defer.inlineCallbacks
def handle_column(self, column, config):
def handle_sensor_column(self, column, config):
"""Returns the sensors of the given type"""
result = []
value_oid = self.nodes[column].oid
Expand All @@ -84,3 +184,28 @@ def handle_column(self, column, config):
sensor.update(config)
result.append(sensor)
returnValue(result)

@defer.inlineCallbacks
def handle_threshold_column(
self, column, config, related_sensor_column, related_sensor_config
):
"""Returns the sensor thresholds of the given type"""
result = []
value_oid = self.nodes[column].oid
related_sensor_oid = self.nodes[related_sensor_column].oid
rows = yield self.retrieve_column(column)
for row in rows:
threshold_sensor = dict(
oid=str(value_oid + row),
scale=None,
mib=self.get_module_name(),
description=config['name'],
internal_name="{ifc}." + column,
ifindex=row[-1],
unit_of_measurement=related_sensor_config['unit_of_measurement'],
precision=related_sensor_config['precision'],
threshold_for_oid=str(related_sensor_oid + row),
)
threshold_sensor.update(config)
result.append(threshold_sensor)
returnValue(result)
37 changes: 37 additions & 0 deletions python/nav/models/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2331,6 +2331,13 @@ class Sensor(models.Model):
(ALERT_TYPE_WARNING, 'An orange warning'),
)

THRESHOLD_TYPE_HIGH = 1
THRESHOLD_TYPE_LOW = 2
THRESHOLD_TYPE_CHOICES = (
(THRESHOLD_TYPE_HIGH, 'Threshold for high values'),
(THRESHOLD_TYPE_LOW, 'Threshold for low values'),
)

id = models.AutoField(db_column='sensorid', primary_key=True)
netbox = models.ForeignKey(Netbox, on_delete=models.CASCADE, db_column='netboxid')
interface = models.ForeignKey(
Expand Down Expand Up @@ -2365,6 +2372,13 @@ class Sensor(models.Model):
alert_type = models.IntegerField(
db_column='alert_type', choices=ALERT_TYPE_CHOICES, null=True
)
threshold_type = models.IntegerField(
db_column='threshold_type', choices=THRESHOLD_TYPE_CHOICES, null=True
)
threshold_alert_type = models.IntegerField(
db_column='threshold_alert_type', choices=ALERT_TYPE_CHOICES, null=True
Comment on lines +2378 to +2379
Copy link
Contributor Author

@stveit stveit Feb 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuses pre-existing alert types. Figured this could give some consistency, as the already existing "Warning" and "Alert" match quite well with the "Warning" and "Alarm" naming scheme from the juniper thresholds.

)
threshold_for_oid = VarcharField(db_column='threshold_for_oid', null=True)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would make sense to be a ForeignKey to the Sensor object this is a threshold for, but it didnt seem very easy to do. The values for the sensor object that is to be created are set after discovery, but before any objects are actually made, so refering to a sensor object that doesnt exist yet seems difficult. But pairing this threshold_for_oid field with a property function threshold_for that gives the actual sensor seemed like the next best thing.


class Meta(object):
db_table = 'sensor'
Expand Down Expand Up @@ -2484,6 +2498,29 @@ def get_display_configuration(self):
}
return {}

@property
def threshold_for(self):
"""Returns the sensor this is a threshold for.
Returns None if no such sensor exists.
"""
if not self.threshold_for_oid:
return None
try:
return self.__class__.objects.get(
netbox=self.netbox, oid=self.threshold_for_oid, mib=self.mib
)
except self.DoesNotExist:
_logger.error("Could not find sensor with oid %s", self.threshold_for_oid)
return None

@property
def thresholds(self):
"""Returns list of all threshold-sensors for this sensor"""
thresholds = self.__class__.objects.filter(
netbox=self.netbox, threshold_for_oid=self.oid, mib=self.mib
)
return list(thresholds)


class PowerSupplyOrFan(models.Model):
STATE_UP = u'y'
Expand Down
5 changes: 5 additions & 0 deletions python/nav/models/sql/changes/sc.05.05.0002.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE sensor
ADD threshold_type INT,
ADD threshold_alert_type INT,
ADD threshold_for_oid VARCHAR
;
47 changes: 47 additions & 0 deletions tests/unittests/mibs/juniper_dom_mib_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from unittest import TestCase
from mock import patch, Mock

from twisted.internet import defer
from twisted.internet.defer import succeed

from nav.mibs.juniper_dom_mib import JuniperDomMib, SENSOR_COLUMNS, THRESHOLD_COLUMNS


class TestJuniperDomMIB(TestCase):
def setUp(self):
pass

def tearDown(self):
pass

def test_handle_sensor_column_returns_correct_amount_of_sensor_dicts(self):
rows_for_column = {"0": "interface 0", "1": "interface 1"}

with patch(
'nav.mibs.juniper_dom_mib.JuniperDomMib.retrieve_column'
) as retrieve:
retrieve.return_value = succeed(rows_for_column)
mib = JuniperDomMib(Mock())
column = "jnxDomCurrentRxLaserPower"
deferred_result = mib.handle_sensor_column(column, SENSOR_COLUMNS[column])
result = deferred_result.result
self.assertEqual(len(result), len(rows_for_column))

def test_handle_threshold_column_returns_correct_amount_of_sensor_dicts(self):
rows_for_column = {"0": "interface 0", "1": "interface 1"}

with patch(
'nav.mibs.juniper_dom_mib.JuniperDomMib.retrieve_column'
) as retrieve:
retrieve.return_value = succeed(rows_for_column)
mib = JuniperDomMib(Mock())
threshold_column = "jnxDomCurrentRxLaserPowerHighAlarmThreshold"
sensor_column = "jnxDomCurrentRxLaserPower"
deferred_result = mib.handle_threshold_column(
threshold_column,
THRESHOLD_COLUMNS[sensor_column][threshold_column],
sensor_column,
SENSOR_COLUMNS[sensor_column],
)
result = deferred_result.result
self.assertEqual(len(result), len(rows_for_column), result)