Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Alert Subsys to OOP and SNMPTraps trigger Alert Rules (#9765)
* Changed snmptrap.php and handlers to allow for alerts. * Moved RunRules() to Dispatcher.php * Modified includes, passes pre-commit tests locally. * Converted RunRules to OO, fixed formatting in files found by TravisCI * rebase, covert alert subsy to oop * Modified init.php to call new Alert subsystem * fixed dependencies * Resolved undefined functions * Fixed PingCheck.php not triggering * Changed runAlerts to __construct * Fixes Can't have Config inside empty() incorrectly named function (my fault) poller.php missing shebang organize imports
- Loading branch information
1 parent
6986711
commit 851994c
Showing
10 changed files
with
1,057 additions
and
915 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?php | ||
/** | ||
* AlertDB.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 <http://www.gnu.org/licenses/>. | ||
* | ||
* | ||
* Original code: | ||
* @author Daniel Preussker <f0o@devilcode.org> | ||
* @copyright 2014 f0o, LibreNMS | ||
* @license GPL | ||
* | ||
* Modified by: | ||
* @package LibreNMS | ||
* @link http://librenms.org | ||
* @copyright 2019 KanREN, Inc. | ||
* @author Heath Barnhart <hbarnhart@kanren.net> | ||
*/ | ||
|
||
namespace LibreNMS\Alert; | ||
|
||
use App\Models\Device; | ||
use LibreNMS\Alert\AlertUtil; | ||
use LibreNMS\Alerting\QueryBuilderParser; | ||
|
||
class AlertDB | ||
{ | ||
|
||
/** | ||
* @param $rule | ||
* @param $query_builder | ||
* @return bool|string | ||
*/ | ||
public static function genSQL($rule, $query_builder = false) | ||
{ | ||
if ($query_builder) { | ||
return QueryBuilderParser::fromJson($query_builder)->toSql(); | ||
} else { | ||
return self::genSQLOld($rule); | ||
} | ||
} | ||
|
||
/** | ||
* Generate SQL from Rule | ||
* @param string $rule Rule to generate SQL for | ||
* @return string|boolean | ||
*/ | ||
public static function genSQLOld($rule) | ||
{ | ||
$rule = AlertUtil::runMacros($rule); | ||
if (empty($rule)) { | ||
//Cannot resolve Macros due to recursion. Rule is invalid. | ||
return false; | ||
} | ||
//Pretty-print rule to dissect easier | ||
$pretty = array('&&' => ' && ', '||' => ' || '); | ||
$rule = str_replace(array_keys($pretty), $pretty, $rule); | ||
$tmp = explode(" ", $rule); | ||
$tables = array(); | ||
foreach ($tmp as $opt) { | ||
if (strstr($opt, '%') && strstr($opt, '.')) { | ||
$tmpp = explode(".", $opt, 2); | ||
$tmpp[0] = str_replace("%", "", $tmpp[0]); | ||
$tables[] = mres(str_replace("(", "", $tmpp[0])); | ||
$rule = str_replace($opt, $tmpp[0].'.'.$tmpp[1], $rule); | ||
} | ||
} | ||
$tables = array_keys(array_flip($tables)); | ||
if (dbFetchCell('SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_NAME = ? && COLUMN_NAME = ?', array($tables[0],'device_id')) != 1) { | ||
//Our first table has no valid glue, append the 'devices' table to it! | ||
array_unshift($tables, 'devices'); | ||
} | ||
$x = sizeof($tables)-1; | ||
$i = 0; | ||
$join = ""; | ||
while ($i < $x) { | ||
if (isset($tables[$i+1])) { | ||
$gtmp = ResolveGlues(array($tables[$i+1]), 'device_id'); | ||
if ($gtmp === false) { | ||
//Cannot resolve glue-chain. Rule is invalid. | ||
return false; | ||
} | ||
$last = ""; | ||
$qry = ""; | ||
foreach ($gtmp as $glue) { | ||
if (empty($last)) { | ||
list($tmp,$last) = explode('.', $glue); | ||
$qry .= $glue.' = '; | ||
} else { | ||
list($tmp,$new) = explode('.', $glue); | ||
$qry .= $tmp.'.'.$last.' && '.$tmp.'.'.$new.' = '; | ||
$last = $new; | ||
} | ||
if (!in_array($tmp, $tables)) { | ||
$tables[] = $tmp; | ||
} | ||
} | ||
$join .= "( ".$qry.$tables[0].".device_id ) && "; | ||
} | ||
$i++; | ||
} | ||
$sql = "SELECT * FROM ".implode(",", $tables)." WHERE (".$join."".str_replace("(", "", $tables[0]).".device_id = ?) && (".str_replace(array("%","@","!~","~"), array("",".*","NOT REGEXP","REGEXP"), $rule).")"; | ||
return $sql; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
<?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 <http://www.gnu.org/licenses/>. | ||
* | ||
* Original Code: | ||
* @author Daniel Preussker <f0o@devilcode.org> | ||
* @copyright 2014 f0o, LibreNMS | ||
* @license GPL | ||
* @package LibreNMS | ||
* @subpackage Alerts | ||
* | ||
* Modeified by: | ||
* @package LibreNMS | ||
* @link http://librenms.org | ||
* @copyright 2019 KanREN, Inc. | ||
* @author Heath Barnhart <hbarnhart@kanren.net> | ||
*/ | ||
|
||
namespace LibreNMS\Alert; | ||
|
||
use App\Models\Device; | ||
use LibreNMS\Alert\AlertUtil; | ||
use LibreNMS\Alert\AlertDB; | ||
|
||
class AlertRules | ||
{ | ||
public function runRules($device_id) | ||
{ | ||
|
||
//Check to see if under maintenance | ||
if (AlertUtil::isMaintenance($device_id) > 0) { | ||
echo "Under Maintenance, Skipping alerts.\r\n"; | ||
return false; | ||
} | ||
//Checks each rule. | ||
foreach (AlertUtil::getRules($device_id) as $rule) { | ||
c_echo('Rule %p#'.$rule['id'].' (' . $rule['name'] . '):%n '); | ||
$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']; | ||
$qry = dbFetchRows($sql, array($device_id)); | ||
$cnt = count($qry); | ||
for ($i = 0; $i < $cnt; $i++) { | ||
if (isset($qry[$i]['ip'])) { | ||
$qry[$i]['ip'] = inet6_ntop($qry[$i]['ip']); | ||
} | ||
} | ||
$s = sizeof($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 == 2) { | ||
c_echo('Status: %ySKIP'); | ||
} elseif ($current_state >= 1) { | ||
c_echo('Status: %bNOCHG'); | ||
// 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', array($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(array('details' => $details), 'alert_log', 'id = ?', array($alert_log['id'])); | ||
} else { | ||
$extra = gzcompress(json_encode(array('contacts' => AlertUtil::getContacts($qry), 'rule'=>$qry)), 9); | ||
if (dbInsert(['state' => 1, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'details' => $extra], 'alert_log')) { | ||
if (is_null($current_state)) { | ||
dbInsert(array('state' => 1, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'open' => 1,'alerted' => 0), 'alerts'); | ||
} else { | ||
dbUpdate(['state' => 1, 'open' => 1], 'alerts', 'device_id = ? && rule_id = ?', [$device_id, $rule['id']]); | ||
} | ||
c_echo(PHP_EOL . 'Status: %rALERT'); | ||
} | ||
} | ||
} else { | ||
if (!is_null($current_state) && $current_state == 0) { | ||
c_echo('Status: %bNOCHG'); | ||
} else { | ||
if (dbInsert(['state' => 0, 'device_id' => $device_id, 'rule_id' => $rule['id']], 'alert_log')) { | ||
if (is_null($current_state)) { | ||
dbInsert(['state' => 0, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'open' => 1, 'alerted' => 0], 'alerts'); | ||
} else { | ||
dbUpdate(['state' => 0, 'open' => 1, 'note' => ''], 'alerts', 'device_id = ? && rule_id = ?', [$device_id, $rule['id']]); | ||
} | ||
|
||
c_echo(PHP_EOL . 'Status: %gOK'); | ||
} | ||
} | ||
} | ||
c_echo('%n' . PHP_EOL); | ||
} | ||
} | ||
} |
Oops, something went wrong.