2015-04-03 18:22:29 +00:00
< ? php
2015-07-13 20:10:26 +02:00
/*
* Copyright ( C ) 2015 Daniel Preussker < f0o @ devilcode . org >
2015-04-03 18:22:29 +00:00
* 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 .
2015-07-13 20:10:26 +02:00
*
2015-04-03 18:22:29 +00:00
* 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 .
2015-07-13 20:10:26 +02:00
*
2015-04-03 18:22:29 +00:00
* You should have received a copy of the GNU General Public License
2015-07-13 20:10:26 +02:00
* along with this program . If not , see < http :// www . gnu . org / licenses />.
*/
2015-04-03 18:22:29 +00:00
/**
* Device - Grouping
* @ author Daniel Preussker < f0o @ devilcode . org >
2016-06-02 12:37:03 -05:00
* @ author Tony Murray < murrayotony @ gmail . com >
* @ copyright 2016 f0o , murrant , LibreNMS
2015-04-03 18:22:29 +00:00
* @ license GPL
* @ package LibreNMS
* @ subpackage Devices
*/
2016-06-02 12:37:03 -05:00
/**
* Add a new device group
* @ param $pattern
* @ param $name
* @ param $desc
* @ return int | string
*/
function AddDeviceGroup ( $name , $desc , $pattern )
{
$group_id = dbInsert ( array ( 'name' => $name , 'desc' => $desc , 'pattern' => $pattern ), 'device_groups' );
if ( $group_id ) {
UpdateDeviceGroup ( $group_id );
}
return $group_id ;
}
/**
* Update a device group
* @ param $group_id
* @ param $pattern
* @ param $name
* @ param $desc
* @ return bool
*/
function EditDeviceGroup ( $group_id , $name = null , $desc = null , $pattern = null )
{
$vars = array ();
if ( ! is_null ( $name )) {
$vars [ 'name' ] = $name ;
}
if ( ! is_null ( $desc )) {
$vars [ 'desc' ] = $desc ;
}
if ( ! is_null ( $pattern )) {
$vars [ 'pattern' ] = $pattern ;
}
$success = dbUpdate ( $vars , 'device_groups' , 'id=?' , array ( $group_id )) >= 0 ;
if ( $success ) {
UpdateDeviceGroup ( $group_id );
}
return $success ;
}
2015-04-03 18:22:29 +00:00
/**
* Generate SQL from Group - Pattern
* @ param string $pattern Pattern to generate SQL for
2016-09-27 11:50:52 -05:00
* @ param string $search What to searchid for
* @ param int $extra
2016-09-18 19:08:33 -05:00
* @ return string sql to perform the search
2015-04-03 18:22:29 +00:00
*/
2016-08-28 12:32:58 -05:00
function GenGroupSQL ( $pattern , $search = '' , $extra = 0 )
{
2015-07-15 19:55:57 +00:00
$pattern = RunGroupMacros ( $pattern );
if ( $pattern === false ) {
2016-08-28 12:32:58 -05:00
return false ;
2015-07-15 19:55:57 +00:00
}
2016-09-27 11:50:52 -05:00
if ( starts_with ( $pattern , '%' )) {
// v1 pattern
$tables = array ();
$words = explode ( ' ' , $pattern );
foreach ( $words as $word ) {
if ( starts_with ( $word , '%' ) && str_contains ( $word , '.' )) {
list ( $table , $column ) = explode ( '.' , $word , 2 );
$table = str_replace ( '%' , '' , $table );
$tables [] = mres ( str_replace ( '(' , '' , $table ));
$pattern = str_replace ( $word , $table . '.' . $column , $pattern );
}
2015-07-13 20:10:26 +02:00
}
2016-09-27 11:50:52 -05:00
$tables = array_keys ( array_flip ( $tables ));
} else {
// v2 pattern
$tables = getTablesFromPattern ( $pattern );
2015-07-13 20:10:26 +02:00
}
2016-09-27 11:50:52 -05:00
$pattern = rtrim ( $pattern , '&|' );
2015-11-19 08:40:49 +00:00
2016-09-27 11:50:52 -05:00
if ( $tables [ 0 ] != 'devices' && 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, prepend the 'devices' table to it!
2016-06-22 08:42:48 +00:00
array_unshift ( $tables , 'devices' );
}
$x = sizeof ( $tables ) - 1 ;
$i = 0 ;
$join = " " ;
2016-08-28 12:32:58 -05:00
while ( $i < $x ) {
if ( isset ( $tables [ $i + 1 ])) {
$gtmp = ResolveGlues ( array ( $tables [ $i + 1 ]), 'device_id' );
if ( $gtmp === false ) {
2016-06-22 08:42:48 +00:00
//Cannot resolve glue-chain. Rule is invalid.
return false ;
}
$last = " " ;
$qry = " " ;
2016-08-28 12:32:58 -05:00
foreach ( $gtmp as $glue ) {
if ( empty ( $last )) {
list ( $tmp , $last ) = explode ( '.' , $glue );
2016-06-22 08:42:48 +00:00
$qry .= $glue . ' = ' ;
2016-08-28 12:32:58 -05:00
} else {
list ( $tmp , $new ) = explode ( '.' , $glue );
2016-06-22 08:42:48 +00:00
$qry .= $tmp . '.' . $last . ' && ' . $tmp . '.' . $new . ' = ' ;
$last = $new ;
}
2016-08-28 12:32:58 -05:00
if ( ! in_array ( $tmp , $tables )) {
2016-06-22 08:42:48 +00:00
$tables [] = $tmp ;
}
}
$join .= " ( " . $qry . $tables [ 0 ] . " .device_id ) && " ;
2015-07-13 20:10:26 +02:00
}
$i ++ ;
}
2015-12-13 17:20:34 +00:00
if ( $extra === 1 ) {
$sql_extra = " ,`devices`.* " ;
}
2016-07-02 06:44:49 +00:00
if ( ! empty ( $search )) {
2016-08-28 12:32:58 -05:00
$search = str_replace ( " ( " , " " , $tables [ 0 ]) . '.' . $search . ' AND' ;
2016-07-02 06:44:49 +00:00
}
if ( ! empty ( $join )) {
2016-09-27 11:50:52 -05:00
$join = '(' . rtrim ( $join , '& ' ) . ') &&' ;
2016-07-02 06:44:49 +00:00
}
$sql = 'SELECT DISTINCT(' . str_replace ( '(' , '' , $tables [ 0 ]) . '.device_id)' . $sql_extra . ' FROM ' . implode ( ',' , $tables ) . ' WHERE ' . $join . ' ' . $search . ' (' . str_replace ( array ( '%' , '@' , '!~' , '~' ), array ( '' , '.*' , 'NOT REGEXP' , 'REGEXP' ), $pattern ) . ')' ;
2015-07-13 20:10:26 +02:00
return $sql ;
} //end GenGroupSQL()
2015-04-03 18:22:29 +00:00
2016-09-27 11:50:52 -05:00
/**
* Extract an array of tables in a pattern
*
* @ param string $pattern
* @ return array
*/
function getTablesFromPattern ( $pattern )
{
preg_match_all ( '/[A-Za-z_]+(?=\.[A-Za-z_]+ )/' , $pattern , $tables );
if ( is_null ( $tables )) {
return array ();
}
return array_keys ( array_flip ( $tables [ 0 ])); // unique tables only
}
2015-04-03 18:22:29 +00:00
/**
2016-06-02 12:37:03 -05:00
* Run the group queries again to get fresh list of devices for this group
2015-07-13 20:10:26 +02:00
* @ param integer $group_id Group - ID
2015-04-03 18:22:29 +00:00
* @ return string
*/
2016-06-02 12:37:03 -05:00
function QueryDevicesFromGroup ( $group_id )
{
2016-09-27 11:50:52 -05:00
$group = dbFetchRow ( 'SELECT pattern,params FROM device_groups WHERE id = ?' , array ( $group_id ));
$pattern = rtrim ( $group [ 'pattern' ], '&|' );
$params = ( array ) json_decode ( $group [ 'params' ]);
2015-07-13 20:10:26 +02:00
if ( ! empty ( $pattern )) {
2016-09-27 11:50:52 -05:00
$result = dbFetchColumn ( GenGroupSQL ( $pattern ), $params );
return $result ;
2015-07-13 20:10:26 +02:00
}
return false ;
2016-06-02 12:37:03 -05:00
} //end QueryDevicesFromGroup()
2015-07-13 20:10:26 +02:00
2016-06-02 12:37:03 -05:00
/**
* Get an array of all the device ids belonging to this group_id
* @ param $group_id
* @ param bool $nested Return an array of arrays containing 'device_id' . ( for API compatibility )
2017-02-27 14:39:02 +00:00
* @ param string $full Return all fields from devices_id
2016-06-02 12:37:03 -05:00
* @ return array
*/
2017-02-27 14:39:02 +00:00
function GetDevicesFromGroup ( $group_id , $nested = false , $full = '' )
2016-06-02 12:37:03 -05:00
{
2017-02-22 10:37:40 +01:00
if ( $full ) {
2017-02-27 14:39:02 +00:00
$query = 'SELECT `device_groups`.`name`, `devices`.* FROM `device_groups` INNER JOIN `device_group_device` ON `device_groups`.`id` = `device_group_device`.`device_group_id` INNER JOIN `devices` ON `device_group_device`.`device_id` = `devices`.`device_id` WHERE `device_groups`.`id` = ?' ;
2017-02-22 10:37:40 +01:00
} else {
2017-02-27 14:39:02 +00:00
$query = 'SELECT `device_id` FROM `device_group_device` WHERE `device_group_id` = ? ' ;
2017-02-22 10:37:40 +01:00
}
2016-06-02 12:37:03 -05:00
if ( $nested ) {
return dbFetchRows ( $query , array ( $group_id ));
} else {
return dbFetchColumn ( $query , array ( $group_id ));
}
} //end GetDevicesFromGroup()
2015-04-03 18:22:29 +00:00
/**
* Get all Device - Groups
* @ return array
*/
2016-08-28 12:32:58 -05:00
function GetDeviceGroups ()
{
2015-08-03 15:18:21 -08:00
return dbFetchRows ( 'SELECT * FROM device_groups ORDER BY name' );
2015-07-13 20:10:26 +02:00
} //end GetDeviceGroups()
2015-04-03 18:22:29 +00:00
/**
2016-06-02 12:37:03 -05:00
* Run the group queries again to get fresh list of groups for this device
* @ param integer $device_id Device - ID
* @ param int $extra Return extra info about the groups ( name , desc , pattern )
2015-04-03 18:22:29 +00:00
* @ return array
*/
2016-08-28 12:32:58 -05:00
function QueryGroupsFromDevice ( $device_id , $extra = 0 )
{
2015-12-12 12:58:07 +00:00
$ret = array ();
foreach ( GetDeviceGroups () as $group ) {
2016-09-27 11:50:52 -05:00
$params = ( array ) json_decode ( $group [ 'params' ]);
array_unshift ( $params , $device_id );
if ( dbFetchCell ( GenGroupSQL ( $group [ 'pattern' ], 'device_id=?' , $extra ) . ' LIMIT 1' , $params ) == $device_id ) {
2015-12-13 17:20:34 +00:00
if ( $extra === 0 ) {
$ret [] = $group [ 'id' ];
2016-08-28 12:32:58 -05:00
} else {
2015-12-13 17:20:34 +00:00
$ret [] = $group ;
}
2015-12-12 12:58:07 +00:00
}
}
return $ret ;
2016-06-02 12:37:03 -05:00
} //end QueryGroupsFromDevice()
/**
* Get the Device Group IDs of a Device from the database
* @ param $device_id
* @ param int $extra Return extra info about the groups ( name , desc , pattern )
* @ return array
*/
function GetGroupsFromDevice ( $device_id , $extra = 0 )
{
$ret = array ();
if ( $extra === 0 ) {
$ret = dbFetchColumn ( 'SELECT `device_group_id` FROM `device_group_device` WHERE `device_id`=?' , array ( $device_id ));
} else {
$ret = dbFetchRows ( 'SELECT `device_groups`.* FROM `device_group_device` LEFT JOIN `device_groups` ON `device_group_device`.`device_group_id`=`device_groups`.`id` WHERE `device_group_device`.`device_id`=?' , array ( $device_id ));
}
return $ret ;
} //end GetGroupsFromDeviceDB()
2015-12-12 12:58:07 +00:00
2015-07-15 19:55:57 +00:00
/**
* Process Macros
* @ param string $rule Rule to process
* @ param int $x Recursion - Anchor
* @ return string | boolean
*/
2016-08-28 12:32:58 -05:00
function RunGroupMacros ( $rule , $x = 1 )
{
2015-07-15 19:55:57 +00:00
global $config ;
krsort ( $config [ 'alert' ][ 'macros' ][ 'group' ]);
2016-08-28 12:32:58 -05:00
foreach ( $config [ 'alert' ][ 'macros' ][ 'group' ] as $macro => $value ) {
if ( ! strstr ( $macro , " " )) {
$rule = str_replace ( '%macros.' . $macro , '(' . $value . ')' , $rule );
2015-07-15 19:55:57 +00:00
}
}
2016-08-28 12:32:58 -05:00
if ( strstr ( $rule , " %macros " )) {
if ( ++ $x < 30 ) {
$rule = RunGroupMacros ( $rule , $x );
2015-07-15 19:55:57 +00:00
} else {
return false ;
}
}
return $rule ;
} //end RunGroupMacros()
2016-06-02 12:37:03 -05:00
/**
* Update device - group relationship for the given device id
* @ param $device_id
*/
function UpdateGroupsForDevice ( $device_id )
{
2016-09-27 11:50:52 -05:00
d_echo ( " ### Start Device Groups ### \n " );
2016-06-02 12:37:03 -05:00
$queried_groups = QueryGroupsFromDevice ( $device_id );
$db_groups = GetGroupsFromDevice ( $device_id );
// compare the arrays to get the added and removed groups
$added_groups = array_diff ( $queried_groups , $db_groups );
$removed_groups = array_diff ( $db_groups , $queried_groups );
2016-09-27 11:50:52 -05:00
d_echo ( " Groups Added: " . implode ( ',' , $added_groups ) . PHP_EOL );
d_echo ( " Groups Removed: " . implode ( ',' , $removed_groups ) . PHP_EOL );
2016-06-02 12:37:03 -05:00
// insert new groups
$insert = array ();
foreach ( $added_groups as $group_id ) {
$insert [] = array ( 'device_id' => $device_id , 'device_group_id' => $group_id );
}
if ( ! empty ( $insert )) {
dbBulkInsert ( $insert , 'device_group_device' );
}
// remove old groups
if ( ! empty ( $removed_groups )) {
dbDelete ( 'device_group_device' , '`device_id`=? AND `device_group_id` IN (?)' , array ( $device_id , array ( implode ( ',' , $removed_groups ))));
}
2016-09-27 11:50:52 -05:00
d_echo ( " ### End Device Groups ### \n " );
2016-06-02 12:37:03 -05:00
}
/**
* Update the device - group relationship for the given group id
* @ param $group_id
*/
function UpdateDeviceGroup ( $group_id )
{
$queried_devices = QueryDevicesFromGroup ( $group_id );
$db_devices = GetDevicesFromGroup ( $group_id );
// compare the arrays to get the added and removed devices
$added_devices = array_diff ( $queried_devices , $db_devices );
$removed_devices = array_diff ( $db_devices , $queried_devices );
// insert new devices
$insert = array ();
foreach ( $added_devices as $device_id ) {
$insert [] = array ( 'device_id' => $device_id , 'device_group_id' => $group_id );
}
if ( ! empty ( $insert )) {
dbBulkInsert ( $insert , 'device_group_device' );
}
// remove old devices
if ( ! empty ( $removed_devices )) {
dbDelete ( 'device_group_device' , '`device_group_id`=? AND `device_id` IN (?)' , array ( $group_id , array ( implode ( ',' , $removed_devices ))));
}
}
2016-09-27 11:50:52 -05:00
/**
* Fill in params into the pattern , replacing placeholders ( ? )
* If $params is empty or null , just returns $pattern
*
* @ return string
*/
function formatDeviceGroupPattern ( $pattern , $params )
{
// fill in parameters
foreach (( array ) $params as $value ) {
if ( ! is_numeric ( $value ) && ! starts_with ( $value , " ' " )) {
$value = " ' " . $value . " ' " ;
}
$pattern = preg_replace ( '/\?/' , $value , $pattern , 1 );
}
return $pattern ;
}