feature: Added the option to select alert rules from a collection

This commit is contained in:
laf
2016-10-26 06:54:48 +00:00
parent 1504c04fee
commit 8a142aa53f
10 changed files with 255 additions and 7 deletions

View File

@@ -32,6 +32,8 @@ require_once '../includes/defaults.inc.php';
require_once '../config.php';
require_once '../includes/definitions.inc.php';
require_once '../includes/functions.php';
require_once 'includes/functions.inc.php';
require_once 'includes/vars.inc.php';
set_debug($_REQUEST['debug']);
@@ -122,6 +124,18 @@ if (isset($_GET['term'],$_GET['device_id'])) {
$obj = $ret;
}
}
} elseif ($vars['type'] === 'alert_rule_collection') {
$x=0;
foreach (get_rules_from_json() as $rule) {
if (str_contains($rule['name'], $vars['term'], true)) {
$rule['id'] = $x;
$tmp[] = $rule;
}
$x++;
}
if (is_array($tmp)) {
$obj = $tmp;
}
}
die(json_encode($obj));

View File

@@ -18,9 +18,22 @@ if (is_admin() === false) {
}
$alert_id = $_POST['alert_id'];
$template_id = $_POST['template_id'];
if (is_numeric($alert_id) && $alert_id > 0) {
$rule = dbFetchRow('SELECT * FROM `alert_rules` WHERE `id` = ? LIMIT 1', array($alert_id));
} elseif (is_numeric($template_id) && $template_id >= 0) {
$x=0;
foreach (get_rules_from_json() as $tmp_rule) {
if ($x == $template_id) {
$rule = $tmp_rule;
break;
}
$x++;
}
logfile(json_encode($rule));
}
if (is_array($rule)) {
$rule_split = preg_split('/([a-zA-Z0-9_\-\.\=\%\<\>\ \"\'\!\~\(\)\*\/\@\|]+[&&|\|\|]{2})/', $rule['rule'], -1, (PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY));
$count = (count($rule_split) - 1);
$rule_split[$count] = $rule_split[$count].' &&';

View File

@@ -1364,3 +1364,9 @@ function file_download($filename, $content)
header('Pragma: public');
echo $content;
}
function get_rules_from_json()
{
global $config;
return json_decode(file_get_contents($config['install_dir'] . '/misc/alert_rules.json'), true);
}

View File

@@ -0,0 +1,120 @@
<?php
/**
* search_rule_collection.inc.php
*
* LibreNMS search_rule_collection modal
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2016 Neil Lathwood
* @author Neil Lathwood <neil@lathwood.co.uk>
*/
if (is_admin() === false) {
die('ERROR: You need to be admin');
}
?>
<div class="modal fade" id="search_rule_modal" tabindex="-1" role="dialog" aria-labelledby="search_rule" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h5 class="modal-title" id="search_rule">Search alert rule collection</h5>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-8">
<input type="hidden" name="template_rule_id" id="template_rule_id" value="">
<input type="text" id="rule_suggest" name="rule_suggest" class="form-control" placeholder="Start typing..."/>
</div>
<div class="col-md-2">
<input type="submit" id="rule_from_collection" name="rule_from_collection" value="Create" class="btn btn-sm btn-primary">
</div>
</div>
<hr>
<div class="row">
<div class="col-md-2">
Rule:
</div>
<div class="col-md-8">
<div id="rule_display"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var rule_suggestions = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: "ajax_rulesuggest.php?type=alert_rule_collection&term=%QUERY",
filter: function (output) {
return $.map(output, function (item) {
return {
name: item.name,
id: item.id,
rule: item.rule,
};
});
},
wildcard: "%QUERY"
}
});
rule_suggestions.initialize();
$('#rule_suggest').typeahead({
hint: true,
highlight: true,
minLength: 1,
classNames: {
menu: 'typeahead-left'
}
},
{
source: rule_suggestions.ttAdapter(),
async: true,
displayKey: 'name',
valueKey: 'id',
templates: {
suggestion: Handlebars.compile('<p>&nbsp;{{name}}</p>')
},
limit: 20
});
$("#rule_suggest").on("typeahead:selected typeahead:autocompleted", function(e,datum) {
$("#template_rule_id").val(datum.id);
$("#rule_display").html('<mark>' + datum.rule + '</mark>');
});
$("#rule_from_collection").click('', function(e) {
e.preventDefault();
$("#template_id").val($("#template_rule_id").val());
$("#search_rule_modal").modal('hide');
$("#create-alert").modal('show');
});
$("#search_rule_modal").on('hidden.bs.modal', function(e) {
$("#template_rule_id").val('');
$("#rule_suggest").val('');
$("#rule_display").html('');
});
</script>

View File

@@ -31,6 +31,7 @@ if (is_admin() !== false) {
<input type="hidden" name="device_id" id="device_id" value="">
<input type="hidden" name="alert_id" id="alert_id" value="">
<input type="hidden" name="type" id="type" value="create-alert-item">
<input type="hidden" name="template_id" id="template_id" value="">
<div class="form-group">
<div class="col-sm-12">
<span id="ajax_response"></span>
@@ -170,6 +171,25 @@ $('#create-alert').on('show.bs.modal', function (event) {
var device_id = button.data('device_id');
var alert_id = button.data('alert_id');
var modal = $(this)
var template_id = $('#template_id').val();
$('#template_id').val('');
var arr = [];
if (template_id >= 0) {
$.ajax({
type: "POST",
url: "ajax_form.php",
data: { type: "parse-alert-rule", alert_id: null, template_id: template_id },
dataType: "json",
success: function(output) {
$.each ( output['rules'], function( key, value ) {
arr.push(value);
});
$('#response').data('tagmanager').populate(arr);
$('#name').val(output['name']);
$('#device_id').val("-1");
}
});
}
$('#device_id').val(device_id);
$('#alert_id').val(alert_id);
$('#tagmanager').tagmanager();
@@ -182,7 +202,7 @@ $('#create-alert').on('show.bs.modal', function (event) {
tagFieldName: 'maps[]',
initialCap: false
});
if( $('#alert_id').val() == '' ) {
if( $('#alert_id').val() == '' || template_id == '') {
$('#preseed-maps').show();
} else {
$('#preseed-maps').hide();
@@ -193,7 +213,6 @@ $('#create-alert').on('show.bs.modal', function (event) {
data: { type: "parse-alert-rule", alert_id: alert_id },
dataType: "json",
success: function(output) {
var arr = [];
$.each ( output['rules'], function( key, value ) {
arr.push(value);
});

View File

@@ -37,7 +37,7 @@ if (isset($_POST['create-default'])) {
);
$default_rules[] = array(
'device_id' => '-1',
'rule' => '%bgpPeers.bgpPeerFsmEstablishedTime < "300" && %bgpPeers.bgpPeerState = "established"',
'rule' => '%bgpPeers.bgpPeerFsmEstablishedTime < "300" && %bgpPeers.bgpPeerState = "established" && %macros.device_up = "1"',
'severity' => 'critical',
'extra' => '{"mute":false,"count":"1","delay":"300"}',
'disabled' => 0,
@@ -61,7 +61,7 @@ if (isset($_POST['create-default'])) {
);
$default_rules[] = array(
'device_id' => '-1',
'rule' => '%sensors.sensor_current > %sensors.sensor_limit && %sensors.sensor_alert = "1"',
'rule' => '%sensors.sensor_current > %sensors.sensor_limit && %sensors.sensor_alert = "1" && %macros.device_up = "1"',
'severity' => 'critical',
'extra' => '{"mute":false,"count":"-1","delay":"300"}',
'disabled' => 0,
@@ -69,7 +69,7 @@ if (isset($_POST['create-default'])) {
);
$default_rules[] = array(
'device_id' => '-1',
'rule' => '%sensors.sensor_current < %sensors.sensor_limit_low && %sensors.sensor_alert = "1"',
'rule' => '%sensors.sensor_current < %sensors.sensor_limit_low && %sensors.sensor_alert = "1" && %macros.device_up = "1"',
'severity' => 'critical',
'extra' => '{"mute":false,"count":"-1","delay":"300"}',
'disabled' => 0,
@@ -77,7 +77,7 @@ if (isset($_POST['create-default'])) {
);
$default_rules[] = array(
'device_id' => '-1',
'rule' => '%services.service_status != "0"',
'rule' => '%services.service_status != "0" && %macros.device_up = "1"',
'severity' => 'critical',
'extra' => '{"mute":false,"count":"-1","delay":"300"}',
'disabled' => 0,
@@ -92,6 +92,7 @@ if (isset($_POST['create-default'])) {
require_once 'includes/modal/new_alert_rule.inc.php';
require_once 'includes/modal/delete_alert_rule.inc.php';
require_once 'includes/modal/alert_rule_collection.inc.php';
?>
<form method="post" action="" id="result_form">
<?php
@@ -117,8 +118,9 @@ echo '<div class="table-responsive">
echo '<td colspan="7">';
if ($_SESSION['userlevel'] >= '10') {
echo '<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#create-alert" data-device_id="'.$device['device_id'].'"><i class="fa fa-plus"></i> Create new alert rule</button>';
echo '<i> - OR - </i>';
echo '<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#search_rule_modal" data-device_id="'.$device['device_id'].'"><i class="fa fa-plus"></i> Create rule from collection</button>';
}
echo '</td>
<td><select name="results" id="results" class="form-control input-sm" onChange="updateResults(this);">';
$result_options = array(
@@ -338,4 +340,11 @@ function changePage(page,e) {
$('#result_form').submit();
}
function newRule(data, e) {
$('#template_id').val(data.value);
$('#create-alert').modal({
show: true
});
}
</script>

26
misc/alert_rules.json Normal file
View File

@@ -0,0 +1,26 @@
[
{
"rule": "%macros.bill_quota_over_quota >= \"75\"",
"name": "Quota bills over 75% used"
},
{
"rule": "%macros.bill_cdr_over_quota >= \"75\"",
"name": "CDR bills over 75% used"
},
{
"rule": "%ipsec_tunnels.tunnel_status != \"active\" && %macros.device_up = \"1\"",
"name": "IPSec tunnels down"
},
{
"rule": "%pollers.time_taken >= \"250\"",
"name": "Poller is taking too long"
},
{
"rule": "%macros.device_up = \"1\" && %devices.os = \"asa\" && %ciscoASA.data > \"5000\"",
"name": "Cisco ASA connections over 5000"
},
{
"rule": "%processors.processor_usage > \"85\" && %macros.device_up = \"1\"",
"name": "Processor usage over 85%"
}
]

2
sql-schema/149.sql Normal file
View File

@@ -0,0 +1,2 @@
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.bill_quota_over_quota','((%bills.total_data/%bills.bill_quota) * 100) && %bills.bill_type = "quota"','((%bills.total_data/%bills.bill_quota) * 100) && %bills.bill_type = "quota"','Quota bills over X perc of quota','alerting',0,'macros',0,1,0);
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.bill_cdr_over_quota','((%bills.rate_95th/%bills.bill_cdr) * 100) && %bills.bill_type = "cdr"','((%bills.rate_95th/%bills.bill_cdr) * 100) && %bills.bill_type = "cdr"','CDR bills over X perc of quota','alerting',0,'macros',0,1,0);

38
tests/AlertingTest.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
/**
* AlertingTest.php
*
* Tests for alerting functionality.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2016 Neil Lathwood
* @author Neil Lathwood <neil@lathwood.co.uk>
*/
namespace LibreNMS\Tests;
class AlertTest extends \PHPUnit_Framework_TestCase
{
public function testJsonAlertCollection()
{
$rules = get_rules_from_json();
$this->assertInternalType('array', $rules);
foreach ($rules as $rule) {
$this->assertInternalType('array', $rule);
}
}
}

View File

@@ -37,6 +37,7 @@ $runtime_stats = array('snmpget' => 0, 'snmpwalk' => 0);
$classLoader->registerDir($install_dir . '/tests', 'LibreNMS\Tests');
require $install_dir . '/includes/common.php';
require $install_dir . '/html/includes/functions.inc.php';
if (getenv('SNMPSIM')) {
require $install_dir . '/includes/functions.php';
} else {