Added Alerting

This commit is contained in:
f0o 2014-12-15 11:10:26 +00:00
parent dbf407746c
commit c0e1d9cbc5
12 changed files with 710 additions and 130 deletions

View File

@ -1,16 +1,26 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
* 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/>. */
/** /**
* Observium * Alerts Cronjob
* * @author f0o <f0o@devilcode.org>
* This file is part of Observium. * @copyright 2014 f0o, LibreNMS
* * @license GPL
* @package observium * @package LibreNMS
* @subpackage alerts * @subpackage Alerts
* @author Adam Armstrong <adama@memetic.org>
* @copyright (C) 2006 - 2012 Adam Armstrong
*
*/ */
include("includes/defaults.inc.php"); include("includes/defaults.inc.php");
@ -18,22 +28,199 @@ include("config.php");
include("includes/definitions.inc.php"); include("includes/definitions.inc.php");
include("includes/functions.php"); include("includes/functions.php");
foreach (dbFetchRows("SELECT *, A.id AS id FROM `alerts` AS A, `devices` AS D WHERE A.device_id = D.device_id AND alerted = '0'") as $alert) RunAlerts();
{
$id = $alert['id'];
$host = $alert['hostname'];
$date = $alert['time_logged'];
$msg = $alert['message'];
$alert_text .= "$date $host $msg";
dbUpdate(array('alerted' => '1'), 'alerts', '`id` = ?', array($id));
/**
* Run all alerts
* @return void
*/
function RunAlerts() {
global $config;
$default_tpl = "%title\r\nSeverity: %severity\r\n{if %state == 0}Time elapsed: %elapsed\r\n{/if}Timestamp: %timestamp\r\nUnique-ID: %uid\r\nRule: %rule\r\n{if %faults}Faults:\r\n{foreach %faults} #%key: %value\r\n{/foreach}{/if}Alert sent to: {foreach %contacts}%value <%key> {/foreach}"; //FIXME: Put somewhere else?
foreach( dbFetchRows("SELECT alerts.device_id, alerts.rule_id, alerts.state FROM alerts WHERE alerts.state != 2 && alerts.open = 1") as $alert ) {
$alert = dbFetchRow("SELECT alert_log.id,alert_log.rule_id,alert_log.device_id,alert_log.state,alert_log.details,alert_log.time_logged,alert_rules.rule,alert_rules.severity,alert_rules.extra FROM alert_log,alert_rules WHERE alert_log.rule_id = alert_rules.id && alert_log.device_id = ? && alert_log.rule_id = ? ORDER BY alert_log.id DESC LIMIT 1",array($alert['device_id'],$alert['rule_id']));
$alert['details'] = json_decode(gzuncompress($alert['details']),true);
$noiss = false;
$noacc = false;
$updet = false;
$rextra = json_decode($alert['extra'],true);
$chk = dbFetchRow('SELECT alerted FROM alerts WHERE device_id = ? && rule_id = ?',array($alert['device_id'],$alert['rule_id']));
if( $chk['alerted'] == $alert['state'] ) {
$noiss = true;
}
if( !empty($rextra['delay']) ) {
if( (time()-strtotime($alert['time_logged'])) < $rextra['delay'] || (!empty($alert['details']['delay']) && (time()-$alert['details']['delay']) < $rextra['delay']) ) {
continue;
} else {
$alert['details']['delay'] = time();
$updet = true;
}
}
if( $alert['state'] == 1 && !empty($rextra['count']) && ($rextra['count'] == -1 || $alert['details']['count']++ < $rextra['count']) ) {
if( $alert['details']['count'] < $rextra['count'] ) {
$noacc = true;
}
$updet = true;
$noiss = false;
}
if( $updet ) {
dbUpdate(array('details' => gzcompress(json_encode($alert['details']),9)),'alert_log','id = ?',array($alert['id']));
}
if( !empty($rextra['muted']) ) {
echo "Muted Alert-UID #".$alert['id']."\r\n";
$noiss = true;
}
if( !$noiss ) {
$obj = DescribeAlert($alert);
if( is_array($obj) ) {
$tpl = dbFetchRow('SELECT template FROM alert_templates WHERE rule_id LIKE "%,'.$alert['rule_id'].',%"');
if( isset($tpl['template']) ) {
$tpl = $tpl['template'];
} else {
$tpl = $default_tpl;
}
echo "Issuing Alert-UID #".$alert['id'].": ";
$msg = FormatAlertTpl($tpl,$obj);
$obj['msg'] = $msg;
if( !empty($config['alert']['transports']) ) {
ExtTransports($obj);
}
echo "\r\n";
dbUpdate(array('alerted' => $alert['state']),'alerts','rule_id = ? && device_id = ?', array($alert['rule_id'], $alert['device_id']));
}
}
if( !$noacc ) {
dbUpdate(array('open' => 0),'alerts','rule_id = ? && device_id = ?', array($alert['rule_id'], $alert['device_id']));
}
}
} }
if ($alert_text) /**
{ * Run external transports
echo("$alert_text"); * @param array $obj Alert-Array
# `echo '$alert_text' | gnokii --sendsms <NUMBER>`; * @return void
*/
function ExtTransports($obj) {
global $config;
foreach( $config['alert']['transports'] as $transport=>$opts ) {
if( 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);
echo ($tmp ? "OK" : "ERROR")."; ";
}
}
} }
/**
* Format Alert
* @param string $tpl Template
* @param array $obj Alert-Array
* @return string
*/
function FormatAlertTpl($tpl,$obj) {
$tpl = addslashes($tpl);
/**
* {if ..}..{else}..{/if}
*/
preg_match_all('/\\{if (.+)\\}(.+)\\{\\/if\\}/Uims',$tpl,$m);
foreach( $m[1] as $k=>$if ) {
$if = preg_replace('/%(\w+)/i','\$obj["$1"]', $if);
$ret = "";
$cond = "if( $if ) {\r\n".'$ret = "'.str_replace("{else}",'";'."\r\n} else {\r\n".'$ret = "',$m[2][$k]).'";'."\r\n}\r\n";
eval($cond); //FIXME: Eval is Evil
$tpl = str_replace($m[0][$k],$ret,$tpl);
}
/**
* {foreach %var}..{/foreach}
*/
preg_match_all('/\\{foreach (.+)\\}(.+)\\{\\/foreach\\}/Uims',$tpl,$m);
foreach( $m[1] as $k=>$for ) {
$for = preg_replace('/%(\w+)/i','\$obj["$1"]', $for);
$ret = "";
$loop = 'foreach( '.$for.' as $key=>$value ) { $ret .= "'.str_replace(array("%key","%value"),array('$key','$value'),$m[2][$k]).'"; }';
eval($loop); //FIXME: Eval is Evil
$tpl = str_replace($m[0][$k],$ret,$tpl);
}
/**
* Populate variables with data
*/
foreach( $obj as $k=>$v ) {
$tpl = str_replace("%".$k, $v, $tpl);
}
return $tpl;
}
/**
* Describe Alert
* @param array $alert Alert-Result from DB
* @return array
*/
function DescribeAlert($alert) {
$tmp = array();
$obj = array();
$device = dbFetchRow("SELECT hostname FROM devices WHERE device_id = ?",array($alert['device_id']));
$obj['hostname'] = $device['hostname'];
$extra = $alert['details'];
$s = (sizeof($extra['rule']) > 1);
if( $alert['state'] == 1 ) {
$obj['title'] = 'Alert for device '.$device['hostname'].' Alert-ID #'.$alert['id'];
foreach( $extra['rule'] as $incident ) {
$i++;
foreach( $incident as $k=>$v ) {
if( !empty($v) && $k != 'device_id' && (stristr($k,'id') || stristr($k,'desc')) && substr_count($k,'_') <= 1 ) {
$obj['faults'][$i] .= $k.' => '.$v."; ";
}
}
}
} elseif( $alert['state'] == 0 ) {
$id = dbFetchRow("SELECT alert_log.id,alert_log.time_logged,alert_log.details FROM alert_log WHERE alert_log.state = 1 && alert_log.rule_id = ? && alert_log.device_id = ? && alert_log.id < ? ORDER BY id DESC LIMIT 1", array($alert['rule_id'],$alert['device_id'],$alert['id']));
if( empty($id['id']) ) {
return false;
}
$extra = json_decode(gzuncompress($id['details']),true);
$s = (sizeof($extra['rule']) > 1);
$obj['title'] = 'Device '.$device['hostname'].' recovered from Alert-ID #'.$id['id'];
$obj['elapsed'] = TimeFormat(strtotime($alert['time_logged'])-strtotime($id['time_logged']));
$obj['id'] = $id['id'];
$obj['faults'] = false;
} else {
return "Unknown State";
}
$obj['uid'] = $alert['id'];
$obj['severity'] = $alert['severity'];
$obj['rule'] = $alert['rule'];
$obj['timestamp'] = $alert['time_logged'];
$obj['contacts'] = $extra['contacts'];
$obj['state'] = $alert['state'];
return $obj;
}
/**
* Format Elapsed Time
* @param int $secs Seconds elapsed
* @return string
*/
function TimeFormat($secs){
$bit = array(
'y' => $secs / 31556926 % 12,
'w' => $secs / 604800 % 52,
'd' => $secs / 86400 % 7,
'h' => $secs / 3600 % 24,
'm' => $secs / 60 % 60,
's' => $secs % 60
);
foreach($bit as $k => $v){
if($v > 0) {
$ret[] = $v . $k;
}
}
if( empty($ret) ) {
return "none";
}
return join(' ', $ret);
}
?> ?>

165
doc/Alerting.md Normal file
View File

@ -0,0 +1,165 @@
Table of Content:
- [About](#about)
- [Rules](#rules)
- [Syntax](#rules-syntax)
- [Examples](#rules-examples)
- [Templates](#templates)
- [Syntax](#templates-syntax)
- [Examples](#templates-examples)
- [Transports](#transports)
- [E-Mail](#transports-email)
- [API](#transports-api)
- [Nagios-Compatible](#transports-nagios)
- [IRC](#transports-irc)
# <a name="about">About</a>
LibreNMS includes a highly customizable alerting system.
The system requires a set of user-defined rules to evaluate the situation of each device, port, service or any other entity.
This document only covers the usage of it. See the [DEVELOPMENT.md](https://github.com/f0o/glowing-tyrion/blob/master/DEVELOPMENT.md) for code-documentation.
# <a name="rules">Rules</a>
Rules are defined using a logical language.
The GUI provides a simple way of creating basic as well as complex Rules in a self-describing manner.
More complex rules can be written manually.
## <a name="rules-syntax">Syntax</a>
Rules must consist of at least 3 elements: An __Entity__, a __Condition__ and a __Value__.
Rules can contain braces and __Glues__.
__Entities__ are provided as `%`-Noted pair of Table and Field. For Example: `%ports.ifOperStatus`.
__Conditions__ can be any of:
- Equals `=`
- Not Equals `!=`
- Matches `~`
- Not Matches `!~`
- Greater `>`
- Greater or Equal `>=`
- Smaller `<`
- Smaller or Equal `<=`
__Values__ can be Entities or any single-quoted data.
__Glues__ can be either `&&` for `AND` or `||` for `OR`.
__Note__: The difference between `Equals` and `Matches` (and it's negation) is that `Equals` does a strict comparison and `Matches` allows the usage of the placeholder `*`. The placeholder `*` is comparable with `.*` in RegExp.
## <a name="rules-examples">Examples</a>
Alert when:
- Device goes down: `%devices.status != '1'`
- Any port changes: `%ports.ifOperStatus != 'up'`
- Root-directory gets too full: `%storage.storage_descr = '/' && %storage.storage_perc >= '75'`
- Any storage gets fuller than the 'warning': `%storage.storage_perc >= %storage_perc_warn`
# <a name="templates">Templates</a>
Templates can be assigned to a single or a group of rules.
They can contain any kind of text.
The template-parser understands `if` and `foreach` controls and replaces certain placeholders with information gathered about the alert.
## <a name="templates-syntax">Syntax</a>
Controls:
- if-else (Else can be omitted):
`{if %placeholder == 'value'}Some Text{else}Other Text{/if}`
- foreach-loop:
`{foreach %placeholder}Key: %key<br/>Value: %value{/foreach}`
__Limitations__: Currently it is not possible to have nested `if` controls, so `if` inside an `if`. It is also not possible to have an `if` inside a `foreach` control. These limitations are going to be resolved in (near?) future.
Placeholders:
- Hostname of the Device: `%hostname`
- Title for the Alert: `%title`
- Time Elapsed, Only available on recovery (`%state == 0`): `%elapsed`
- Alert-ID: `%id`
- Unique-ID: `%uid`
- Faults, Only available on alert (`%state == 1`), must be iterated in a foreach: `%faults`
- State: `%state`
- Severity: `%severity`
- Rule: `%rule`
- Timestamp: `%timestamp`
- Contacts, must be iterated in a foreach, `%key` holds email and `%value` holds name: `%contacts`
## <a name="templates-examples">Examples</a>
Default Template:
```text
%title\r\n
Severity: %severity\r\n
{if %state == 0}Time elapsed: %elapsed\r\n{/if}
Timestamp: %timestamp\r\n
Unique-ID: %uid\r\n
Rule: %rule\r\n
{if %faults}Faults:\r\n
{foreach %faults} #%key: %value\r\n{/foreach}{/if}
Alert sent to: {foreach %contacts}%value <%key> {/foreach}
```
# <a name="transports">Transports</a>
Transports are located within `$config['install_dir']/includes/alerts/transports.*.php` and defined as well as configured via `$config['alert']['transports']['Example'] = 'Some Options'`.
Contacts will be gathered automatically and passed to the configured transports.
The contacts will always include the `SysContact` defined in the Device's SNMP configuration and also every LibreNMS-User that has at least `read`-permissions on the entity that is to be alerted.
At the moment LibreNMS only supports Port or Device permissions.
To include users that have `Global-Read` or `Administrator` permissions it is required to add these additions to the `config.php` respectively:
```php
$config['alert']['globals'] = true; //Include Global-Read into alert-contacts
$config['alert']['admins'] = true; //Include Adminstrators into alert-contacts
```
## <a name="transports-email">E-Mail</a>
E-Mail transport is enabled with adding the following to your `config.php`:
```php
$config['alert']['transports']['mail'] = true;
```
The E-Mail transports uses the same email-configuration like the rest of LibreNMS.
As a small reminder, here is it's configuration directives including defaults:
```php
$config['email_backend'] = 'mail'; // Mail backend. Allowed: "mail" (PHP's built-in), "sendmail", "smtp".
$config['email_from'] = NULL; // Mail from. Default: "ProjectName" <projectid@`hostname`>
$config['email_user'] = $config['project_id'];
$config['email_sendmail_path'] = '/usr/sbin/sendmail'; // The location of the sendmail program.
$config['email_smtp_host'] = 'localhost'; // Outgoing SMTP server name.
$config['email_smtp_port'] = 25; // The port to connect.
$config['email_smtp_timeout'] = 10; // SMTP connection timeout in seconds.
$config['email_smtp_secure'] = NULL; // Enable encryption. Use 'tls' or 'ssl'
$config['email_smtp_auth'] = FALSE; // Whether or not to use SMTP authentication.
$config['email_smtp_username'] = NULL; // SMTP username.
$config['email_smtp_password'] = NULL; // Password for SMTP authentication.
```
## <a name="transports-api">API</a>
API transports definitions are a bit more complex than the E-Mail configuration.
The basis for configuration is `$config['alert']['transports']['api'][METHOD]` where `METHOD` can be `get`,`post` or `put`.
This basis has to contain an array with URLs of each API to call.
The URL can have the same placeholders as defined in the [Template-Syntax](#templates-syntax).
If the `METHOD` is `get`, all placeholders will be URL-Encoded.
The API transport uses cURL to call the APIs, therefore you might need to install `php5-curl` or similar in order to make it work.
__Note__: it is highly recommended to define own [Templates](#templates) when you want to use the API transport. The default template might exceed URL-length for GET requests and therefore cause all sorts of errors.
Example:
```php
$config['alert']['transports']['api']['get'][] = "https://api.thirdparti.es/issue?apikey=abcdefg&subject=%title";
```
## <a name="transports-nagios">Nagios Compatible</a>
The nagios transport will feed a FIFO at the defined location with the same format that nagios would.
This allows you to use other Alerting-Systems to work with LibreNMS, for example [Flapjack](http://flapjack.io).
```php
$config['alert']['transports']['nagios'] = "/path/to/my.fifo"; //Flapjack expects it to be at '/var/cache/nagios3/event_stream.fifo'
```
## <a name="transports-irc">IRC</a>
The IRC transports only works together with the LibreNMS IRC-Bot.
Configuration of the LibreNMS IRC-Bot is described [here](https://github.com/librenms/librenms/blob/master/doc/IRC-Bot.md).
```php
$config['alert']['transports']['irc'] = true;
```

View File

@ -1,112 +1,151 @@
<?php <?php
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
* 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/>. */
/** /**
* Observium Network Management and Monitoring System * Alerts Tracking
* Copyright (C) 2006-2012, Adam Armstrong - http://www.observium.org * @author Daniel Preussker <f0o@devilcode.org>
* * @copyright 2014 f0o, LibreNMS
* @package alerting * @license GPL
* @author Adam Armstrong <adama@memetic.org> * @package LibreNMS
* * @subpackage Alerts
*/ */
/**
* Generate SQL from Rule
* @param string $rule Rule to generate SQL for
* @return string
*/
function GenSQL($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($tmpp[0]);
$rule = str_replace($opt,$tmpp[0].'.'.$tmpp[1],$rule);
}
}
$tables = array_unique($tables);
$x = sizeof($tables);
$i = 0;
$join = "";
while( $i < $x ) {
if( isset($tables[$i+1]) ) {
$join .= $tables[$i].".device_id = ".$tables[$i+1].".device_id && ";
}
$i++;
}
$sql = "SELECT * FROM ".implode(",",$tables)." WHERE (".$join."".$tables[0].".device_id = ?) && (".str_replace(array("*","!~","~"),array("%","NOT LIKE","LIKE"),$rule).")";
return $sql;
}
/** /**
* Build a cache of default alert conditions * Run all rules for a device
* * @param int $device Device-ID
* @return void
*/
function RunRules($device) {
global $debug;
$chk = dbFetchRow("SELECT id FROM alert_schedule WHERE alert_schedule.device_id = ? AND NOW() BETWEEN alert_schedule.start AND alert_schedule.end", array($device));
if( $chk['id'] > 0 ) {
return false;
}
foreach( dbFetchRows("SELECT * FROM alert_rules WHERE alert_rules.disabled = 0 && ( alert_rules.device_id = -1 || alert_rules.device_id = ? ) ORDER BY device_id,id",array($device)) as $rule ) {
echo " #".$rule['id'].":";
$chk = dbFetchRow("SELECT state FROM alerts WHERE rule_id = ? && device_id = ? ORDER BY id DESC LIMIT 1", array($rule['id'], $device));
$sql = GenSQL($rule['rule']);
$qry = dbFetchRows($sql,array($device));
if( sizeof($qry) > 0 ) {
if( $chk['state'] === "2" ) {
echo " SKIP ";
} elseif( $chk['state'] === "1" ) {
echo " NOCHG ";
} else {
$extra = gzcompress(json_encode(array('contacts' => GetContacts($qry), 'rule'=>$qry)),9);
if( dbInsert(array('state' => 1, 'device_id' => $device, 'rule_id' => $rule['id'], 'details' => $extra),'alert_log') ) {
if( !dbUpdate(array('state' => 1, 'open' => 1),'alerts','device_id = ? && rule_id = ?', array($device,$rule['id'])) ) {
dbInsert(array('state' => 1, 'device_id' => $device, 'rule_id' => $rule['id'], 'open' => 1),'alerts');
}
echo " ALERT ";
}
}
} else {
if( $chk['state'] === "0" ) {
echo " NOCHG ";
} else {
if( dbInsert(array('state' => 0, 'device_id' => $device, 'rule_id' => $rule['id']),'alert_log') ){
if( !dbUpdate(array('state' => 0, 'open' => 1),'alerts','device_id = ? && rule_id = ?', array($device,$rule['id'])) ) {
dbInsert(array('state' => 0, 'device_id' => $device, 'rule_id' => $rule['id'], 'open' => 1),'alerts');
}
echo " OK ";
}
}
}
}
}
/**
* Find contacts for alert
* @param array $results Rule-Result
* @return array * @return array
*/ */
function GetContacts($results) {
function cache_conditions_global() { global $config;
$cache = array(); if( sizeof($results) == 0 ) {
foreach (dbFetchRows("SELECT * FROM `alert_conditions_global`") as $entry) return array();
{ }
$cache[$entry['type']][$entry['subtype']][$entry['metric']][] = array('operator' => $entry['operator'], 'value' => $entry['value'], $contacts = array();
'severity' => $entry['severity'], 'alerter' => $entry['alerter'], 'enable' => $entry['enable']); $uids = array();
} foreach( $results as $result ) {
return $cache; $tmpa = array();
$tmp = NULL;
if( is_numeric($result["port_id"]) ) {
$tmpa = dbFetchRows("SELECT user_id FROM ports_perms WHERE access_level >= 0 AND port_id = ?",array($result["port_id"]));
foreach( $tmpa as $tmp ) {
$uids[$tmp['user_id']] = $tmp['user_id'];
}
}
if( is_numeric($result["device_id"]) ) {
$tmpa = dbFetchRow("SELECT sysContact FROM devices WHERE device_id = ?",array($result["device_id"]));
$contacts[$tmpa["sysContact"]] = "NOC";
$tmpa = dbFetchRows("SELECT user_id FROM devices_perms WHERE access_level >= 0 AND device_id = ?", array($result["device_id"]));
foreach( $tmpa as $tmp ) {
$uids[$tmp['user_id']] = $tmp['user_id'];
}
}
}
if( $config["alert"]["globals"] ) {
$tmpa = dbFetchRows("SELECT realname,email FROM users WHERE level >= 5 AND level < 10");
foreach( $tmpa as $tmp ) {
$contacts[$tmp['email']] = $tmp['realname'];
}
}
if( $config["alert"]["admins"] ) {
$tmpa = dbFetchRows("SELECT realname,email FROM users WHERE level = 10");
foreach( $tmpa as $tmp ) {
$contacts[$tmp['email']] = $tmp['realname'];
}
}
if( is_array($uids) ) {
foreach( $uids as $uid ) {
$tmp = dbFetchRow("SELECT realname,email FROM users WHERE user_id = ?", array($uid));
$contacts[$tmp['email']] = $tmp['realname'];
}
}
return $contacts;
} }
/**
* Build a cache of device-specific alert conditions
*
* @return array
* @param device_id
*/
function cache_conditions_device($device_id) {
$cache = array();
foreach (dbFetchRows("SELECT * FROM `alert_conditions` WHERE `device_id` = ?", array($device_id)) as $entry)
{
$cache[$entry['type']][$entry['subtype']][$entry['entity']][$entry['metric']][] = array('condition' => $entry['operator'], 'value' => $entry['value'],
'severity' => $entry['severity'], 'alerter' => $entry['alerter'],
'enable' => $entry['enable']);
}
return $cache;
}
/**
* Compare two values
*
* @return integer
* @param value_a
* @param condition
* @param value_b
*/
function test_condition($value_a, $condition, $value_b)
{
switch($condition)
{
case ">":
if($value_a > $value_b) { $alert = 1; } else { $alert = 0; }
break;
case "<":
if($value_a < $value_b) { $alert = 1; } else { $alert = 0; }
break;
case "!=":
if($value_a != $value_b) { $alert = 1; } else { $alert = 0; }
break;
case "=":
if($value_a = $value_b) { $alert = 1; } else { $alert = 0; }
break;
default:
$alert = -1;
break;
}
return $alert;
}
/**
* Check entity data against alert conditions
*
* @param value_a
* @param condition
* @param value_b
*/
function check_entity($device, $entity_type, $entity_id, $data)
{
global $glo_conditions;
global $dev_conditions;
if(!empty($entity_id)) { echo(" $entity_id"); }
foreach($data as $name => $value)
{
foreach($dev_conditions[$entity_type][$entity_id][$name] as $condition)
{
$alert = test_condition($value, $condition['condition'], $condition['value']);
if($alert == 1)
{
echo("ALERT ");
} else {
echo("OK ");
}
}
}
}
?> ?>

View File

@ -0,0 +1,48 @@
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
* 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/>. */
/**
* API Transport
* @author f0o <f0o@devilcode.org>
* @copyright 2014 f0o, LibreNMS
* @license GPL
* @package LibreNMS
* @subpackage Alerts
*/
foreach( $opts as $method=>$apis ) {
// var_dump($method); //FIXME: propper debuging
foreach( $apis as $api ) {
// var_dump($api); //FIXME: propper debuging
list($host, $api) = explode("?",$api,2);
foreach( $obj as $k=>$v ) {
$api = str_replace("%".$k,$method == "get" ? urlencode($v) : $v, $api);
}
// var_dump($api); //FIXME: propper debuging
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, ($method == "get" ? $host."?".$api : $host) );
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
curl_setopt($curl, CURLOPT_POSTFIELDS, $api);
$ret = curl_exec($curl);
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if( $code != 200 ) {
var_dump("API '$host' returnd Error"); //FIXME: propper debuging
var_dump("Params: ".$api); //FIXME: propper debuging
var_dump("Return: ".$ret); //FIXME: propper debuging
return false;
}
}
}
return true;

View File

@ -0,0 +1,25 @@
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
* 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/>. */
/**
* Dummy Transport
* @author f0o <f0o@devilcode.org>
* @copyright 2014 f0o, LibreNMS
* @license GPL
* @package LibreNMS
* @subpackage Alerts
*/
var_dump($obj);
return true;

View File

@ -0,0 +1,24 @@
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
* 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/>. */
/**
* IRC Transport
* @author f0o <f0o@devilcode.org>
* @copyright 2014 f0o, LibreNMS
* @license GPL
* @package LibreNMS
* @subpackage Alerts
*/
return file_put_contents($config['install_dir']."/.ircbot.alert", json_encode($obj)."\n", FILE_APPEND);

View File

@ -0,0 +1,24 @@
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
* 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/>. */
/**
* Mail Transport
* @author f0o <f0o@devilcode.org>
* @copyright 2014 f0o, LibreNMS
* @license GPL
* @package LibreNMS
* @subpackage Alerts
*/
return send_mail($obj['contacts'], $obj['title'], $obj['msg']);

View File

@ -0,0 +1,48 @@
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
* 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/>. */
/**
* Nagios Transport
* @author f0o <f0o@devilcode.org>
* @copyright 2014 f0o, LibreNMS
* @license GPL
* @package LibreNMS
* @subpackage Alerts
*/
/*
host_perfdata_file_template=
[HOSTPERFDATA]\t
$TIMET$\t
$HOSTNAME$\t
HOST\t
$HOSTSTATE$\t
$HOSTEXECUTIONTIME$\t
$HOSTLATENCY$\t
$HOSTOUTPUT$\t
$HOSTPERFDATA$
*/
$format = '';
$format .= "[HOSTPERFDATA]\t";
$format .= $obj['timestamp']."\t";
$format .= $obj['hostname']."\t";
$format .= md5($obj['rule'])."\t"; //FIXME: Better entity
$format .= ($obj['state'] ? $obj['severity'] : "ok")."\t";
$format .= 0."\t";
$format .= 0."\t";
$format .= str_replace("\n","",nl2br($obj['msg']))."\t";
$format .= "NULL"; //FIXME: What's the HOSTPERFDATA equivalent for LibreNMS? Oo
$format .= "\n";
return file_put_contents($opts, $format);

16
irc.php
View File

@ -151,11 +151,17 @@ class ircbot {
} }
private function alertData() { private function alertData() {
if( ($tmp = $this->read("alert")) !== false ) { if( ($alert = $this->read("alert")) !== false ) {
foreach( $tmp as $data ) { $alert = json_decode($alert,true);
$this->data = $data; foreach( $this->authd as $nick=>$data ) {
echo $this->data; if( $data['expire'] >= time() ) {
//dostuff $this->irc_raw("PRIVMSG ".$nick." :".trim($alert['title'])." - Rule: ".trim($alert['rule'])." - Faults".(sizeof($alert['faults']) > 3 ? " (showing first 3 out of ".sizeof($alert['faults'])." )" : "" ).":");
foreach( $alert['faults'] as $k=>$v ) {
$this->irc_raw("PRIVMSG ".$nick." :#".$k." ".$v);
if( $k >= 3 )
break;
}
}
} }
} }
} }

View File

@ -1,4 +1,5 @@
33 */6 * * * root /opt/librenms/discovery.php -h all >> /dev/null 2>&1 33 */6 * * * root /opt/librenms/discovery.php -h all >> /dev/null 2>&1
*/5 * * * * root /opt/librenms/discovery.php -h new >> /dev/null 2>&1 */5 * * * * root /opt/librenms/discovery.php -h new >> /dev/null 2>&1
*/5 * * * * root /opt/librenms/poller-wrapper.py 16 >> /dev/null 2>&1 */5 * * * * root /opt/librenms/poller-wrapper.py 16 >> /dev/null 2>&1
15 0 * * * root sh /opt/librenms/daily.sh > /dev/null 2>&1 15 0 * * * root sh /opt/librenms/daily.sh >> /dev/null 2>&1
*/2 * * * * root /opt/librenms/alerts.php >> /dev/null 2>&1

View File

@ -20,6 +20,7 @@ include("config.php");
include("includes/definitions.inc.php"); include("includes/definitions.inc.php");
include("includes/functions.php"); include("includes/functions.php");
include("includes/polling/functions.inc.php"); include("includes/polling/functions.inc.php");
include("includes/alerts.inc.php");
$poller_start = utime(); $poller_start = utime();
echo($config['project_name_version']." Poller\n\n"); echo($config['project_name_version']." Poller\n\n");
@ -108,6 +109,8 @@ foreach (dbFetch($query) as $device)
{ {
$device = dbFetchRow("SELECT * FROM `devices` WHERE `device_id` = '".$device['device_id']."'"); $device = dbFetchRow("SELECT * FROM `devices` WHERE `device_id` = '".$device['device_id']."'");
poll_device($device, $options); poll_device($device, $options);
RunRules($device['device_id']);
echo "\r\n";
$polled_devices++; $polled_devices++;
} }

10
sql-schema/036.sql Normal file
View File

@ -0,0 +1,10 @@
DROP TABLE IF EXISTS `alerts`;
CREATE TABLE IF NOT EXISTS `alerts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `rule_id` int(11) NOT NULL, `state` int(11) NOT NULL, `alerted` int(11) NOT NULL, `open` int(11) NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `alert_log`;
CREATE TABLE IF NOT EXISTS `alert_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule_id` int(11) NOT NULL, `device_id` int(11) NOT NULL, `state` int(11) NOT NULL, `details` longblob NOT NULL, `time_logged` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY `id` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `alert_rules`;
CREATE TABLE IF NOT EXISTS `alert_rules` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `rule` text CHARACTER SET utf8 NOT NULL, `severity` enum('ok','warning','critical') CHARACTER SET utf8 NOT NULL, `extra` varchar(255) CHARACTER SET utf8 NOT NULL, `disabled` tinyint(1) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `alert_schedule`;
CREATE TABLE IF NOT EXISTS `alert_schedule` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `start` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `end` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `alert_templates`;
CREATE TABLE IF NOT EXISTS `alert_templates` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule_id` varchar(255) NOT NULL DEFAULT ',', `template` longtext NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;