Merge pull request #863 from f0o/alert_macros

Alerting-Update
This commit is contained in:
Neil Lathwood 2015-04-27 11:21:22 +01:00
commit bcf3c5c541
10 changed files with 213 additions and 21 deletions

View File

@ -208,7 +208,7 @@ function ExtTransports($obj) {
global $config;
$tmp = false; //To keep scrutinizer from naging because it doesnt understand eval
foreach( $config['alert']['transports'] as $transport=>$opts ) {
if( file_exists($config['install_dir']."/includes/alerts/transport.".$transport.".php") ) {
if( ($opts === true || !empty($opts)) && file_exists($config['install_dir']."/includes/alerts/transport.".$transport.".php") ) {
echo $transport." => ";
eval('$tmp = function($obj,$opts) { global $config; '.file_get_contents($config['install_dir']."/includes/alerts/transport.".$transport.".php").' };');
$tmp = $tmp($obj,$opts);
@ -292,7 +292,7 @@ function DescribeAlert($alert) {
$i++;
$obj['faults'][$i] = $incident;
foreach( $incident as $k=>$v ) {
if( !empty($v) && $k != 'device_id' && (stristr($k,'id') || stristr($k,'desc')) && substr_count($k,'_') <= 1 ) {
if( !empty($v) && $k != 'device_id' && (stristr($k,'id') || stristr($k,'desc') || stristr($k,'msg')) && substr_count($k,'_') <= 1 ) {
$obj['faults'][$i]['string'] .= $k.' => '.$v."; ";
}
}

View File

@ -22,6 +22,11 @@ Table of Content:
- [Ports](#entity-ports)
- [Processors](#entity-processors)
- [Storage](#entity-storage)
- [Macros](#macros)
- [Device](#macros-device)
- [Port](#macros-port)
- [Time](#macros-time)
# <a name="about">About</a>
@ -316,3 +321,109 @@ __processors.processor_descr__ = The description of the processor.
__storage.storage_descr__ = The description of the storage.
__storage.storage_perc__ = The usage of the storage as a percentage.
# <a name="macros">Macros</a>
Macros are shorthands to either portion of rules or pure SQL enhanced with placeholders.
You can define your own macros in your `config.php`.
Example macro-implementation of Debian-Devices
```php
$config['alert']['macros']['rule']['is_debian'] = '%devices.features ~ "@debian@"';
```
And in the Rule:
```
... && %macros.is_debian = "1" && ...
```
This Example-macro is a Boolean-macro, it applies a form of filter to the set of results defined by the rule.
All macros that are not unary should return Boolean.
You can only apply _Equal_ or _Not-Equal_ Operations on Bollean-macros where `True` is represented by `"1"` and `False` by `"0"`.
## <a name="macros-device">Device</a> (Boolean)
Entity: `%macros.device`
Description: Only select devices that aren't deleted, ignored or disabled.
Source: `(%devices.disabled = "0" && %devices.ignore = "0")`
### <a name="macros-device-up">Device is up</a> (Boolean)
Entity: `%macros.device_up`
Description: Only select devices that are up.
Implies: %macros.device
Source: `(%devices.status = "1" && %macros.device)`
### <a name="macros-device-down">Device is down</a> (Boolean)
Entity: `%macros.device_down`
Description: Only select devices that are down.
Implies: %macros.device
Source: `(%devices.status = "0" && %macros.device)`
## <a name="macros-port">Port</a> (Boolean)
Entity: `%macros.port`
Description: Only select ports that aren't deleted, ignored or disabled.
Source: `(%ports.deleted = "0" && %ports.ignore = "0" && %ports.disabled = "0")`
### <a name="macros-port-up">Port is up</a> (Boolean)
Entity: `%macros.port_up`
Description: Only select ports that are up and also should be up.
Implies: %macros.port
Source: `(%ports.ifOperStatus = "up" && %ports.ifAdminStatus = "up" && %macros.port)`
### <a name="macros-port-down">Port is down</a> (Boolean)
Entity: `%macros.port_down`
Description: Only select ports that are down.
Implies: %macros.port
Source: `(%ports.ifOperStatus = "down" && %ports.ifAdminStatus != "down" && %macros.port)`
### <a name="macros-port-usage-perc">Port-Usage in Percent</a> (Decimal)
Entity: `%macros.port_usage_perc`
Description: Return port-usage in percent.
Source: `((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100`
## <a name="macros-time">Time</a>
### <a name="macros-time-now">Now</a> (Datetime)
Entity: `%macros.now`
Description: Alias of MySQL's NOW()
Source: `NOW()`
### <a name="macros-time-past-Nm">Past N Minutes</a> (Datetime)
Entity: `%macros.past_$m`
Description: Returns a MySQL Timestamp dated `$` Minutes in the past. `$` can only be a supported Resolution.
Example: `%macros.past_5m` is Last 5 Minutes.
Resolution: 5,10,15,30,60
Source: `DATE_SUB(NOW(),INTERVAL $ MINUTE)`

View File

@ -67,10 +67,16 @@ if( isset($_GET['term'],$_GET['device_id']) ) {
$chk = $memcache->get('rule-suggest_'.$term[0]);
}
if( !(sizeof($chk) > 0) || $chk === false ) {
$tmp = dbFetchRows('SHOW COLUMNS FROM '.$term[0]);
foreach( $tmp as $tst ) {
if( isset($tst['Field']) ) {
$chk[] = $term[0].'.'.$tst['Field'];
if( $term[0] == "macros" ) {
foreach( $config['alert']['macros']['rule'] as $macro=>$v ) {
$chk[] = "macros.".$macro;
}
} else {
$tmp = dbFetchRows('SHOW COLUMNS FROM '.$term[0]);
foreach( $tmp as $tst ) {
if( isset($tst['Field']) ) {
$chk[] = $term[0].'.'.$tst['Field'];
}
}
}
}
@ -84,6 +90,7 @@ if( isset($_GET['term'],$_GET['device_id']) ) {
foreach( $tmp as $tst ) {
$chk[] = $tst['TABLE_NAME'].'.';
}
$chk[] = 'macros.';
}
}
if( sizeof($chk) > 0 ) {

View File

@ -21,6 +21,12 @@ if(!is_numeric($_POST['group_id'])) {
exit;
} else {
if(dbDelete('device_groups', "`id` = ?", array($_POST['group_id']))) {
if( dbFetchCell('SELECT COUNT(id) FROM alert_map WHERE target = ?',array('g'.$_POST['group_id'])) >= 1 ) {
foreach( dbFetchRows('SELECT id FROM alert_map WHERE target = ?',array('g'.$_POST['group_id'])) as $map ) {
$_POST['map_id'] = $map['id'];
include('forms/delete-alert-map.inc.php');
}
}
echo('group has been deleted.');
exit;
} else {

View File

@ -245,11 +245,13 @@ $('#and, #or').click('', function(e) {
strategy: 'array',
tagFieldName: 'rules[]'
});
if(entity.indexOf("%") >= 0) {
$('#response').data('tagmanager').populate([ entity+' '+condition+' '+value+' '+glue ]);
} else {
$('#response').data('tagmanager').populate([ '%'+entity+' '+condition+' "'+value+'" '+glue ]);
if(value.indexOf("%") < 0) {
value = '"'+value+'"';
}
if(entity.indexOf("%") < 0) {
entity = '%'+entity;
}
$('#response').data('tagmanager').populate([ entity+' '+condition+' '+value+' '+glue ]);
}
});

View File

@ -12,12 +12,12 @@ $no_refresh = TRUE;
<?php
if(isset($_POST['create-default'])) {
$default_rules[] = array('device_id' => '-1', 'rule' => '%devices.status != "1" && %devices.disabled = "0" && %devices.ignore = "0"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"-1","delay":"300"}', 'disabled' => 0, 'name' => 'Devices up/down');
$default_rules[] = array('device_id' => '-1', 'rule' => '%devices.uptime < "300" && %devices.disabled = "0" && %devices.ignore = "0"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"1","delay":"300"}', 'disabled' => 0, 'name' => 'Device rebooted');
$default_rules[] = array('device_id' => '-1', 'rule' => '%bgpPeers.bgpPeerState != "established"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"1","delay":"300"}', 'disabled' => 0, 'name' => 'BGP Session down');
$default_rules[] = array('device_id' => '-1', 'rule' => '%macros.device_down = "1"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"-1","delay":"300"}', 'disabled' => 0, 'name' => 'Devices up/down');
$default_rules[] = array('device_id' => '-1', 'rule' => '%devices.uptime < "300" && %macros.device = "1"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"1","delay":"300"}', 'disabled' => 0, 'name' => 'Device rebooted');
$default_rules[] = array('device_id' => '-1', 'rule' => '%bgpPeers.bgpPeerState != "established" && %macros.device_up = "1"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"1","delay":"300"}', 'disabled' => 0, 'name' => 'BGP Session down');
$default_rules[] = array('device_id' => '-1', 'rule' => '%bgpPeers.bgpPeerFsmEstablishedTime < "300" && %bgpPeers.bgpPeerState = "established"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"1","delay":"300"}', 'disabled' => 0, 'name' => 'BGP Session establised');
$default_rules[] = array('device_id' => '-1', 'rule' => '%ports.ifOperStatus != "up" && %ports.ifAdminStatus = "up" && %ports.deleted = "0" && %ports.ignore = "0" && %ports.disabled = "0"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"1","delay":"300"}', 'disabled' => 0, 'name' => 'Port status up/down');
$default_rules[] = array('device_id' => '-1', 'rule' => '((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100 >= 80', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"-1","delay":"300"}', 'disabled' => 0, 'name' => 'Port utilisation over threshold');
$default_rules[] = array('device_id' => '-1', 'rule' => '%macros.port_down = "1"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"1","delay":"300"}', 'disabled' => 0, 'name' => 'Port status up/down');
$default_rules[] = array('device_id' => '-1', 'rule' => '%macros.port_usage_perc >= "80"', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"-1","delay":"300"}', 'disabled' => 0, 'name' => 'Port utilisation over threshold');
$default_rules[] = array('device_id' => '-1', 'rule' => '%sensors.sensor_current > %sensors.sensor_limit', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"-1","delay":"300"}', 'disabled' => 0, 'name' => 'Sensor over limit');
$default_rules[] = array('device_id' => '-1', 'rule' => '%sensors.sensor_current < %sensors.sensor_limit_low', 'severity' => 'critical', 'extra' => '{"mute":false,"count":"-1","delay":"300"}', 'disabled' => 0, 'name' => 'Sensor under limit');
foreach( $default_rules as $add_rule ) {

View File

@ -11,6 +11,7 @@
*/
$pagetitle[] = "Alert Stats";
$sql = "";
if (isset($device['device_id']) && $device['device_id'] > 0) {
$sql = " AND alert_log.device_id=?";
$param = array(

View File

@ -48,11 +48,11 @@ foreach (dbFetchRows($sql,$param) as $alert) {
$fault_detail .= $tmp;
} else {
foreach ($tmp_alerts as $k=>$v) {
if (!empty($v) && $k != 'device_id' && (stristr($k,'id') || stristr($k,'desc')) && substr_count($k,'_') <= 1) {
if (!empty($v) && $k != 'device_id' && (stristr($k,'id') || stristr($k,'desc') || stristr($k,'msg')) && substr_count($k,'_') <= 1) {
$fault_detail .= "$k => '$v', ";
}
$fault_detail = rtrim($fault_detail,", ");
}
$fault_detail = rtrim($fault_detail,", ");
}
$fault_detail .= "<br>";
}
@ -97,7 +97,7 @@ foreach (dbFetchRows($sql,$param) as $alert) {
if ($_SESSION['userlevel'] >= '10') {
$ack_ico = 'volume-up';
$ack_col = 'success';
if(in_array($alert['state'],array(2,3,4))) {
if($alert['state'] == 2) {
$ack_ico = 'volume-off';
$ack_col = 'danger';
}

View File

@ -28,9 +28,13 @@ include_once($config['install_dir'].'/html/includes/authentication/'.$config['au
/**
* Generate SQL from Rule
* @param string $rule Rule to generate SQL for
* @return string
* @return string|boolean
*/
function GenSQL($rule) {
$rule = RunMacros($rule);
if( empty($rule) ) {
return false;
}
$tmp = explode(" ",$rule);
$tables = array();
foreach( $tmp as $opt ) {
@ -55,6 +59,29 @@ function GenSQL($rule) {
return $sql;
}
/**
* Process Macros
* @param string $rule Rule to process
* @return string|boolean
*/
function RunMacros($rule,$x=1) {
global $config;
krsort($config['alert']['macros']['rule']);
foreach( $config['alert']['macros']['rule'] as $macro=>$value ) {
if( !strstr($macro," ") ) {
$rule = str_replace('%macros.'.$macro,$value,$rule);
}
}
if( strstr($rule,"%macros") ) {
if( ++$x < 30 ) {
$rule = RunMacros($rule,$x);
} else {
return false;
}
}
return $rule;
}
/**
* Get Alert-Rules for Devices
* @param int $device Device-ID
@ -158,8 +185,8 @@ function GetContacts($results) {
if( sizeof($results) == 0 ) {
return array();
}
if( $config['alerts']['email']['default_only'] ) {
return array($config['alerts']['email']['default'] => 'NOC');
if( $config['alert']['default_only'] == true || $config['alerts']['email']['default_only'] == true ) {
return array(''.($config['alert']['default_mail'] ? $config['alert']['default_mail'] : $config['alerts']['email']['default']) => 'NOC');
}
$users = get_userlist();
$contacts = array();

View File

@ -201,6 +201,44 @@ $config['email_smtp_password'] = NULL; // Password for SM
// Alerting Settings
$config['alert'] = array(
'macros' => array( //Macros:
'rule' => array( // For Rules
//Time Macros
'now' => 'NOW()',
'past_5m' => 'DATE_SUB(NOW(),INTERVAL 5 MINUTE)',
'past_10m' => 'DATE_SUB(NOW(),INTERVAL 10 MINUTE)',
'past_15m' => 'DATE_SUB(NOW(),INTERVAL 15 MINUTE)',
'past_30m' => 'DATE_SUB(NOW(),INTERVAL 30 MINUTE)',
'past_60m' => 'DATE_SUB(NOW(),INTERVAL 60 MINUTE)',
//Device Macros
'device' => '(%devices.disabled = "0" && %devices.ignore = "0")',
'device_up' => '(%devices.status = "1" && %macros.device)',
'device_down' => '(%devices.status = "0" && %macros.device)',
//Port Macros
'port' => '(%ports.deleted = "0" && %ports.ignore = "0" && %ports.disabled = "0")',
'port_up' => '(%ports.ifOperStatus = "up" && %ports.ifAdminStatus = "up" && %macros.port)',
'port_down' => '(%ports.ifOperStatus = "down" && %ports.ifAdminStatus != "down" && %macros.port)',
'port_usage_perc' => '((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100',
//Misc Macros
),
),
'transports' => array( //Transports:
'dummy' => false, // Dummy alerting (debug)
'mail' => false, // E-Mail alerting
'irc' => false, // IRC Alerting
),
'globals' => false, //Issue to global-read users
'admins' => false, //Issue to administrators
'default_only' => false, //Only issue to default
'default_mail' => '', //Default email
);
//Legacy options
$config['alerts']['email']['default'] = NULL; // Default alert recipient
$config['alerts']['email']['default_only'] = FALSE; // Only use default recipient
$config['alerts']['email']['enable'] = TRUE; // Enable email alerts