Details
-
Improvement
-
Resolution: Fixed
-
Minor
-
None
-
Professional Edition
Description
We're using ansible to configure our servers and use a python script, that pulls information off the observium database for that task.
In order to group servers more effectively for hierarchical playbooks, I wanted nested groups.
I added support for nested groups in `includes\alerts.inc.php` (and I think I also solved the `// FIXME, what is this?` ).
I had to change the sql query a bit to allow for joins - that's why the patch affects that many lines - it actually isn't that big.
Usage:
In device rules simply add the following for example:
group includes vpnservers
One thing's still to do: You need to rebuild the groups again if one of the groups a include-rule relies on has changed after the include-rule has been updated.
I would've added it already but I'm not yet familiar with the codebase of observium yet and haven't found all the code that does the group building yet.
This is a start though
Attachments
Activity
I could think about it. But I don't have time in the next 3-4 weeks.
What do you mean by "rather build lists of entities"?
Any interest in extending this to allow excluding by group? (I think it might well be simpler to not use JOINS, and rather build lists of entities for each group)
Code warnings:
- NO camelCase variable name;
- IMPORTANT! array() instead [];
- TRUE instead true;
- in sql USING better than ON for common fields;
for(i++) is mandatory there because the size of $groups_index changes and foreach doesn't notice that.
Also check this code snippet for reference:
http://sandbox.onlinephpfunctions.com/code/53cbecd4712e3fc3712c46ab9f452e7133cf2625
We really needed this feature completed and so I tried to understand as much of the function 'update_device_group_table($device)' in 'includes/groups.inc.php' as I could and needed to find the problem.
The problem was actually in my modified version of cache_device_groups($device) but I didn't understand it until I learned more about update_device_group_table. The latter function accesses a part of the array returned by cache_device_groups that I wasn't including anymore because for my code snippets, it wasn't important.
Nested groups work completely now.
Let's say you have 3 levels of groups:
- vpn basic:
matched via regex on hostname
- vpn secure:
matched via regex on hostname
- vpnservers:
group includes vpn secure
group includes vpn basic
- servers:
group includes vpnservers
(imagine other group include statements)
Now, if you remove the "group includes vpn basic" rule or change the regex to not match the "vpn basic" hosts anymore, those hosts will be removed from vpnservers and servers immediately on next rebuild.
If you revert those changes and run rebuild again, the hosts will be back in those groups immediately.
I've tested this in our environment a few times
Also, @Adam Armstrong, I've renamed the $sel variable to $select for your proper variable naming pleasure
I think I need some additional information on groups, because, sadly, the documentation isn't very clear about this.
In order to implement a group rebuild, that wouldn't take multiple runs to populate all groups that include other groups, I've patched the function 'cache_device_groups($device)' in includes/groups.inc.php (see code below).
When I rebuild groups, output suggests, that it's working for groups but not on entities ("vpnservers" should also be assigned in entities and will be if I rerun the rebuild):
What is the difference between groups and entities here?
Is the difference between groups and entities here the same as it is when defining a rule for a group?
Or in general: what is the purpose of the entity filter?
/**
|
* Build an array of groups that apply to a supplied device
|
*
|
* This takes the array of global conditions and removes associations that don't match the supplied device array
|
*
|
* @param array device
|
* @return array
|
*/
|
// TESTME needs unit testing
|
function cache_device_groups($device) |
{
|
// Return no conditions if the device is ignored or disabled. |
// This is not really relevant to the groups system |
//if ($device['ignore'] == 1 || $device['disabled'] == 1) { return array(); } |
|
$groups = cache_groups(); |
$recursiveRules = []; // will hold all recursive rules |
$groups_index = []; // a zero based index of all applied groups |
// as opposed to the group_id based index of groups in $groups_new |
|
//DEVREMOVE |
echo "groups:<br>\n"; |
//krumo($groups); |
var_dump($groups); |
|
foreach ($groups['assoc'] as $assoc_key => $assoc) |
{
|
// Save rule if it's recursive for later checkings |
$condition = $assoc['device_attribs'][0]['condition']; |
if (preg_match('#include[s]?#i', $condition)) { |
$recursiveRules[$assoc_key] = $assoc; |
}
|
|
// Build group array |
if (match_device($device, $assoc['device_attribs'], FALSE)) |
{
|
$assoc['group_id']; |
$groups['group'][$assoc['group_id']]['assoc'][$assoc_key] = $groups['assoc'][$assoc_key]; |
$groups_new['group'][$assoc['group_id']] = $groups['group'][$assoc['group_id']]; |
$groups_index[] = $groups['group'][$assoc['group_id']]; |
} else { |
unset($groups['assoc'][$assoc_key]); |
}
|
}
|
|
echo "rules:<br>\n"; |
//krumo($recursiveRules); |
var_dump($recursiveRules); |
|
// Process recursive rules |
// This will loop through all already applied groups and those groups |
// that will be applied through recursive rules to check for new |
// recursive rules that apply. |
for ($i=0; $i<count($groups_index); $i++) { |
$rules = []; |
$group_name = $groups_index[$i]['group_name']; |
|
foreach ($recursiveRules as $rec) { |
// check if rule targets the group |
$attribs = $rec['device_attribs'][0]; |
echo "Comparing $group_name with rule:<br>\n"; //DR |
var_dump($attribs); //DR |
if (strcmp($attribs['value'], $group_name) == 0) { |
$rules[] = $rec; |
echo "<br><b>found!</b>"; //DR |
}
|
echo "<br><br>"; //DR |
}
|
|
// process found rules! |
if (count($rules) != 0) { |
foreach($rules as $rule) { |
$done = false; |
// check if recursive rule is already applied (and avoid endless loops) |
foreach($groups_index as $compare) { |
if (strcmp($compare['group_name'], $groups['group'][$rule['group_id']]['group_name']) == 0) { |
// device is already in that group |
$done = true; |
break; |
}
|
}
|
|
// add new group |
if (!$done) { |
echo "Adding device to group: ".$groups['group'][$rule['group_id']]['group_name']."!<br>"; //DR |
$groups_new['group'][$rule['group_id']] = $groups['group'][$rule['group_id']]; |
$groups_index[] = $groups['group'][$rule['group_id']]; |
}
|
}
|
} // end: rules found and processed |
}
|
|
//DEVREMOVE |
echo "groups new:<br>\n"; |
//krumo($groups_new); |
var_dump($groups_new); |
|
return $groups_new; |
}
|
(I will remove my debug output stuff ofc when I hand this in as a patch)
You can rename sel to select or something if you want ^^
Yes, I have tested this and it works
@adama could you explain what you meant by saying "rather build lists of entities"?
I could already start thinking about the implementation if I had more information.