mirror of
https://github.com/stylersnico/librenms.git
synced 2026-07-24 16:23:09 +02:00
Merge pull request #3102 from Rosiak/state-monitoring
Proper State Monitoring
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# Sensor State Support
|
||||
|
||||
### Introduction
|
||||
|
||||
In this section we are briefly going to walk through, what it takes to write sensor state support.
|
||||
We will also briefly get around the concepts of the current sensor state monitoring.
|
||||
|
||||
### Logic
|
||||
|
||||
For sensor state monitoring, we have 4 DB tables we need to concentrate about.
|
||||
- sensors
|
||||
- state_indexes
|
||||
- state_translations
|
||||
- sensors_to_state_indexes
|
||||
|
||||
We will just briefly tie a comment to each one of them.
|
||||
|
||||
#### sensors
|
||||
|
||||
*Each time a sensor needs to be polled, the system needs to know which sensor is it that it need to poll, at what oid is this sensor located and what class the sensor is etc.
|
||||
This information is fetched from the sensors table.*
|
||||
|
||||
#### state_indexes
|
||||
|
||||
*Is where we keep track of which state sensors we monitor.*
|
||||
|
||||
#### state_translations
|
||||
|
||||
*Is where we map the possible returned state sensor values to a generic LibreNMS value, in order to make displaying and alerting more generic.
|
||||
We also map these values to the actual state sensor(state_index) where these values are actually returned from.*
|
||||
|
||||
|
||||
*The LibreNMS generic states is derived from Nagios:*
|
||||
|
||||
```
|
||||
0 = OK
|
||||
|
||||
1 = Warning
|
||||
|
||||
2 = Critical
|
||||
|
||||
3 = Unknown
|
||||
```
|
||||
|
||||
#### sensors_to_state_indexes
|
||||
|
||||
*Is as you might have guessed, where the sensor_id is mapped to a state_index_id.*
|
||||
|
||||
### Example
|
||||
This example will be based on a Cisco power supply sensor and is all it takes to have sensor state support for Cisco power supplys in Cisco switches.
|
||||
The file should be located in /includes/discovery/sensors/state/cisco.inc.php.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
if ($device['os_group'] == 'cisco') {
|
||||
$temp = snmpwalk_cache_multi_oid($device, 'ciscoEnvMonSupplyStatusTable', array(), 'CISCO-ENVMON-MIB');
|
||||
$cur_oid = '.1.3.6.1.4.1.9.9.13.1.5.1.3.';
|
||||
|
||||
if (is_array($temp)) {
|
||||
|
||||
//Create State Index
|
||||
$state_name = 'ciscoEnvMonSupplyState';
|
||||
$state_index_id = create_state_index($state_name);
|
||||
|
||||
//Create State Translation
|
||||
if ($state_index_id) {
|
||||
$states = array(
|
||||
array($state_index_id,'normal',0,1,0) ,
|
||||
array($state_index_id,'warning',0,2,1) ,
|
||||
array($state_index_id,'critical',0,3,2) ,
|
||||
array($state_index_id,'shutdown',0,4,3) ,
|
||||
array($state_index_id,'notPresent',0,5,3) ,
|
||||
array($state_index_id,'notFunctioning',0,6,2)
|
||||
);
|
||||
foreach($states as $value){
|
||||
$insert = array(
|
||||
'state_index_id' => $value[0],
|
||||
'state_descr' => $value[1],
|
||||
'state_draw_graph' => $value[2],
|
||||
'state_value' => $value[3],
|
||||
'state_generic_value' => $value[4]
|
||||
);
|
||||
dbInsert($insert, 'state_translations');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($temp as $index => $entry) {
|
||||
//Discover Sensors
|
||||
discover_sensor($valid['sensor'], 'state', $device, $cur_oid.$index, $index, $state_name, $temp[$index]['ciscoEnvMonSupplyStatusDescr'], '1', '1', null, null, null, null, $temp[$index]['ciscoEnvMonSupplyState'], 'snmp', $index);
|
||||
|
||||
//Create Sensor To State Index
|
||||
create_sensor_to_state_index($device, $state_name, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
$sensors = dbFetchRows('SELECT * FROM `sensors` WHERE `sensor_class` = ? AND device_id = ? ORDER BY `poller_type`, `sensor_oid`, `sensor_index`', array($sensor_class, $device['device_id']));
|
||||
|
||||
if ($sensor_class == 'state') {
|
||||
$sensors = dbFetchRows('SELECT * FROM `sensors` LEFT JOIN `sensors_to_state_indexes` ON sensors_to_state_indexes.sensor_id = sensors.sensor_id LEFT JOIN state_indexes ON state_indexes.state_index_id = sensors_to_state_indexes.state_index_id WHERE `sensor_class` = ? AND device_id = ? ORDER BY `poller_type`, `sensor_oid`, `sensor_index`', array($sensor_class, $device['device_id']));
|
||||
}
|
||||
|
||||
if (count($sensors)) {
|
||||
echo '<div class="container-fluid ">
|
||||
<div class="row">
|
||||
@@ -12,6 +16,11 @@ if (count($sensors)) {
|
||||
echo ' </div>
|
||||
<table class="table table-hover table-condensed table-striped">';
|
||||
foreach ($sensors as $sensor) {
|
||||
$state_translation = array();
|
||||
if (!empty($sensor['state_index_id'])) {
|
||||
$state_translation = dbFetchRows('SELECT * FROM `state_translations` WHERE `state_index_id` = ? AND `state_value` = ? ', array($sensor['state_index_id'], $sensor['sensor_current']));
|
||||
}
|
||||
|
||||
if (!isset($sensor['sensor_current'])) {
|
||||
$sensor['sensor_current'] = 'NaN';
|
||||
}
|
||||
@@ -51,12 +60,36 @@ if (count($sensors)) {
|
||||
$sensor_minigraph = generate_lazy_graph_tag($graph_array);
|
||||
|
||||
$sensor['sensor_descr'] = truncate($sensor['sensor_descr'], 48, '');
|
||||
|
||||
echo '<tr>
|
||||
<td>'.overlib_link($link, shorten_interface_type($sensor['sensor_descr']), $overlib_content).'</td>
|
||||
<td>'.overlib_link($link, $sensor_minigraph, $overlib_content).'</td>
|
||||
<td>'.overlib_link($link, '<span '.($sensor['sensor_current'] < $sensor['sensor_limit_low'] || $sensor['sensor_current'] > $sensor['sensor_limit'] ? "style='color: red'" : '').'>'.$sensor['sensor_current'].$sensor_unit.'</span>', $overlib_content).'</td>
|
||||
</tr>';
|
||||
if (!empty($state_translation['0']['state_descr'])) {
|
||||
$state_style="";
|
||||
switch ($state_translation['state_generic_value']) {
|
||||
case 0: // OK
|
||||
$state_style="class='label label-success'";
|
||||
break;
|
||||
case 1: // Warning
|
||||
$state_style="class='label label-warning'";
|
||||
break;
|
||||
case 2: // Critical
|
||||
$state_style="class='label label-danger'";
|
||||
break;
|
||||
case 3: // Unknown
|
||||
default:
|
||||
$state_style="class='label label-default'";
|
||||
break;
|
||||
}
|
||||
echo '<tr>
|
||||
<td>'.overlib_link($link, shorten_interface_type($sensor['sensor_descr']), $overlib_content, $sensor_class).'</td>
|
||||
<td>'.overlib_link($link, $sensor_minigraph, $overlib_content, $sensor_class).'</td>
|
||||
<td>'.overlib_link($link, '<span '.$state_style.'>'.$state_translation['0']['state_descr'].'</span>', $overlib_content, $sensor_class).'</td>
|
||||
</tr>';
|
||||
}
|
||||
else {
|
||||
echo '<tr>
|
||||
<td>'.overlib_link($link, shorten_interface_type($sensor['sensor_descr']), $overlib_content, $sensor_class).'</td>
|
||||
<td>'.overlib_link($link, $sensor_minigraph, $overlib_content, $sensor_class).'</td>
|
||||
<td>'.overlib_link($link, '<span '.($sensor['sensor_current'] < $sensor['sensor_limit_low'] || $sensor['sensor_current'] > $sensor['sensor_limit'] ? "style='color: red'" : '').'>'.$sensor['sensor_current'].$sensor_unit.'</span>', $overlib_content, $sensor_class).'</td>
|
||||
</tr>';
|
||||
}
|
||||
}//end foreach
|
||||
|
||||
echo '</table>';
|
||||
|
||||
@@ -11,6 +11,7 @@ if ($used_sensors['current']) $datas[] = 'current';
|
||||
if ($used_sensors['power']) $datas[] = 'power';
|
||||
if ($used_sensors['dbm']) $datas[] = 'dbm';
|
||||
if ($used_sensors['load']) $datas[] = 'load';
|
||||
if ($used_sensors['state']) $datas[] = 'state';
|
||||
|
||||
// FIXME generalize -> static-config ?
|
||||
$type_text['overview'] = "Overview";
|
||||
@@ -29,6 +30,7 @@ $type_text['power'] = "Power";
|
||||
$type_text['toner'] = "Toner";
|
||||
$type_text['dbm'] = "dBm";
|
||||
$type_text['load'] = "Load";
|
||||
$type_text['state'] = "State";
|
||||
|
||||
if (!$vars['metric']) {
|
||||
$vars['metric'] = "processor";
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
$graph_type = 'sensor_state';
|
||||
$unit = '';
|
||||
$class = 'state';
|
||||
|
||||
require 'pages/health/sensors.inc.php';
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/*
|
||||
* LibreNMS
|
||||
*
|
||||
* Copyright (c) 2016 Søren Friis Rosiak <sorenrosiak@gmail.com>
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version. Please see LICENSE.txt at the top level of
|
||||
* the source code distribution for details.
|
||||
*/
|
||||
|
||||
if ($device['os_group'] == 'cisco') {
|
||||
|
||||
$tables = array(
|
||||
array('ciscoEnvMonVoltageStatusTable','.1.3.6.1.4.1.9.9.13.1.2.1.7.','ciscoEnvMonVoltageState','ciscoEnvMonVoltageStatusDescr') ,
|
||||
array('ciscoEnvMonTemperatureStatusTable','.1.3.6.1.4.1.9.9.13.1.3.1.6.','ciscoEnvMonTemperatureState','ciscoEnvMonTemperatureStatusDescr') ,
|
||||
array('ciscoEnvMonFanStatusTable','.1.3.6.1.4.1.9.9.13.1.4.1.3.','ciscoEnvMonFanState','ciscoEnvMonFanStatusDescr') ,
|
||||
array('ciscoEnvMonSupplyStatusTable','.1.3.6.1.4.1.9.9.13.1.5.1.3.','ciscoEnvMonSupplyState','ciscoEnvMonSupplyStatusDescr')
|
||||
);
|
||||
|
||||
foreach($tables as $tablevalue){
|
||||
$temp = snmpwalk_cache_multi_oid($device, $tablevalue[0], array(), 'CISCO-ENVMON-MIB');
|
||||
$cur_oid = $tablevalue[1];
|
||||
|
||||
if (is_array($temp)) {
|
||||
//Create State Index
|
||||
$state_name = $tablevalue[2];
|
||||
$state_index_id = create_state_index($state_name);
|
||||
|
||||
//Create State Translation
|
||||
if ($state_index_id !== null) {
|
||||
$states = array(
|
||||
array($state_index_id,'normal',0,1,0) ,
|
||||
array($state_index_id,'warning',0,2,1) ,
|
||||
array($state_index_id,'critical',0,3,2) ,
|
||||
array($state_index_id,'shutdown',0,4,3) ,
|
||||
array($state_index_id,'notPresent',0,5,3) ,
|
||||
array($state_index_id,'notFunctioning',0,6,2)
|
||||
);
|
||||
foreach($states as $value){
|
||||
$insert = array(
|
||||
'state_index_id' => $value[0],
|
||||
'state_descr' => $value[1],
|
||||
'state_draw_graph' => $value[2],
|
||||
'state_value' => $value[3],
|
||||
'state_generic_value' => $value[4]
|
||||
);
|
||||
dbInsert($insert, 'state_translations');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($temp as $index => $entry) {
|
||||
//Discover Sensors
|
||||
$descr = ucwords($temp[$index][$tablevalue[3]]);
|
||||
discover_sensor($valid['sensor'], 'state', $device, $cur_oid.$index, $index, $state_name, $descr, '1', '1', null, null, null, null, $temp[$index][$tablevalue[2]], 'snmp', $index);
|
||||
|
||||
//Create Sensor To State Index
|
||||
create_sensor_to_state_index($device, $state_name, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1446,3 +1446,36 @@ function rrdtest($path, &$stdOutput, &$stdError) {
|
||||
proc_close($process);
|
||||
return $status['exitcode'];
|
||||
}
|
||||
|
||||
function create_state_index($state_name) {
|
||||
if (dbFetchRow('SELECT * FROM state_indexes WHERE state_name = ?', array($state_name)) === false) {
|
||||
$insert = array('state_name' => $state_name);
|
||||
return dbInsert($insert, 'state_indexes');
|
||||
}
|
||||
}
|
||||
|
||||
function create_sensor_to_state_index($device, $state_name, $index)
|
||||
{
|
||||
$sensor_entry = dbFetchRow('SELECT sensor_id FROM `sensors` WHERE `sensor_class` = ? AND `device_id` = ? AND `sensor_type` = ? AND `sensor_index` = ?', array(
|
||||
'state',
|
||||
$device['device_id'],
|
||||
$state_name,
|
||||
$index
|
||||
));
|
||||
$state_indexes_entry = dbFetchRow('SELECT state_index_id FROM `state_indexes` WHERE `state_name` = ?', array(
|
||||
$state_name
|
||||
));
|
||||
if (!empty($sensor_entry['sensor_id']) && !empty($state_indexes_entry['state_index_id'])) {
|
||||
$insert = array(
|
||||
'sensor_id' => $sensor_entry['sensor_id'],
|
||||
'state_index_id' => $state_indexes_entry['state_index_id'],
|
||||
);
|
||||
foreach($insert as $key => $val_check) {
|
||||
if (!isset($val_check)) {
|
||||
unset($insert[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
dbInsert($insert, 'sensors_to_state_indexes');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,11 @@ function poll_sensor($device, $class, $unit) {
|
||||
log_event(ucfirst($class).' '.$sensor['sensor_descr'].' above threshold: '.$sensor_value." $unit (> ".$sensor['sensor_limit']." $unit)", $device, $class, $sensor['sensor_id']);
|
||||
}
|
||||
|
||||
dbUpdate(array('sensor_current' => $sensor_value, 'lastupdate' => array('NOW()')), 'sensors', '`sensor_class` = ? AND `sensor_id` = ?', array($class, $sensor['sensor_id']));
|
||||
if ($sensor['sensor_class'] == 'state' && $sensor['sensor_current'] != $sensor_value) {
|
||||
log_event($class . ' sensor has changed from ' . $sensor['sensor_current'] . ' to ' . $sensor_value, $device, $class, $sensor['sensor_id']);
|
||||
}
|
||||
|
||||
dbUpdate(array('sensor_current' => $sensor_value, 'sensor_prev' => $sensor['sensor_current'], 'lastupdate' => array('NOW()')), 'sensors', '`sensor_class` = ? AND `sensor_id` = ?', array($class,$sensor['sensor_id']));
|
||||
}//end foreach
|
||||
|
||||
}//end poll_sensor()
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS `state_indexes` ( `state_index_id` int(11) NOT NULL AUTO_INCREMENT, `state_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`state_index_id`), UNIQUE KEY `state_name` (`state_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
|
||||
CREATE TABLE IF NOT EXISTS `state_translations` ( `state_translation_id` int(11) NOT NULL AUTO_INCREMENT, `state_index_id` int(11) NOT NULL, `state_descr` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `state_draw_graph` tinyint(1) NOT NULL, `state_value` tinyint(1) NOT NULL, `state_generic_value` tinyint(1) NOT NULL, `state_lastupdated` timestamp NOT NULL, PRIMARY KEY (`state_translation_id`), UNIQUE KEY `state_index_id_value` (`state_index_id`,`state_value`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
|
||||
CREATE TABLE IF NOT EXISTS `sensors_to_state_indexes` ( `sensors_to_state_translations_id` int(11) NOT NULL AUTO_INCREMENT, `sensor_id` int(11) NOT NULL, `state_index_id` int(11) NOT NULL, PRIMARY KEY (`sensors_to_state_translations_id`), UNIQUE KEY `sensor_id_state_index_id` (`sensor_id`,`state_index_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
|
||||
ALTER TABLE `sensors_to_state_indexes` ADD FOREIGN KEY (`sensor_id`) REFERENCES `sensors`(`sensor_id`) ON DELETE RESTRICT ON UPDATE RESTRICT;
|
||||
ALTER TABLE `sensors_to_state_indexes` ADD FOREIGN KEY (`state_index_id`) REFERENCES `state_indexes`(`state_index_id`) ON DELETE RESTRICT ON UPDATE RESTRICT;
|
||||
ALTER TABLE `sensors` ADD `sensor_prev` float default NULL;
|
||||
Reference in New Issue
Block a user