From 009840bf8a08e4b202b756905306e96628f5de88 Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Thu, 2 Jun 2016 12:37:03 -0500 Subject: [PATCH 1/2] Store device group relationships in a pivot table. --- html/includes/api_functions.inc.php | 2 +- .../forms/create-device-group.inc.php | 6 +- html/includes/table/devices.inc.php | 2 +- html/pages/devices.inc.php | 2 +- includes/device-groups.inc.php | 162 ++++++++++++++++-- includes/polling/functions.inc.php | 4 + sql-schema/116.sql | 11 ++ 7 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 sql-schema/116.sql diff --git a/html/includes/api_functions.inc.php b/html/includes/api_functions.inc.php index e559dfcd9a..75aa966bbf 100644 --- a/html/includes/api_functions.inc.php +++ b/html/includes/api_functions.inc.php @@ -1271,7 +1271,7 @@ function get_devices_by_group() { } else { $group_id = dbFetchCell("SELECT `id` FROM `device_groups` WHERE `name`=?",array($name)); - $devices = GetDevicesFromGroup($group_id); + $devices = GetDevicesFromGroup($group_id, true); $count = count($devices); if (empty($devices)) { $message = 'No devices found in group ' . $name; diff --git a/html/includes/forms/create-device-group.inc.php b/html/includes/forms/create-device-group.inc.php index ef82a16394..03f90ca3f5 100644 --- a/html/includes/forms/create-device-group.inc.php +++ b/html/includes/forms/create-device-group.inc.php @@ -16,6 +16,8 @@ if (is_admin() === false) { die('ERROR: You need to be admin'); } +require_once '../includes/device-groups.inc.php'; + $pattern = $_POST['patterns']; $group_id = $_POST['group_id']; $name = mres($_POST['name']); @@ -38,7 +40,7 @@ if (empty($pattern)) { $update_message = 'ERROR: No group was generated'; } else if (is_numeric($group_id) && $group_id > 0) { - if (dbUpdate(array('pattern' => $pattern, 'name' => $name, 'desc' => $desc), 'device_groups', 'id=?', array($group_id)) >= 0) { + if (EditDeviceGroup($group_id, $name, $desc, $pattern)) { $update_message = "Edited Group: $name: $pattern"; } else { @@ -46,7 +48,7 @@ else if (is_numeric($group_id) && $group_id > 0) { } } else { - if (dbInsert(array('pattern' => $pattern, 'name' => $name, 'desc' => $desc), 'device_groups')) { + if (AddDeviceGroup($name, $desc, $pattern)) { $update_message = "Added Group: $name: $pattern"; } else { diff --git a/html/includes/table/devices.inc.php b/html/includes/table/devices.inc.php index e84c5dfdd9..3ebcf7a44c 100644 --- a/html/includes/table/devices.inc.php +++ b/html/includes/table/devices.inc.php @@ -87,7 +87,7 @@ if (!empty($_POST['group'])) { $sql .= ' AND ( '; foreach (GetDevicesFromGroup($_POST['group']) as $dev) { $sql .= '`devices`.`device_id` = ? OR '; - $param[] = $dev['device_id']; + $param[] = $dev; } $sql = substr($sql, 0, (strlen($sql) - 3)); diff --git a/html/pages/devices.inc.php b/html/pages/devices.inc.php index 6d446d5c1d..61f5d1d15d 100644 --- a/html/pages/devices.inc.php +++ b/html/pages/devices.inc.php @@ -200,7 +200,7 @@ if($format == "graph") { $where .= " AND ( "; foreach( GetDevicesFromGroup($vars['group']) as $dev ) { $where .= "device_id = ? OR "; - $sql_param[] = $dev['device_id']; + $sql_param[] = $dev; } $where = substr($where, 0, strlen($where)-3); $where .= " )"; diff --git a/includes/device-groups.inc.php b/includes/device-groups.inc.php index 3624db490c..c4651e59ee 100644 --- a/includes/device-groups.inc.php +++ b/includes/device-groups.inc.php @@ -18,13 +18,59 @@ /** * Device-Grouping * @author Daniel Preussker - * @copyright 2015 f0o, LibreNMS + * @author Tony Murray + * @copyright 2016 f0o, murrant, LibreNMS * @license GPL * @package LibreNMS * @subpackage Devices */ +/** + * 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; +} + /** * Generate SQL from Group-Pattern * @param string $pattern Pattern to generate SQL for @@ -77,22 +123,38 @@ function GenGroupSQL($pattern, $search='',$extra=0) { /** - * Get all devices of Group + * Run the group queries again to get fresh list of devices for this group * @param integer $group_id Group-ID * @return string */ -function GetDevicesFromGroup($group_id) { - $pattern = dbFetchCell('SELECT pattern FROM device_groups WHERE id = ?', array($group_id)); +function QueryDevicesFromGroup($group_id) +{ + $pattern = dbFetchCell('SELECT pattern FROM device_groups WHERE id = ?', array($group_id)); $pattern = rtrim($pattern, '&&'); $pattern = rtrim($pattern, '||'); if (!empty($pattern)) { - return dbFetchRows(GenGroupSQL($pattern)); + return dbFetchColumn(GenGroupSQL($pattern)); } return false; -}//end GetDevicesFromGroup() +}//end QueryDevicesFromGroup() +/** + * 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) + * @return array + */ +function GetDevicesFromGroup($group_id, $nested = false) +{ + $query = 'SELECT `device_id` FROM `device_group_device` WHERE `device_group_id`=?'; + if ($nested) { + return dbFetchRows($query, array($group_id)); + } else { + return dbFetchColumn($query, array($group_id)); + } +}//end GetDevicesFromGroup() /** * Get all Device-Groups @@ -104,14 +166,15 @@ function GetDeviceGroups() { }//end GetDeviceGroups() /** - * Get all groups of Device - * @param integer $device Device-ID + * 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) * @return array */ -function GetGroupsFromDevice($device,$extra=0) { +function QueryGroupsFromDevice($device_id,$extra=0) { $ret = array(); foreach (GetDeviceGroups() as $group) { - if (dbFetchCell(GenGroupSQL($group['pattern'], 'device_id=?',$extra).' LIMIT 1', array($device)) == $device) { + if (dbFetchCell(GenGroupSQL($group['pattern'], 'device_id=?',$extra).' LIMIT 1', array($device_id)) == $device_id) { if ($extra === 0) { $ret[] = $group['id']; } @@ -123,7 +186,24 @@ function GetGroupsFromDevice($device,$extra=0) { return $ret; -}//end GetGroupsFromDevice() +}//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() /** * Process Macros @@ -148,3 +228,63 @@ function RunGroupMacros($rule,$x=1) { } return $rule; }//end RunGroupMacros() + + +/** + * Update device-group relationship for the given device id + * @param $device_id + */ +function UpdateGroupsForDevice($device_id) +{ + global $debug; + $debug = true; + $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); + + // 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)))); + } + +} + +/** + * 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)))); + } +} diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index e3ad021cac..bb6ef9cc14 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -1,5 +1,6 @@ Date: Thu, 2 Jun 2016 16:22:17 -0500 Subject: [PATCH 2/2] SQL query on one line --- sql-schema/116.sql | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sql-schema/116.sql b/sql-schema/116.sql index 7d74618a6b..800a240246 100644 --- a/sql-schema/116.sql +++ b/sql-schema/116.sql @@ -1,11 +1,3 @@ ALTER TABLE `devices` CHANGE `device_id` `device_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT; ALTER TABLE `device_groups` CHANGE `id` `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT; -CREATE TABLE `device_group_device` ( - `device_group_id` int(10) unsigned NOT NULL, - `device_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`device_group_id`,`device_id`), - KEY `device_group_device_device_group_id_index` (`device_group_id`), - KEY `device_group_device_device_id_index` (`device_id`), - CONSTRAINT `device_group_device_device_group_id_foreign` FOREIGN KEY (`device_group_id`) REFERENCES `device_groups` (`id`) ON DELETE CASCADE, - CONSTRAINT `device_group_device_device_id_foreign` FOREIGN KEY (`device_id`) REFERENCES `devices` (`device_id`) ON DELETE CASCADE -); +CREATE TABLE `device_group_device` (`device_group_id` int(10) unsigned NOT NULL, `device_id` int(10) unsigned NOT NULL, PRIMARY KEY (`device_group_id`,`device_id`), KEY `device_group_device_device_group_id_index` (`device_group_id`), KEY `device_group_device_device_id_index` (`device_id`), CONSTRAINT `device_group_device_device_group_id_foreign` FOREIGN KEY (`device_group_id`) REFERENCES `device_groups` (`id`) ON DELETE CASCADE, CONSTRAINT `device_group_device_device_id_foreign` FOREIGN KEY (`device_id`) REFERENCES `devices` (`device_id`) ON DELETE CASCADE);