feature: Application auto discovery (#6143)

This commit is contained in:
Tony Murray
2017-03-22 09:59:39 -05:00
committed by Neil Lathwood
parent 4e40314a3a
commit e7057ecea5
8 changed files with 243 additions and 85 deletions

View File

@ -0,0 +1,56 @@
<?php
/**
* application-update.php
*
* Handle application enable disable from ajax
*
* 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/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2017 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
if (is_admin() === false) {
$status = array('status' => 1, 'message' => 'You need to be admin');
} else {
$device_id = $_POST['device_id'];
$app = $_POST['application'];
if (!isset($app) && validate_device_id($device_id) === false) {
$status = array('status' => 1, 'message' => 'Error with data');
} else {
$status = array('status' => 1, 'message' => 'Database update failed');
if ($_POST['state'] == 'true') {
$update = array(
'device_id' => $device_id,
'app_type' => $app,
'app_status' => '',
'app_instance' => ''
);
if (dbInsert($update, 'applications')) {
log_event("Application enabled by user: $app", $device_id, 'application', 1);
$status = array('status' => 0, 'message' => 'Application enabled');
}
} else {
if (dbDelete('applications', '`device_id`=? AND `app_type`=?', array($device_id, $app))) {
log_event("Application disabled by user: $app", $device_id, 'application', 3);
$status = array('status' => 0, 'message' => 'Application disabled');
}
}
}
}
header('Content-Type: application/json');
echo _json_encode($status);

View File

@ -2,95 +2,68 @@
<?php
// Load our list of available applications
foreach (scandir($config['install_dir'].'/includes/polling/applications/') as $file) {
if (substr($file, -8) == '.inc.php') {
$applications[] = substr($file, 0, -8);
}
$applications = array();
foreach (glob($config['install_dir'] . '/includes/polling/applications/*.inc.php') as $file) {
$name = basename($file, '.inc.php');
$applications[$name] = $name;
}
// Check if the form was POSTed
if ($_POST['device']) {
$updated = 0;
$param[] = $device['device_id'];
foreach (array_keys($_POST) as $key) {
if (substr($key, 0, 4) == 'app_') {
$param[] = substr($key, 4);
$enabled[] = substr($key, 4);
$replace[] = '?';
}
}
// Generate a list of enabled apps with a value of whether they are discovered or not
$enabled_apps = array_reduce(dbFetchRows(
'SELECT `app_type`,`discovered` FROM `applications` WHERE `device_id`=? ORDER BY `app_type`',
array($device['device_id'])
), function ($result, $app) {
$result[$app['app_type']] = $app['discovered'];
return $result;
}, array());
if (count($enabled)) {
$updated += dbDelete('applications', '`device_id` = ? AND `app_type` NOT IN ('.implode(',', $replace).')', $param);
} else {
$updated += dbDelete('applications', '`device_id` = ?', array($param));
}
foreach (dbFetchRows('SELECT `app_type` FROM `applications` WHERE `device_id` = ?', array($device['device_id'])) as $row) {
$app_in_db[] = $row['app_type'];
}
foreach ($enabled as $app) {
if (!in_array($app, $app_in_db)) {
$updated += dbInsert(array('device_id' => $device['device_id'], 'app_type' => $app, 'app_status' => '', 'app_instance' => ''), 'applications');
}
}
if ($updated) {
print_message('Applications updated!');
} else {
print_message('No changes.');
}
}//end if
// Show list of apps with checkboxes
echo '<div style="padding: 10px;">';
$apps_enabled = dbFetchRows('SELECT * from `applications` WHERE `device_id` = ? ORDER BY app_type', array($device['device_id']));
if (count($apps_enabled)) {
foreach ($apps_enabled as $application) {
$app_enabled[] = $application['app_type'];
}
}
echo "<div class='row'>
<div class='col-md-4'>
<form id='appedit' name='appedit' method='post' action='' role='form' class='form-horizontal'>
<input type=hidden name=device value='".$device['device_id']."'>
<table class='table table-hover table-responsive'>
<tr align=center>
<th>Enable</th>
<th>Application</th>
</tr>
";
$row = 1;
echo '<ul class="list-group row">';
foreach ($applications as $app) {
if (is_integer($row / 2)) {
$row_colour = $list_colour_a;
} else {
$row_colour = $list_colour_b;
$modifiers = '';
$app_text = nicecase($app);
// check if the app exists in the enable apps array and check if it was automatically enabled
if (isset($enabled_apps[$app])) {
$modifiers = ' checked';
if ($enabled_apps[$app]) {
$app_text .= '<span class="text-success"> (Discovered)</span>';
$modifiers .= ' disabled';
}
}
echo " <tr bgcolor=$row_colour>";
echo ' <td>';
echo ' <input type=checkbox'.(in_array($app, $app_enabled) ? ' checked="1"' : '')." name='app_".$app."'>";
echo ' </td>';
echo ' <td>'.nicecase($app).'</td>';
echo ' </tr>
';
$row++;
echo '<li class="list-group-item col-xs-12 col-md-6 col-lg-4">';
echo "<input style='visibility:hidden;width:100px;' type='checkbox' name='application' data-size='small'";
echo " data-application='$app' data-device_id='{$device['device_id']}'$modifiers>";
echo '<span style="font-size:medium;padding-left:5px;"> ' . $app_text . '</span>';
echo '</li>';
}
echo '</table>';
echo '<div class="row">
<div class="col-md-1">
<button type="submit" name="Submit" class="btn btn-default"><i class="fa fa-check"></i> Save</button>
</div>
</div>
';
echo '</form>';
echo '</div>';
echo '</div>';
echo '</ul>';
?>
<script>
$('[name="application"]').bootstrapSwitch('offColor', 'danger');
$('input[name="application"]').on('switchChange.bootstrapSwitch', function (event, state) {
event.preventDefault();
var $this = $(this);
var application = $this.data("application");
var device_id = $this.data("device_id");
$.ajax({
type: 'POST',
url: 'ajax_form.php',
data: {type: "application-update", application: application, device_id: device_id, state: state},
success: function(result){
if (result.status == 0) {
toastr.success(result.message);
} else {
toastr.error(result.message);
$this.bootstrapSwitch('state', !state, true);
}
},
error: function () {
toastr.error('Problem with backend');
$this.bootstrapSwitch('state', !state, true);
}
});
});
</script>

View File

@ -77,7 +77,8 @@ foreach ($poller_modules as $module => $module_status) {
<td>
');
echo('<input type="checkbox" name="poller-module" data-poller_module="'.$module.'" data-device_id="'.$device['device_id'].'" '.$module_checked.'>');
echo '<input type="checkbox" style="visibility:hidden;width:100px;" name="poller-module" data-poller_module="'
.$module.'" data-device_id="'.$device['device_id'].'" '.$module_checked.'>';
echo('
</td>
@ -159,7 +160,8 @@ foreach ($discovery_modules as $module => $module_status) {
</td>
<td>');
echo('<input type="checkbox" name="discovery-module" data-discovery_module="'.$module.'" data-device_id="'.$device['device_id'].'" '.$module_checked.'>');
echo '<input type="checkbox" style="visibility:hidden;width:100px;" name="discovery-module" data-discovery_module="'
.$module.'" data-device_id="'.$device['device_id'].'" '.$module_checked.'>';
echo('
</td>

View File

@ -769,6 +769,7 @@ $config['discovery_modules']['vmware-vminfo'] = 0;
$config['discovery_modules']['libvirt-vminfo'] = 0;
$config['discovery_modules']['toner'] = 0;
$config['discovery_modules']['ucd-diskio'] = 1;
$config['discovery_modules']['applications'] = 0;
$config['discovery_modules']['services'] = 1;
$config['discovery_modules']['stp'] = 1;
$config['discovery_modules']['ntp'] = 1;

View File

@ -6,3 +6,5 @@ processor_stacked: 1
over:
- { graph: device_processor, text: 'Processor Usage' }
- { graph: device_ucd_memory, text: 'Memory Usage' }
discovery_modules:
applications: 1

View File

@ -15,6 +15,7 @@ poller_modules:
ospf: 0
stp: 0
discovery_modules:
applications: 1
bgp-peers: 0
stp: 0
vmware-vminfo: 1

View File

@ -0,0 +1,120 @@
<?php
/**
* applications.inc.php
*
* Discover applications
*
* 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/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2016 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
echo "\nApplications: ";
// fetch applications from the client
$results = snmpwalk_cache_oid($device, 'nsExtendStatus', array(), 'NET-SNMP-EXTEND-MIB');
// Load our list of available applications
$applications = array();
if ($results) {
foreach (glob($config['install_dir'] . '/includes/polling/applications/*.inc.php') as $file) {
$name = basename($file, '.inc.php');
$applications[$name] = $name;
}
// fix applications that don't match their snmp extend name
$applications['dhcpstats'] = 'dhcp-stats';
$applications['fbsdnfsclient'] = 'fbsd-nfs-client';
$applications['fbsdnfsserver'] = 'fbsd-nfs-server';
$applications['mailq'] = 'postfix';
$applications['osupdate'] = 'os-updates';
$applications['phpfpmsp'] = 'php-fpm';
$applications['postfixdetailed'] = 'postfix';
}
d_echo(PHP_EOL . 'Available: ' . implode(', ', array_keys($applications)) . PHP_EOL);
d_echo('Checking for: ' . implode(', ', array_keys($results)) . PHP_EOL);
// Generate a list of enabled apps and a list of all discovered apps from the db
list($enabled_apps, $discovered_apps) = array_reduce(dbFetchRows(
'SELECT `app_type`,`discovered` FROM `applications` WHERE `device_id`=? ORDER BY `app_type`',
array($device['device_id'])
), function ($result, $app) {
$result[0][] = $app['app_type'];
if ($app['discovered']) {
$result[1][] = $app['app_type'];
}
return $result;
}, array(array(), array()));
// Enable applications
$current_apps = array();
foreach ($results as $extend => $result) {
if (isset($applications[$extend])) {
$app = $applications[$extend];
$current_apps[] = $app;
if (in_array($app, $enabled_apps)) {
echo '.';
} else {
dbInsert(array(
'device_id' => $device['device_id'],
'app_type' => $app,
'discovered' => 1,
'app_status' => '',
'app_instance' => ''
), 'applications');
echo '+';
log_event("Application enabled by discovery: $app", $device, 'application', 1);
}
}
}
// remove non-existing apps
$apps_to_remove = array_diff($discovered_apps, $current_apps);
$num = count($apps_to_remove);
if ($num > 0) {
echo str_repeat('-', $num);
$vars = $apps_to_remove;
array_unshift($vars, $device['device_id']);
dbDelete(
'applications',
'`device_id`=? AND `app_type` IN (' . implode(',', array_fill(0, $num, '?')) . ')',
$vars
);
foreach ($apps_to_remove as $app) {
log_event("Application disabled by discovery: $app", $device, 'application', 3);
}
}
echo PHP_EOL;
unset(
$applications,
$enabled_apps,
$discovered_apps,
$current_apps,
$apps_to_remove,
$results,
$file,
$name,
$extend,
$app,
$num
);

3
sql-schema/181.sql Normal file
View File

@ -0,0 +1,3 @@
ALTER TABLE `applications` CHANGE `app_state_prev` `app_state_prev` VARCHAR(32) NULL;
ALTER TABLE `applications` ADD `discovered` TINYINT NOT NULL DEFAULT '0' AFTER `app_state`;
ALTER IGNORE TABLE `applications` ADD UNIQUE `unique_index`(`device_id`, `app_type`);