mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Added ability to set a custom SQL query for alert rules. (#9094)
* Added support for AVG in rules * More updates * Final work to have advanced sql queries * Added missing use * Fix exception when invalid json is passed * Fixed api for alert rules * updated docs
This commit is contained in:
committed by
Tony Murray
parent
53a1730fc7
commit
466b5a35a8
@@ -146,7 +146,7 @@ class QueryBuilderParser implements \JsonSerializable
|
|||||||
public static function fromJson($json)
|
public static function fromJson($json)
|
||||||
{
|
{
|
||||||
if (!is_array($json)) {
|
if (!is_array($json)) {
|
||||||
$json = json_decode($json, true);
|
$json = json_decode($json, true) ?: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new static($json);
|
return new static($json);
|
||||||
@@ -235,7 +235,7 @@ class QueryBuilderParser implements \JsonSerializable
|
|||||||
$wrap = false;
|
$wrap = false;
|
||||||
|
|
||||||
if ($expand) {
|
if ($expand) {
|
||||||
$sql = 'SELECT * FROM ' . implode(',', $this->getTables());
|
$sql = 'SELECT * FROM ' .implode(',', $this->getTables());
|
||||||
$sql .= ' WHERE ' . $this->generateGlue() . ' AND ';
|
$sql .= ' WHERE ' . $this->generateGlue() . ' AND ';
|
||||||
|
|
||||||
// only wrap in ( ) if the condition is OR and there is more than one rule
|
// only wrap in ( ) if the condition is OR and there is more than one rule
|
||||||
|
@@ -84,7 +84,6 @@ Output:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"message": "",
|
|
||||||
"message": "Alert has been unmuted"
|
"message": "Alert has been unmuted"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -243,8 +242,8 @@ Route: `/api/v0/rules`
|
|||||||
|
|
||||||
Input (JSON):
|
Input (JSON):
|
||||||
|
|
||||||
- device_id: This is either the device id or -1 for a global rule
|
- devices: This is either an array of device ids or -1 for a global rule
|
||||||
- rule: The rule which should be in the format %entity $condition $value (i.e %devices.status != 0 for devices marked as down).
|
- builder: The rule which should be in the format entity.condition value (i.e devices.status != 0 for devices marked as down). It must be json encoded in the format rules are currently stored.
|
||||||
- severity: The severity level the alert will be raised against, Ok, Warning, Critical.
|
- severity: The severity level the alert will be raised against, Ok, Warning, Critical.
|
||||||
- disabled: Whether the rule will be disabled or not, 0 = enabled, 1 = disabled
|
- disabled: Whether the rule will be disabled or not, 0 = enabled, 1 = disabled
|
||||||
- count: This is how many polling runs before an alert will trigger and the frequency.
|
- count: This is how many polling runs before an alert will trigger and the frequency.
|
||||||
@@ -255,7 +254,7 @@ Input (JSON):
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
```curl
|
```curl
|
||||||
curl -X POST -d '{"device_id":"-1", "rule":"%devices.os != \"Cisco\"","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules
|
curl -X POST -d '{"device_id":[1,2,3], "name": "testrule", builder":"{\"condition\":\"AND\",\"rules\":[{\"id\":\"devices.hostname\",\"field\":\"devices.hostname\",\"type\":\"string\",\"input\":\"text\",\"operator\":\"equal\",\"value\":\"localhost\"}],\"valid\":true}","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules
|
||||||
```
|
```
|
||||||
|
|
||||||
Output:
|
Output:
|
||||||
@@ -278,8 +277,8 @@ Route: `/api/v0/rules`
|
|||||||
Input (JSON):
|
Input (JSON):
|
||||||
|
|
||||||
- rule_id: You must specify the rule_id to edit an existing rule, if this is absent then a new rule will be created.
|
- rule_id: You must specify the rule_id to edit an existing rule, if this is absent then a new rule will be created.
|
||||||
- device_id: This is either the device id or -1 for a global rule
|
- devices: This is either an array of device ids or -1 for a global rule
|
||||||
- rule: The rule which should be in the format %entity $condition $value (i.e %devices.status != 0 for devices marked as down).
|
- builder: The rule which should be in the format entity.condition value (i.e devices.status != 0 for devices marked as down). It must be json encoded in the format rules are currently stored.
|
||||||
- severity: The severity level the alert will be raised against, Ok, Warning, Critical.
|
- severity: The severity level the alert will be raised against, Ok, Warning, Critical.
|
||||||
- disabled: Whether the rule will be disabled or not, 0 = enabled, 1 = disabled
|
- disabled: Whether the rule will be disabled or not, 0 = enabled, 1 = disabled
|
||||||
- count: This is how many polling runs before an alert will trigger and the frequency.
|
- count: This is how many polling runs before an alert will trigger and the frequency.
|
||||||
@@ -290,7 +289,7 @@ Input (JSON):
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
```curl
|
```curl
|
||||||
curl -X PUT -d '{"rule_id":1,"device_id":"-1", "rule":"%devices.os != \"Cisco\"","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules
|
curl -X PUT -d '{"rule_id":1,"device_id":"-1", "name": "testrule", "builder":"{\"condition\":\"AND\",\"rules\":[{\"id\":\"devices.hostname\",\"field\":\"devices.hostname\",\"type\":\"string\",\"input\":\"text\",\"operator\":\"equal\",\"value\":\"localhost\"}],\"valid\":true}","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules
|
||||||
```
|
```
|
||||||
|
|
||||||
Output:
|
Output:
|
||||||
|
@@ -60,6 +60,17 @@ Here are some of the other options available when adding an alerting rule:
|
|||||||
- Invert match: Invert the matching rule (ie. alert on items that _don't_ match the rule).
|
- Invert match: Invert the matching rule (ie. alert on items that _don't_ match the rule).
|
||||||
- Recovery alerts: This will disable the recovery notification from being sent if turned off.
|
- Recovery alerts: This will disable the recovery notification from being sent if turned off.
|
||||||
|
|
||||||
|
# Advanced
|
||||||
|
|
||||||
|
On the Advanced tab, you can specify some additional options for the alert rule:
|
||||||
|
|
||||||
|
- Override SQL: Enable this if you using a custom query
|
||||||
|
- Query: The query to be used for the alert.
|
||||||
|
|
||||||
|
> An example of this would be an average rule for all CPUs over 10%:
|
||||||
|
> SELECT *,AVG(processors.processor_usage) as cpu_avg FROM devices,processors WHERE (devices.device_id = ? AND devices.device_id = processors.device_id) AND (devices.status = 1 && (devices.disabled = 0 && devices.ignore = 0)) = 1 HAVING AVG(processors.processor_usage) > 10
|
||||||
|
> cpu_avg would then contain the average CPU usage value.
|
||||||
|
|
||||||
## Procedure
|
## Procedure
|
||||||
You can associate a rule to a procedure by giving the URL of the procedure when creating the rule. Only links like "http://" are supported, otherwise an error will be returned. Once configured, procedure can be opened from the Alert widget through the "Open" button, which can be shown/hidden from the widget configuration box.
|
You can associate a rule to a procedure by giving the URL of the procedure when creating the rule. Only links like "http://" are supported, otherwise an error will be returned. Once configured, procedure can be opened from the Alert widget through the "Open" button, which can be shown/hidden from the widget configuration box.
|
||||||
|
|
||||||
|
@@ -43,7 +43,7 @@ Placeholders are special variables that if used within the template will be repl
|
|||||||
- long uptime of the Device (28 days, 22h 30m 7s): `$alert->uptime_long`
|
- long uptime of the Device (28 days, 22h 30m 7s): `$alert->uptime_long`
|
||||||
- description (purpose db field) of the Device: `$alert->description`
|
- description (purpose db field) of the Device: `$alert->description`
|
||||||
- notes of the Device: `$alert->notes`
|
- notes of the Device: `$alert->notes`
|
||||||
- notes of the alert: `$alert->alert_notes`
|
- notes of the alert (ack notes): `$alert->alert_notes`
|
||||||
- ping timestamp (if icmp enabled): `$alert->ping_timestamp`
|
- ping timestamp (if icmp enabled): `$alert->ping_timestamp`
|
||||||
- ping loss (if icmp enabled): `$alert->ping_loss`
|
- ping loss (if icmp enabled): `$alert->ping_loss`
|
||||||
- ping min (if icmp enabled): `$alert->ping_min`
|
- ping min (if icmp enabled): `$alert->ping_min`
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use LibreNMS\Authentication\LegacyAuth;
|
use LibreNMS\Authentication\LegacyAuth;
|
||||||
|
use LibreNMS\Alerting\QueryBuilderParser;
|
||||||
|
|
||||||
function authToken(\Slim\Route $route)
|
function authToken(\Slim\Route $route)
|
||||||
{
|
{
|
||||||
@@ -1063,20 +1064,28 @@ function add_edit_rule()
|
|||||||
check_is_admin();
|
check_is_admin();
|
||||||
$app = \Slim\Slim::getInstance();
|
$app = \Slim\Slim::getInstance();
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
if (json_last_error()) {
|
||||||
|
api_error(500, "We couldn't parse the provided json");
|
||||||
|
}
|
||||||
|
|
||||||
$rule_id = mres($data['rule_id']);
|
$rule_id = mres($data['rule_id']);
|
||||||
$device_id = mres($data['device_id']);
|
$tmp_devices = (array)mres($data['devices']);
|
||||||
if (empty($device_id) && !isset($rule_id)) {
|
$groups = (array)$data['groups'];
|
||||||
api_error(400, 'Missing the device id or global device id (-1)');
|
if (empty($tmp_devices) && !isset($rule_id)) {
|
||||||
|
api_error(400, 'Missing the devices or global device (-1)');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($device_id == 0) {
|
$devices = [];
|
||||||
$device_id = '-1';
|
foreach ($tmp_devices as $device) {
|
||||||
|
if ($device == "-1") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$devices[] = ctype_digit($device) ? $device : getidbyname($device);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rule = $data['rule'];
|
$builder = $data['builder'] ?: $data['rule'];
|
||||||
if (empty($rule)) {
|
if (empty($builder)) {
|
||||||
api_error(400, 'Missing the alert rule');
|
api_error(400, 'Missing the alert builder rule');
|
||||||
}
|
}
|
||||||
|
|
||||||
$name = mres($data['name']);
|
$name = mres($data['name']);
|
||||||
@@ -1102,6 +1111,8 @@ function add_edit_rule()
|
|||||||
$count = mres($data['count']);
|
$count = mres($data['count']);
|
||||||
$mute = mres($data['mute']);
|
$mute = mres($data['mute']);
|
||||||
$delay = mres($data['delay']);
|
$delay = mres($data['delay']);
|
||||||
|
$override_query = $data['override_query'];
|
||||||
|
$adv_query = $data['adv_query'];
|
||||||
$delay_sec = convert_delay($delay);
|
$delay_sec = convert_delay($delay);
|
||||||
if ($mute == 1) {
|
if ($mute == 1) {
|
||||||
$mute = true;
|
$mute = true;
|
||||||
@@ -1109,31 +1120,46 @@ function add_edit_rule()
|
|||||||
$mute = false;
|
$mute = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$extra = array(
|
$extra = [
|
||||||
'mute' => $mute,
|
'mute' => $mute,
|
||||||
'count' => $count,
|
'count' => $count,
|
||||||
'delay' => $delay_sec,
|
'delay' => $delay_sec,
|
||||||
);
|
'options' =>
|
||||||
|
[
|
||||||
|
'override_query' => $override_query
|
||||||
|
],
|
||||||
|
];
|
||||||
$extra_json = json_encode($extra);
|
$extra_json = json_encode($extra);
|
||||||
|
|
||||||
|
if ($override_query === 'on') {
|
||||||
|
$query = $adv_query;
|
||||||
|
} else {
|
||||||
|
$query = QueryBuilderParser::fromJson($builder)->toSql();
|
||||||
|
if (empty($query)) {
|
||||||
|
api_error(500, "We couldn't parse your rule");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isset($rule_id)) {
|
if (!isset($rule_id)) {
|
||||||
if (dbFetchCell('SELECT `name` FROM `alert_rules` WHERE `name`=?', array($name)) == $name) {
|
if (dbFetchCell('SELECT `name` FROM `alert_rules` WHERE `name`=?', array($name)) == $name) {
|
||||||
api_error(500, 'Addition failed : Name has already been used');
|
api_error(500, 'Addition failed : Name has already been used');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (dbFetchCell("SELECT name FROM alert_rules WHERE name=? AND id !=? ", array($name, $rule_id)) == $name) {
|
if (dbFetchCell("SELECT name FROM alert_rules WHERE name=? AND id !=? ", array($name, $rule_id)) == $name) {
|
||||||
api_error(500, 'Addition failed : Name has already been used');
|
api_error(500, 'Update failed : Invalid rule id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_numeric($rule_id)) {
|
if (is_numeric($rule_id)) {
|
||||||
if (!(dbUpdate(array('name' => $name, 'rule' => $rule, 'severity' => $severity, 'disabled' => $disabled, 'extra' => $extra_json), 'alert_rules', 'id=?', array($rule_id)) >= 0)) {
|
if (!(dbUpdate(array('name' => $name, 'builder' => $builder, 'query' => $query, 'severity' => $severity, 'disabled' => $disabled, 'extra' => $extra_json), 'alert_rules', 'id=?', array($rule_id)) >= 0)) {
|
||||||
api_error(500, 'Failed to update existing alert rule');
|
api_error(500, 'Failed to update existing alert rule');
|
||||||
}
|
}
|
||||||
} elseif (!dbInsert(array('name' => $name, 'device_id' => $device_id, 'rule' => $rule, 'severity' => $severity, 'disabled' => $disabled, 'extra' => $extra_json), 'alert_rules')) {
|
} elseif (!$rule_id = dbInsert(array('name' => $name, 'builder' => $builder, 'query' => $query, 'severity' => $severity, 'disabled' => $disabled, 'extra' => $extra_json), 'alert_rules')) {
|
||||||
api_error(500, 'Failed to create new alert rule');
|
api_error(500, 'Failed to create new alert rule');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbSyncRelationship('alert_device_map', 'rule_id', $rule_id, 'device_id', $devices);
|
||||||
|
dbSyncRelationship('alert_group_map', 'rule_id', $rule_id, 'group_id', $groups);
|
||||||
api_success_noresult(200);
|
api_success_noresult(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,8 +38,18 @@ if (!LegacyAuth::user()->hasGlobalAdmin()) {
|
|||||||
$status = 'ok';
|
$status = 'ok';
|
||||||
$message = '';
|
$message = '';
|
||||||
|
|
||||||
$builder_json = $_POST['builder_json'];
|
$builder_json = $vars['builder_json'];
|
||||||
$query = QueryBuilderParser::fromJson($builder_json)->toSql();
|
$override_query = $vars['override_query'];
|
||||||
|
|
||||||
|
$options = [
|
||||||
|
'override_query' => $override_query,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($override_query === 'on') {
|
||||||
|
$query = $vars['adv_query'];
|
||||||
|
} else {
|
||||||
|
$query = QueryBuilderParser::fromJson($builder_json)->toSql();
|
||||||
|
}
|
||||||
$rule_id = $_POST['rule_id'];
|
$rule_id = $_POST['rule_id'];
|
||||||
$count = mres($_POST['count']);
|
$count = mres($_POST['count']);
|
||||||
$delay = mres($_POST['delay']);
|
$delay = mres($_POST['delay']);
|
||||||
@@ -79,6 +89,7 @@ $extra = array(
|
|||||||
'invert' => $invert,
|
'invert' => $invert,
|
||||||
'interval' => $interval_sec,
|
'interval' => $interval_sec,
|
||||||
'recovery' => $recovery,
|
'recovery' => $recovery,
|
||||||
|
'options' => $options,
|
||||||
);
|
);
|
||||||
|
|
||||||
$extra_json = json_encode($extra);
|
$extra_json = json_encode($extra);
|
||||||
|
@@ -70,12 +70,13 @@ if (is_array($rule)) {
|
|||||||
|
|
||||||
header('Content-type: application/json');
|
header('Content-type: application/json');
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'extra' => isset($rule['extra']) ? json_decode($rule['extra']) : null,
|
'extra' => isset($rule['extra']) ? json_decode($rule['extra']) : null,
|
||||||
'maps' => $maps,
|
'maps' => $maps,
|
||||||
'transports' => $transports,
|
'transports' => $transports,
|
||||||
'name' => $rule['name'],
|
'name' => $rule['name'],
|
||||||
'proc' => $rule['proc'],
|
'proc' => $rule['proc'],
|
||||||
'builder' => $builder,
|
'builder' => $builder,
|
||||||
'severity' => $rule['severity'],
|
'severity' => $rule['severity'],
|
||||||
|
'adv_query' => $rule['query'],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,11 @@ if (LegacyAuth::user()->hasGlobalAdmin()) {
|
|||||||
<h5 class="modal-title" id="Create">Alert Rule :: <a href="https://docs.librenms.org/Alerting/"><i class="fa fa-book fa-1x"></i> Docs</a> </h5>
|
<h5 class="modal-title" id="Create">Alert Rule :: <a href="https://docs.librenms.org/Alerting/"><i class="fa fa-book fa-1x"></i> Docs</a> </h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
|
<li role="presentation" class="active"><a href="#main" aria-controls="main" role="tab" data-toggle="tab">Main </a></li>
|
||||||
|
<li role="presentation"><a href="#advanced" aria-controls="advanced" role="tab" data-toggle="tab">Advanced</a></li>
|
||||||
|
</ul>
|
||||||
|
<br />
|
||||||
<form method="post" role="form" id="rules" class="form-horizontal alerts-form">
|
<form method="post" role="form" id="rules" class="form-horizontal alerts-form">
|
||||||
<input type="hidden" name="device_id" id="device_id" value="<?php echo isset($device['device_id']) ? $device['device_id'] : -1; ?>">
|
<input type="hidden" name="device_id" id="device_id" value="<?php echo isset($device['device_id']) ? $device['device_id'] : -1; ?>">
|
||||||
<input type="hidden" name="device_name" id="device_name" value="<?php echo format_hostname($device); ?>">
|
<input type="hidden" name="device_name" id="device_name" value="<?php echo format_hostname($device); ?>">
|
||||||
@@ -37,88 +41,100 @@ if (LegacyAuth::user()->hasGlobalAdmin()) {
|
|||||||
<input type="hidden" name="type" id="type" value="alert-rules">
|
<input type="hidden" name="type" id="type" value="alert-rules">
|
||||||
<input type="hidden" name="template_id" id="template_id" value="">
|
<input type="hidden" name="template_id" id="template_id" value="">
|
||||||
<input type="hidden" name="builder_json" id="builder_json" value="">
|
<input type="hidden" name="builder_json" id="builder_json" value="">
|
||||||
<div class='form-group' title="The description of this alert rule.">
|
<div class="tab-content">
|
||||||
<label for='name' class='col-sm-3 col-md-2 control-label'>Rule name: </label>
|
<div role="tabpanel" class="tab-pane active" id="main">
|
||||||
<div class='col-sm-9 col-md-10'>
|
<div class='form-group' title="The description of this alert rule.">
|
||||||
<input type='text' id='name' name='name' class='form-control validation' maxlength='200' required>
|
<label for='name' class='col-sm-3 col-md-2 control-label'>Rule name: </label>
|
||||||
</div>
|
<div class='col-sm-9 col-md-10'>
|
||||||
</div>
|
<input type='text' id='name' name='name' class='form-control validation' maxlength='200' required>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<div class="col-sm-3 col-md-2">
|
</div>
|
||||||
<div class="dropdown">
|
<div class="form-group">
|
||||||
<button class="btn btn-default dropdown-toggle" type="button"
|
<div class="col-sm-3 col-md-2">
|
||||||
id="import-from" data-toggle="dropdown" aria-haspopup="true"
|
<div class="dropdown">
|
||||||
aria-expanded="true">
|
<button class="btn btn-default dropdown-toggle" type="button"
|
||||||
Import from
|
id="import-from" data-toggle="dropdown" aria-haspopup="true"
|
||||||
<span class="caret"></span>
|
aria-expanded="true">
|
||||||
</button>
|
Import from
|
||||||
<ul class="dropdown-menu" aria-labelledby="import-from" id="import-dropdown">
|
<span class="caret"></span>
|
||||||
<li><a href="#" name="import-query" id="import-query">SQL Query</a></li>
|
</button>
|
||||||
<li><a href="#" name="import-old-format" id="import-old-format">Old Format</a></li>
|
<ul class="dropdown-menu" aria-labelledby="import-from" id="import-dropdown">
|
||||||
<li><a href="#" name="import-collection" id="import-collection">Collection</a></li>
|
<li><a href="#" name="import-query" id="import-query">SQL Query</a></li>
|
||||||
</ul>
|
<li><a href="#" name="import-old-format" id="import-old-format">Old Format</a></li>
|
||||||
|
<li><a href="#" name="import-collection" id="import-collection">Collection</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-9 col-md-10">
|
||||||
|
<div id="builder"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" title="How to display the alert. OK: green, Warning: yellow, Critical: red">
|
||||||
|
<label for='severity' class='col-sm-3 col-md-2 control-label'>Severity: </label>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<select name='severity' id='severity' class='form-control'>
|
||||||
|
<option value='ok'>OK</option>
|
||||||
|
<option value='warning'>Warning</option>
|
||||||
|
<option value='critical' selected>Critical</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<label for='count' class='col-sm-3 col-md-2 control-label' title="How many notifications to issue while active before stopping. -1 means no limit. If interval is 0, this has no effect.">Max alerts: </label>
|
||||||
|
<div class="col-sm-2" title="How many notifications to issue while active before stopping. -1 means no limit. If interval is 0, this has no effect.">
|
||||||
|
<input type='text' id='count' name='count' class='form-control' size="4" value="123">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3" title="How log to wait before issuing a notification. If the alert clears before the delay, no notification will be issued. (s,m,h,d)">
|
||||||
|
<label for='delay' class='control-label' style="vertical-align: top;">Delay: </label>
|
||||||
|
<input type='text' id='delay' name='delay' class='form-control' size="4">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-md-3" title="How often to re-issue notifications while this alert is active. 0 means notify once. This is affected by the poller interval. (s,m,h,d)">
|
||||||
|
<label for='interval' class='control-label' style="vertical-align: top;">Interval: </label>
|
||||||
|
<input type='text' id='interval' name='interval' class='form-control' size="4">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='form-group form-inline'>
|
||||||
|
<label for='mute' class='col-sm-3 col-md-2 control-label' title="Show alert status in the webui, but do not issue notifications.">Mute alerts: </label>
|
||||||
|
<div class='col-sm-2' title="Show alert status in the webui, but do not issue notifications.">
|
||||||
|
<input type="checkbox" name="mute" id="mute">
|
||||||
|
</div>
|
||||||
|
<label for='invert' class='col-sm-3 col-md-2 control-label' title="Alert when this rule doesn't match." style="vertical-align: top;">Invert match: </label>
|
||||||
|
<div class='col-sm-2' title="Alert when this rule doesn't match.">
|
||||||
|
<input type='checkbox' name='invert' id='invert'>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" title="Issue recovery notifications.">
|
||||||
|
<label for='recovery' class='col-sm-3 col-md-2 control-label'>Recovery alerts: </label>
|
||||||
|
<div class='col-sm-2'>
|
||||||
|
<input type='checkbox' name='recovery' id='recovery'>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" title="Restricts this alert rule to the selected devices or groups.">
|
||||||
|
<label for='maps' class='col-sm-3 col-md-2 control-label'>Map To: </label>
|
||||||
|
<div class="col-sm-9 col-md-10">
|
||||||
|
<select id="maps" name="maps[]" class="form-control" multiple="multiple"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='form-group' title="A link to some documentation on how to handle this alert. This will be included in notifications.">
|
||||||
|
<label for='proc' class='col-sm-3 col-md-2 control-label'>Procedure URL: </label>
|
||||||
|
<div class='col-sm-9 col-md-10'>
|
||||||
|
<input type='text' id='proc' name='proc' class='form-control validation' pattern='(http|https)://.*' maxlength='80'>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-9 col-md-10">
|
<div role="tabpanel" class="tab-pane" id="advanced">
|
||||||
<div id="builder"></div>
|
<div class="form-group">
|
||||||
</div>
|
<label for="override_query" class="col-sm-3 col-md-2 control-label">Override SQL</label>
|
||||||
</div>
|
<div class="col-sm-9 col-md-10">
|
||||||
<div class="form-group" title="How to display the alert. OK: green, Warning: yellow, Critical: red">
|
<input type='checkbox' name='override_query' id='override_query'>
|
||||||
<label for='severity' class='col-sm-3 col-md-2 control-label'>Severity: </label>
|
</div>
|
||||||
<div class="col-sm-2">
|
</div>
|
||||||
<select name='severity' id='severity' class='form-control'>
|
<div class="form-group">
|
||||||
<option value='ok'>OK</option>
|
<label for="adv_query" class="col-sm-3 col-md-2 control-label">Query</label>
|
||||||
<option value='warning'>Warning</option>
|
<div class="col-sm-9 col-md-10">
|
||||||
<option value='critical' selected>Critical</option>
|
<input type="text" id="adv_query" name="adv_query" class="form-control">
|
||||||
</select>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<label for='count' class='col-sm-3 col-md-2 control-label' title="How many notifications to issue while active before stopping. -1 means no limit. If interval is 0, this has no effect.">Max alerts: </label>
|
|
||||||
<div class="col-sm-2" title="How many notifications to issue while active before stopping. -1 means no limit. If interval is 0, this has no effect.">
|
|
||||||
<input type='text' id='count' name='count' class='form-control' size="4" value="123">
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-3" title="How long to wait before issuing a notification. If the alert clears before the delay, no notification will be issued. (s,m,h,d)">
|
|
||||||
<label for='delay' class='control-label' style="vertical-align: top;">Delay: </label>
|
|
||||||
<input type='text' id='delay' name='delay' class='form-control' size="4">
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4 col-md-3" title="How often to re-issue notifications while this alert is active. 0 means notify once. This is affected by the poller interval. (s,m,h,d)">
|
|
||||||
<label for='interval' class='control-label' style="vertical-align: top;">Interval: </label>
|
|
||||||
<input type='text' id='interval' name='interval' class='form-control' size="4">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class='form-group form-inline'>
|
|
||||||
<label for='mute' class='col-sm-3 col-md-2 control-label' title="Show alert status in the webui, but do not issue notifications.">Mute alerts: </label>
|
|
||||||
<div class='col-sm-2' title="Show alert status in the webui, but do not issue notifications.">
|
|
||||||
<input type="checkbox" name="mute" id="mute">
|
|
||||||
</div>
|
|
||||||
<label for='invert' class='col-sm-3 col-md-2 control-label' title="Alert when this rule doesn't match." style="vertical-align: top;">Invert match: </label>
|
|
||||||
<div class='col-sm-2' title="Alert when this rule doesn't match.">
|
|
||||||
<input type='checkbox' name='invert' id='invert'>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group" title="Issue recovery notifications.">
|
|
||||||
<label for='recovery' class='col-sm-3 col-md-2 control-label'>Recovery alerts: </label>
|
|
||||||
<div class='col-sm-2'>
|
|
||||||
<input type='checkbox' name='recovery' id='recovery'>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group" title="Restricts this alert rule to the selected devices or groups.">
|
|
||||||
<label for='maps' class='col-sm-3 col-md-2 control-label'>Map To: </label>
|
|
||||||
<div class="col-sm-9 col-md-10">
|
|
||||||
<select id="maps" name="maps[]" class="form-control" multiple="multiple"></select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group" title="Restricts this alert rule to specified transports.">
|
|
||||||
<label for="transports" class="col-sm-3 col-md-2 control-label">Transports: </label>
|
|
||||||
<div class="col-sm-9 col-md-10">
|
|
||||||
<select id="transports" name="transports[]" class="form-control" multiple="multiple"></select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class='form-group' title="A link to some documentation on how to handle this alert. This will be included in notifications.">
|
|
||||||
<label for='proc' class='col-sm-3 col-md-2 control-label'>Procedure URL: </label>
|
|
||||||
<div class='col-sm-9 col-md-10'>
|
|
||||||
<input type='text' id='proc' name='proc' class='form-control validation' pattern='(http|https)://.*' maxlength='80'>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -269,15 +285,17 @@ if (LegacyAuth::user()->hasGlobalAdmin()) {
|
|||||||
$("#mute").bootstrapSwitch('state', false);
|
$("#mute").bootstrapSwitch('state', false);
|
||||||
$("#invert").bootstrapSwitch('state', false);
|
$("#invert").bootstrapSwitch('state', false);
|
||||||
$("#recovery").bootstrapSwitch('state', true);
|
$("#recovery").bootstrapSwitch('state', true);
|
||||||
|
$("#override_query").bootstrapSwitch('state', false);
|
||||||
$(this).find("input[type=text]").val("");
|
$(this).find("input[type=text]").val("");
|
||||||
$('#count').val('-1');
|
$('#count').val('-1');
|
||||||
$('#delay').val('1m');
|
$('#delay').val('1m');
|
||||||
$('#interval').val('5m');
|
$('#interval').val('5m');
|
||||||
|
$('#adv_query').val('');
|
||||||
|
|
||||||
var $maps = $('#maps');
|
var $maps = $('#maps');
|
||||||
$maps.empty();
|
$maps.empty();
|
||||||
$maps.val(null).trigger('change');
|
$maps.val(null).trigger('change');
|
||||||
setRuleDevice() // pre-populate device in the maps if this is a per-device rule
|
setRuleDevice();// pre-populate device in the maps if this is a per-device rule
|
||||||
|
|
||||||
var $transports = $("#transports");
|
var $transports = $("#transports");
|
||||||
$transports.empty();
|
$transports.empty();
|
||||||
@@ -291,6 +309,7 @@ if (LegacyAuth::user()->hasGlobalAdmin()) {
|
|||||||
$('#proc').val(rule.proc);
|
$('#proc').val(rule.proc);
|
||||||
$('#builder').queryBuilder("setRules", rule.builder);
|
$('#builder').queryBuilder("setRules", rule.builder);
|
||||||
$('#severity').val(rule.severity).trigger('change');
|
$('#severity').val(rule.severity).trigger('change');
|
||||||
|
$('#adv_query').val(rule.adv_query);
|
||||||
|
|
||||||
var $maps = $('#maps');
|
var $maps = $('#maps');
|
||||||
$maps.empty();
|
$maps.empty();
|
||||||
@@ -337,12 +356,20 @@ if (LegacyAuth::user()->hasGlobalAdmin()) {
|
|||||||
$('#interval').val(extra.interval);
|
$('#interval').val(extra.interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extra.adv_query) {
|
||||||
|
$('#adv_query').val(extra.adv_query);
|
||||||
|
}
|
||||||
|
|
||||||
$("[name='mute']").bootstrapSwitch('state', extra.mute);
|
$("[name='mute']").bootstrapSwitch('state', extra.mute);
|
||||||
$("[name='invert']").bootstrapSwitch('state', extra.invert);
|
$("[name='invert']").bootstrapSwitch('state', extra.invert);
|
||||||
if (typeof extra.recovery == 'undefined') {
|
if (typeof extra.recovery == 'undefined') {
|
||||||
extra.recovery = true;
|
extra.recovery = true;
|
||||||
}
|
}
|
||||||
$("[name='recovery']").bootstrapSwitch('state', extra.recovery)
|
if (typeof extra.options.override_query == 'undefined') {
|
||||||
|
extra.options.override_query = false;
|
||||||
|
}
|
||||||
|
$("[name='recovery']").bootstrapSwitch('state', extra.recovery);
|
||||||
|
$("[name='override_query']").bootstrapSwitch('state', extra.options.override_query);
|
||||||
} else {
|
} else {
|
||||||
$('#count').val('-1');
|
$('#count').val('-1');
|
||||||
}
|
}
|
||||||
|
@@ -55,14 +55,21 @@ switch ($type) {
|
|||||||
$response = 'no match';
|
$response = 'no match';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rule['builder']) {
|
$extra = json_decode($rule['extra'], true);
|
||||||
|
if ($extra['options']['override_query'] === 'on') {
|
||||||
|
$qb = $extra['options']['override_query'];
|
||||||
|
} elseif ($rule['builder']) {
|
||||||
$qb = QueryBuilderParser::fromJson($rule['builder']);
|
$qb = QueryBuilderParser::fromJson($rule['builder']);
|
||||||
} else {
|
} else {
|
||||||
$qb = QueryBuilderParser::fromOld($rule['rule']);
|
$qb = QueryBuilderParser::fromOld($rule['rule']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$output .= 'Rule name: ' . $rule['name'] . PHP_EOL;
|
$output .= 'Rule name: ' . $rule['name'] . PHP_EOL;
|
||||||
$output .= 'Alert rule: ' . $qb->toSql(false) . PHP_EOL;
|
if ($qb instanceof QueryBuilderParser) {
|
||||||
|
$output .= 'Alert rule: ' . $qb->toSql(false) . PHP_EOL;
|
||||||
|
} else {
|
||||||
|
$output .= 'Alert rule: Custom SQL Query' . PHP_EOL;
|
||||||
|
}
|
||||||
$output .= 'Alert query: ' . $rule['query'] . PHP_EOL;
|
$output .= 'Alert query: ' . $rule['query'] . PHP_EOL;
|
||||||
$output .= 'Rule match: ' . $response . PHP_EOL . PHP_EOL;
|
$output .= 'Rule match: ' . $response . PHP_EOL . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
@@ -177,6 +177,8 @@ foreach (dbFetchRows($full_query, $param) as $rule) {
|
|||||||
|
|
||||||
if (empty($rule['builder'])) {
|
if (empty($rule['builder'])) {
|
||||||
$rule_display = $rule['rule'];
|
$rule_display = $rule['rule'];
|
||||||
|
} elseif ($rule_extra['options']['override_query'] === 'on') {
|
||||||
|
$rule_display = 'Custom SQL Query';
|
||||||
} else {
|
} else {
|
||||||
$rule_display = QueryBuilderParser::fromJson($rule['builder'])->toSql(false);
|
$rule_display = QueryBuilderParser::fromJson($rule['builder'])->toSql(false);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user