mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
152 lines
6.8 KiB
PHP
152 lines
6.8 KiB
PHP
<?php
|
|
/**
|
|
* AlertRules.php
|
|
*
|
|
* Extending the built in logging to add an event logger function
|
|
*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*
|
|
* Original Code:
|
|
*
|
|
* @author Daniel Preussker <f0o@devilcode.org>
|
|
* @copyright 2014 f0o, LibreNMS
|
|
* @license GPL
|
|
*
|
|
* @link https://www.librenms.org
|
|
*
|
|
* @copyright 2019 KanREN, Inc.
|
|
* @author Heath Barnhart <hbarnhart@kanren.net>
|
|
*/
|
|
|
|
namespace LibreNMS\Alert;
|
|
|
|
use App\Models\Eventlog;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Database\QueryException;
|
|
use LibreNMS\Enum\AlertState;
|
|
use LibreNMS\Enum\Severity;
|
|
use Log;
|
|
|
|
class AlertRules
|
|
{
|
|
public function runRules($device_id)
|
|
{
|
|
//Check to see if under maintenance
|
|
if (AlertUtil::isMaintenance($device_id) > 0) {
|
|
echo "Under Maintenance, skipping alert rules check.\r\n";
|
|
|
|
return false;
|
|
}
|
|
//Check to see if disable alerting is set
|
|
if (AlertUtil::hasDisableNotify($device_id)) {
|
|
echo "Disable alerting is set, Clearing active alerts and skipping alert rules check\r\n";
|
|
$device_alert['state'] = AlertState::CLEAR;
|
|
$device_alert['alerted'] = 0;
|
|
$device_alert['open'] = 0;
|
|
dbUpdate($device_alert, 'alerts', '`device_id` = ?', [$device_id]);
|
|
|
|
return false;
|
|
}
|
|
//Checks each rule.
|
|
foreach (AlertUtil::getRules($device_id) as $rule) {
|
|
Log::info('Rule %p#' . $rule['id'] . ' (' . $rule['name'] . '):%n ', ['color' => true]);
|
|
$extra = json_decode($rule['extra'], true);
|
|
if (isset($extra['invert'])) {
|
|
$inv = (bool) $extra['invert'];
|
|
} else {
|
|
$inv = false;
|
|
}
|
|
d_echo(PHP_EOL);
|
|
if (empty($rule['query'])) {
|
|
$rule['query'] = AlertDB::genSQL($rule['rule'], $rule['builder']);
|
|
}
|
|
$sql = $rule['query'];
|
|
|
|
// set fetch assoc
|
|
global $PDO_FETCH_ASSOC;
|
|
$PDO_FETCH_ASSOC = true;
|
|
try {
|
|
$qry = \DB::select($sql, [$device_id]);
|
|
} catch (QueryException $e) {
|
|
c_echo('%RError: %n' . $e->getMessage() . PHP_EOL);
|
|
Eventlog::log("Error in alert rule {$rule['name']} ({$rule['id']}): " . $e->getMessage(), $device_id, 'alert', Severity::Error);
|
|
continue; // skip this rule
|
|
}
|
|
$PDO_FETCH_ASSOC = false;
|
|
|
|
$cnt = count($qry);
|
|
for ($i = 0; $i < $cnt; $i++) {
|
|
if (isset($qry[$i]['ip'])) {
|
|
$qry[$i]['ip'] = inet6_ntop($qry[$i]['ip']);
|
|
}
|
|
}
|
|
$s = count($qry);
|
|
if ($s == 0 && $inv === false) {
|
|
$doalert = false;
|
|
} elseif ($s > 0 && $inv === false) {
|
|
$doalert = true;
|
|
} elseif ($s == 0 && $inv === true) {
|
|
$doalert = true;
|
|
} else {
|
|
$doalert = false;
|
|
}
|
|
|
|
$current_state = dbFetchCell('SELECT state FROM alerts WHERE rule_id = ? AND device_id = ? ORDER BY id DESC LIMIT 1', [$rule['id'], $device_id]);
|
|
if ($doalert) {
|
|
if ($current_state == AlertState::ACKNOWLEDGED) {
|
|
Log::info('Status: %ySKIP%n', ['color' => true]);
|
|
} elseif ($current_state >= AlertState::ACTIVE) {
|
|
Log::info('Status: %bNOCHG%n', ['color' => true]);
|
|
// NOCHG here doesn't mean no change full stop. It means no change to the alert state
|
|
// So we update the details column with any fresh changes to the alert output we might have.
|
|
$alert_log = dbFetchRow('SELECT alert_log.id, alert_log.details FROM alert_log,alert_rules WHERE alert_log.rule_id = alert_rules.id && alert_log.device_id = ? && alert_log.rule_id = ? && alert_rules.disabled = 0
|
|
ORDER BY alert_log.id DESC LIMIT 1', [$device_id, $rule['id']]);
|
|
$details = [];
|
|
if (! empty($alert_log['details'])) {
|
|
$details = json_decode(gzuncompress($alert_log['details']), true);
|
|
}
|
|
$details['contacts'] = AlertUtil::getContacts($qry);
|
|
$details['rule'] = $qry;
|
|
$details = gzcompress(json_encode($details), 9);
|
|
dbUpdate(['details' => $details], 'alert_log', 'id = ?', [$alert_log['id']]);
|
|
} else {
|
|
$extra = gzcompress(json_encode(['contacts' => AlertUtil::getContacts($qry), 'rule' => $qry]), 9);
|
|
if (dbInsert(['state' => AlertState::ACTIVE, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'details' => $extra], 'alert_log')) {
|
|
if (is_null($current_state)) {
|
|
dbInsert(['state' => AlertState::ACTIVE, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'open' => 1, 'alerted' => 0], 'alerts');
|
|
} else {
|
|
dbUpdate(['state' => AlertState::ACTIVE, 'open' => 1, 'timestamp' => Carbon::now()], 'alerts', 'device_id = ? && rule_id = ?', [$device_id, $rule['id']]);
|
|
}
|
|
Log::info(PHP_EOL . 'Status: %rALERT%n', ['color' => true]);
|
|
}
|
|
}
|
|
} else {
|
|
if (! is_null($current_state) && $current_state == AlertState::RECOVERED) {
|
|
Log::info('Status: %bNOCHG%n', ['color' => true]);
|
|
} else {
|
|
if (dbInsert(['state' => AlertState::RECOVERED, 'device_id' => $device_id, 'rule_id' => $rule['id']], 'alert_log')) {
|
|
if (is_null($current_state)) {
|
|
dbInsert(['state' => AlertState::RECOVERED, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'open' => 1, 'alerted' => 0], 'alerts');
|
|
} else {
|
|
dbUpdate(['state' => AlertState::RECOVERED, 'open' => 1, 'note' => '', 'timestamp' => Carbon::now()], 'alerts', 'device_id = ? && rule_id = ?', [$device_id, $rule['id']]);
|
|
}
|
|
|
|
Log::info(PHP_EOL . 'Status: %gOK%n', ['color' => true]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|