mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Merge pull request #3821 from adaniels21487/issue-3272-1
Component Update - Status
This commit is contained in:
@ -23,7 +23,7 @@ Table of Content:
|
||||
The Component extension provides a generic database storage mechanism for discovery and poller modules.
|
||||
The Driver behind this extension was to provide the features of ports, in a generic manner to discovery/poller modules.
|
||||
|
||||
It provides a status (Normal or Alert), the ability to Disable (do not poll), or Ignore (do not Alert).
|
||||
It provides a status (Nagios convention), the ability to Disable (do not poll), or Ignore (do not Alert).
|
||||
|
||||
# <a name="database">Database Structure</a>
|
||||
|
||||
@ -282,18 +282,23 @@ Please see the [API-Docs](http://docs.librenms.org/API/API-Docs/#api-route-25) f
|
||||
## <a name="alert">Alerting</a>
|
||||
|
||||
It is intended that discovery/poller modules will detect the status of a component during the polling cycle.
|
||||
If you are creating a poller module which can detect a fault condition simply set STATUS to 0 and ERROR to a message that indicates the problem.
|
||||
Status is logged using the Nagios convention for status codes, where:
|
||||
0 = Ok,
|
||||
1 = Warning,
|
||||
2 = Critical
|
||||
|
||||
If you are creating a poller module which can detect a fault condition simply set STATUS to something other than 0 and ERROR to a message that indicates the problem.
|
||||
|
||||
To actually raise an alert, the user will need to create an alert rule. To assist with this several Alerting Macro's have been created:
|
||||
|
||||
- ```%macro.component_alert``` - A component that is not disabled or ignored and in alert state.
|
||||
- ```%macro.component_normal``` - A component that is not disabled or ignored and NOT in alert state.
|
||||
- ```%macro.component_normal``` - A component that is not disabled or ignored and in a Normal state.
|
||||
- ```%macro.component_warning``` - A component that is not disabled or ignored and NOT in a Warning state.
|
||||
- ```%macro.component_critical``` - A component that is not disabled or ignored and NOT in a Critical state.
|
||||
|
||||
To raise alerts for components, the following rules could be created:
|
||||
|
||||
- ```%macros.component_alert = "1"``` - To alert on all components
|
||||
- ```%macros.component_alert = "1" && %component.type = "<Type of Component>"``` - To alert on all components of a particular type.
|
||||
- ```%macros.component_critical = "1"``` - To alert on all Critical components
|
||||
- ```%macros.component_critical = "1" && %component.type = "<Type of Component>"``` - To alert on all Critical components of a particular type.
|
||||
|
||||
If there is a particular component you would like excluded from alerting, simply set the ignore field to 1.
|
||||
|
||||
|
41
html/includes/common/component-status.inc.php
Normal file
41
html/includes/common/component-status.inc.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
require_once "../includes/component.php";
|
||||
$OBJCOMP = new component();
|
||||
|
||||
$common_output[] = '
|
||||
<div>
|
||||
<table id="component-status" class="table table-hover table-condensed table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="status" data-order="desc">Status</th>
|
||||
<th data-column-id="count">Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
';
|
||||
foreach ($OBJCOMP->getComponentStatus() as $k => $v) {
|
||||
if ($k == 0) {
|
||||
$status = 'Ok';
|
||||
$color = 'green';
|
||||
}
|
||||
elseif ($k == 1) {
|
||||
$status = 'Warning';
|
||||
$color = 'grey';
|
||||
}
|
||||
else {
|
||||
$status = 'Critical';
|
||||
$color = 'red';
|
||||
}
|
||||
$common_output[] .= '
|
||||
<tr>
|
||||
<td><p class="text-left '.$color.'">'.$status.'</p></td>
|
||||
<td><p class="text-left '.$color.'">'.$v.'</p></td>
|
||||
</tr>
|
||||
';
|
||||
}
|
||||
$common_output[] .= '
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
';
|
@ -34,17 +34,30 @@ $COMPONENTS = $OBJCOMP->getComponents($device_id,$options);
|
||||
$response[] = array(
|
||||
'id' => '<button type="submit" id="save-form" class="btn btn-success btn-sm" title="Save current component disable/ignore settings">Save</button><button type="submit" id="form-reset" class="btn btn-danger btn-sm" title="Reset form to when the page was loaded">Reset</button>',
|
||||
'label' => ' ',
|
||||
'status' => '<button type="submit" id="alert-select" class="btn btn-default btn-sm" title="Disable alerting on all currently-alerting components">Alerting</button>',
|
||||
'status' => '<button type="submit" id="warning-select" class="btn btn-default btn-sm" title="Disable alerting on all currently warning components">Warning</button> <button type="submit" id="critical-select" class="btn btn-default btn-sm" title="Disable alerting on all currently critical components">Critical</button>',
|
||||
'disable' => '<button type="submit" id="disable-toggle" class="btn btn-default btn-sm" title="Toggle polling for all components">Toggle</button><button type="button" id="disable-select" class="btn btn-default btn-sm" title="Disable polling on all components">Select All</button>',
|
||||
'ignore' => '<button type="submit" id="ignore-toggle" class="btn btn-default btn-sm" title="Toggle alerting for all components">Toggle</button><button type="button" id="ignore-select" class="btn btn-default btn-sm" title="Disable alerting on all components">Select All</button>',
|
||||
);
|
||||
|
||||
foreach ($COMPONENTS[$device_id] as $ID => $AVP) {
|
||||
if ($AVP['status'] == 0) {
|
||||
$class = "green";
|
||||
$status = "Ok";
|
||||
}
|
||||
elseif ($AVP['status'] == 1) {
|
||||
$class = "grey";
|
||||
$status = "Warning";
|
||||
}
|
||||
else {
|
||||
// Critical
|
||||
$class = "red";
|
||||
$status = "Critical";
|
||||
}
|
||||
$response[] = array(
|
||||
'id' => $ID,
|
||||
'type' => $AVP['type'],
|
||||
'label' => $AVP['label'],
|
||||
'status' => ($AVP['status'] ? "<span name='status_".$ID."' class='green'>Normal</span>" : "<span name='status_".$ID."' class='red'>Alert</span>"),
|
||||
'status' => "<span name='status_".$ID."' class='".$class."'>".$status."</span>",
|
||||
'disable' => '<input type="checkbox" class="disable-check" name="dis_'.$ID.'"'.($AVP['disabled'] ? 'checked' : '').'>',
|
||||
'ignore' => '<input type="checkbox" class="ignore-check" name="ign_'.$ID.'"'.($AVP['ignore'] ? 'checked' : '').'>',
|
||||
);
|
||||
|
@ -44,13 +44,27 @@
|
||||
event.preventDefault();
|
||||
$('.ignore-check').prop('checked', true);
|
||||
});
|
||||
$('#alert-select').click(function (event) {
|
||||
// select ignore buttons for all ports which are down
|
||||
$('#warning-select').click(function (event) {
|
||||
// select ignore button for all components that are in a warning state.
|
||||
event.preventDefault();
|
||||
$('[name^="status_"]').each(function () {
|
||||
var name = $(this).attr('name');
|
||||
var text = $(this).text();
|
||||
if (name && text == 'Alert') {
|
||||
if (name && text == 'Warning') {
|
||||
// get the component number from the object name
|
||||
var id = name.split('_')[1];
|
||||
// find its corresponding checkbox and toggle it
|
||||
$('input[name="ign_' + id + '"]').trigger('click');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#critical-select').click(function (event) {
|
||||
// select ignore button for all components that are in a critical state.
|
||||
event.preventDefault();
|
||||
$('[name^="status_"]').each(function () {
|
||||
var name = $(this).attr('name');
|
||||
var text = $(this).text();
|
||||
if (name && text == 'Critical') {
|
||||
// get the component number from the object name
|
||||
var id = name.split('_')[1];
|
||||
// find its corresponding checkbox and toggle it
|
||||
|
@ -19,7 +19,7 @@ global $config;
|
||||
// Loop over each component, pulling out the Overlays.
|
||||
foreach ($components as $oid => $overlay) {
|
||||
if ($overlay['otvtype'] == 'overlay') {
|
||||
if ($overlay['status'] == 1) {
|
||||
if ($overlay['status'] == 0) {
|
||||
$overlay_status = "<span class='green pull-right'>Normal</span>";
|
||||
$gli = "";
|
||||
}
|
||||
@ -33,7 +33,7 @@ foreach ($components as $oid => $overlay) {
|
||||
<?php
|
||||
foreach ($components as $aid => $adjacency) {
|
||||
if (($adjacency['otvtype'] == 'adjacency') && ($adjacency['index'] == $overlay['index'])) {
|
||||
if ($adjacency['status'] == 1) {
|
||||
if ($adjacency['status'] == 0) {
|
||||
$adj_status = "<span class='green pull-right'>Normal</span>";
|
||||
$gli = "";
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ foreach ($COMPONENTS as $DEVICE_ID => $COMP) {
|
||||
// Loop over each component, pulling out the Overlays.
|
||||
foreach ($COMP as $OID => $OVERLAY) {
|
||||
if ($OVERLAY['otvtype'] == 'overlay') {
|
||||
if ($OVERLAY['status'] == 1) {
|
||||
if ($OVERLAY['status'] == 0) {
|
||||
$OVERLAY_STATUS = "<span class='green pull-right'>Normal</span>";
|
||||
$GLI = "";
|
||||
}
|
||||
@ -33,7 +33,7 @@ foreach ($COMPONENTS as $DEVICE_ID => $COMP) {
|
||||
<?php
|
||||
foreach ($COMP as $AID => $ADJACENCY) {
|
||||
if (($ADJACENCY['otvtype'] == 'adjacency') && ($ADJACENCY['index'] == $OVERLAY['index'])) {
|
||||
if ($ADJACENCY['status'] == 1) {
|
||||
if ($ADJACENCY['status'] == 0) {
|
||||
$ADJ_STATUS = "<span class='green pull-right'>Normal</span>";
|
||||
$GLI = "";
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class component {
|
||||
private $reserved = array(
|
||||
'type' => '',
|
||||
'label' => '',
|
||||
'status' => 1,
|
||||
'status' => 0,
|
||||
'ignore' => 0,
|
||||
'disabled' => 0,
|
||||
'error' => '',
|
||||
@ -148,6 +148,69 @@ class component {
|
||||
return $RESULT;
|
||||
}
|
||||
|
||||
public function getComponentStatus($device=null) {
|
||||
$sql_query = "SELECT status, count(status) as count FROM component WHERE";
|
||||
$sql_param = array();
|
||||
$add = 0;
|
||||
|
||||
if (!is_null($device)) {
|
||||
// Add a device filter to the SQL query.
|
||||
$sql_query .= " `device_id` = ?";
|
||||
$sql_param[] = $device;
|
||||
$add++;
|
||||
}
|
||||
|
||||
if ($add == 0) {
|
||||
// No filters, remove " WHERE" -6
|
||||
$sql_query = substr($sql_query, 0, strlen($sql_query)-6);
|
||||
}
|
||||
$sql_query .= " GROUP BY status";
|
||||
d_echo("SQL Query: ".$sql_query);
|
||||
|
||||
// $service is not null, get only what we want.
|
||||
$result = dbFetchRows($sql_query, $sql_param);
|
||||
|
||||
// Set our defaults to 0
|
||||
$count = array(0 => 0, 1 => 0, 2 => 0);
|
||||
// Rebuild the array in a more convenient method
|
||||
foreach ($result as $v) {
|
||||
$count[$v['status']] = $v['count'];
|
||||
}
|
||||
|
||||
d_echo("Component Count by Status: ".print_r($count,TRUE)."\n");
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function getComponentStatusLog($component=null,$start=null,$end=null) {
|
||||
if ( ($component == null) || ($start == null) || ($end == null) ) {
|
||||
// Error...
|
||||
d_echo("Required arguments are missing. Component: ".$component.", Start: ".$start.", End: ".$end."\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create our return array.
|
||||
$return = array();
|
||||
|
||||
// 1. find the previous value, this is the value when $start occurred.
|
||||
$sql_query = "SELECT status FROM component_statuslog WHERE `component` = ? AND time < ? ORDER BY `id` desc LIMIT 1";
|
||||
$sql_param = array($component,$start);
|
||||
$result = dbFetchRow($sql_query, $sql_param);
|
||||
if ($result == false) {
|
||||
$return['initial'] = false;
|
||||
}
|
||||
else {
|
||||
$return['initial'] = $result['status'];
|
||||
}
|
||||
|
||||
// 2. Then we just need a list of all the entries for the time period.
|
||||
$sql_query = "SELECT status, time, message FROM component_statuslog WHERE `component` = ? AND time >= ? AND time < ? ORDER BY `time`";
|
||||
$sql_param = array($component,$start,$end);
|
||||
$return['data'] = dbFetchRows($sql_query, $sql_param);
|
||||
|
||||
d_echo("Status Log Data: ".print_r($return,TRUE)."\n");
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function createComponent ($device_id,$TYPE) {
|
||||
// Prepare our default values to be inserted.
|
||||
$DATA = $this->reserved;
|
||||
@ -159,6 +222,9 @@ class component {
|
||||
// Insert a new component into the database.
|
||||
$id = dbInsert($DATA, 'component');
|
||||
|
||||
// Add a default status log entry - we always start ok.
|
||||
$this->createStatusLogEntry($id,0,'Component Created');
|
||||
|
||||
// Create a default component array based on what was inserted.
|
||||
$ARRAY = array();
|
||||
$ARRAY[$id] = $DATA;
|
||||
@ -166,6 +232,17 @@ class component {
|
||||
return $ARRAY;
|
||||
}
|
||||
|
||||
public function createStatusLogEntry($component,$status,$message) {
|
||||
// Add an entry to the statuslog table for a particular component.
|
||||
$DATA = array(
|
||||
'component' => $component,
|
||||
'status' => $status,
|
||||
'message' => $message,
|
||||
);
|
||||
|
||||
return dbInsert($DATA, 'component_statuslog');
|
||||
}
|
||||
|
||||
public function deleteComponent ($id) {
|
||||
// Delete a component from the database.
|
||||
return dbDelete('component', "`id` = ?",array($id));
|
||||
@ -187,6 +264,12 @@ class component {
|
||||
// Ignore type, we cant change that.
|
||||
unset($AVP['type'],$OLD[$device_id][$COMPONENT]['type']);
|
||||
|
||||
// If the Status has changed we need to add a log entry
|
||||
if ($AVP['status'] != $OLD[$device_id][$COMPONENT]['status']) {
|
||||
d_echo("Status Changed - Old: ".$OLD[$device_id][$COMPONENT]['status'].", New: ".$AVP['status']."\n");
|
||||
$this->createStatusLogEntry($COMPONENT,$AVP['status'],$AVP['error']);
|
||||
}
|
||||
|
||||
// Process our reserved components first.
|
||||
$UPDATE = array();
|
||||
foreach ($this->reserved as $k => $v) {
|
||||
@ -239,7 +322,7 @@ class component {
|
||||
log_event("Component: ".$AVP[$COMPONENT]['type']."(".$COMPONENT."). Attribute: ".$ATTR.", was modified from: ".$OLD[$COMPONENT][$ATTR].", to: ".$VALUE,$device_id,'component',$COMPONENT);
|
||||
}
|
||||
|
||||
} // End Foreach COMPONENT
|
||||
} // End Foreach AVP
|
||||
|
||||
// Process our Deletes.
|
||||
$DELETE = array_diff_key($OLD[$device_id][$COMPONENT], $AVP);
|
||||
|
@ -116,11 +116,11 @@ if ($device['os_group'] == 'cisco') {
|
||||
// If we have set a message, we have an error, activate alert.
|
||||
if ($message !== false) {
|
||||
$result['error'] = $message;
|
||||
$result['status'] = 0;
|
||||
$result['status'] = 2;
|
||||
}
|
||||
else {
|
||||
$result['error'] = "";
|
||||
$result['status'] = 1;
|
||||
$result['status'] = 0;
|
||||
}
|
||||
|
||||
// Let's log some debugging
|
||||
@ -154,11 +154,11 @@ if ($device['os_group'] == 'cisco') {
|
||||
// If we have set a message, we have an error, activate alert.
|
||||
if ($message !== false) {
|
||||
$result['error'] = $message;
|
||||
$result['status'] = 0;
|
||||
$result['status'] = 1;
|
||||
}
|
||||
else {
|
||||
$result['error'] = "";
|
||||
$result['status'] = 1;
|
||||
$result['status'] = 0;
|
||||
}
|
||||
|
||||
// Set a default name, if for some unknown reason we cant find the parent VPN.
|
||||
|
@ -106,11 +106,11 @@ if ($device['os_group'] == "cisco") {
|
||||
// If we have set a message, we have an error, activate alert.
|
||||
if ($message !== false) {
|
||||
$array['error'] = $message;
|
||||
$array['status'] = 0;
|
||||
$array['status'] = 2;
|
||||
}
|
||||
else {
|
||||
$array['error'] = "";
|
||||
$array['status'] = 1;
|
||||
$array['status'] = 0;
|
||||
}
|
||||
|
||||
// Time to graph the count of the active VLAN's on this overlay.
|
||||
@ -154,11 +154,11 @@ if ($device['os_group'] == "cisco") {
|
||||
// If we have set a message, we have an error, activate alert.
|
||||
if ($message !== false) {
|
||||
$array['error'] = $message;
|
||||
$array['status'] = 0;
|
||||
$array['status'] = 1;
|
||||
}
|
||||
else {
|
||||
$array['error'] = "";
|
||||
$array['status'] = 1;
|
||||
$array['status'] = 0;
|
||||
}
|
||||
|
||||
// Let's log some debugging
|
||||
|
9
sql-schema/126.sql
Normal file
9
sql-schema/126.sql
Normal file
@ -0,0 +1,9 @@
|
||||
DROP TABLE IF EXISTS `component_statuslog`;
|
||||
CREATE TABLE `component_statuslog` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID for each log entry, unique index', `component_id` int(11) unsigned NOT NULL COMMENT 'id from the component table', `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'The status that the component was changed TO', `timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'When the status of the component was changed', PRIMARY KEY (`id`), KEY `device` (`component_id`), CONSTRAINT `component_statuslog_ibfk_1` FOREIGN KEY (`component_id`) REFERENCES `component` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='log of status changes to a component.';
|
||||
ALTER TABLE `component` CHANGE `status` `status` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'The status of the component, retreived from the device';
|
||||
UPDATE `config` SET `config_name`='alert.macros.rule.component_warning',`config_descr`='Component status Warning' WHERE `config_name`='alert.macros.rule.component_normal';
|
||||
UPDATE `config` SET `config_name`='alert.macros.rule.component_normal',`config_descr`='Component status Normal' WHERE `config_name`='alert.macros.rule.component_alert';
|
||||
INSERT INTO `config` (`config_name`,`config_value`,`config_default`,`config_descr`,`config_group`,`config_group_order`,`config_sub_group`,`config_sub_group_order`,`config_hidden`,`config_disabled`) VALUES ('alert.macros.rule.component_critical','(%component.status = 2 && %macros.component)','(%component.status = 2 && %macros.component)','Component status Critical','alerting',0,'macros',0,'1','0');
|
||||
UPDATE component SET status=2 WHERE status=0;
|
||||
UPDATE component SET status=0 WHERE status=1;
|
||||
INSERT INTO `widgets` (`widget_title`,`widget`,`base_dimensions`) VALUES ('Component Status','component-status','3,2');
|
Reference in New Issue
Block a user