mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Graphing Device Dependency (#10916)
* graphing Device Dependency * remove uneeded code * fix link to go to device Overview * rebuild dependency map to blade/laravel * remove uneeded file * code climate fixes * remove not used code * remove blank line * device access filter optimization * remove blank line * force new travis check ... * fix deviceLink configuration * . * rewrite code * moving to Maps Namespace * retrigger tests * some code changes * further renaming * retrigger tests * some code improvements * . * move vis.min.js in javascript section * Device Dependency for Device Groups * . * codeclimate fixes * show child/parents of Device - even if not in Device Group * Device Highlighting * add missing function * replace hardcoded get params with ->get in Controller * redesign Controller * code climate fixes * fix binary operator to 'or' * remove 'or' * code climate fixes * further Code changes * move loadMissing behind merge
This commit is contained in:
106
app/Http/Controllers/Maps/DeviceDependencyController.php
Normal file
106
app/Http/Controllers/Maps/DeviceDependencyController.php
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DependencyController.php
|
||||||
|
*
|
||||||
|
* Controller for graphing Relationships
|
||||||
|
*
|
||||||
|
* 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 2019 Thomas Berberich
|
||||||
|
* @author Thomas Berberich <sourcehhdoctor@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Maps;
|
||||||
|
|
||||||
|
use App\Models\Device;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use LibreNMS\Util\Url;
|
||||||
|
|
||||||
|
class DeviceDependencyController extends MapController
|
||||||
|
{
|
||||||
|
protected static function deviceList($request)
|
||||||
|
{
|
||||||
|
$group_id = $request->get('group');
|
||||||
|
|
||||||
|
if (! $group_id) {
|
||||||
|
return Device::hasAccess($request->user())->with('parents', 'location')->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
$devices = Device::inDeviceGroup($group_id)
|
||||||
|
->hasAccess($request->user())
|
||||||
|
->with([
|
||||||
|
'location',
|
||||||
|
'parents' => function ($query) use ($request) {
|
||||||
|
$query->hasAccess($request->user());
|
||||||
|
},
|
||||||
|
'children' => function ($query) use ($request) {
|
||||||
|
$query->hasAccess($request->user());
|
||||||
|
}])
|
||||||
|
->get();
|
||||||
|
return $devices->merge($devices->map->only('children', 'parents')->flatten())->loadMissing('parents', 'location');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device Dependency Map
|
||||||
|
public function dependencyMap(Request $request)
|
||||||
|
{
|
||||||
|
$group_id = $request->get('group');
|
||||||
|
$highlight_node = $request->get('highlight_node');
|
||||||
|
|
||||||
|
$dependencies = [];
|
||||||
|
$devices_by_id = [];
|
||||||
|
$device_list = [];
|
||||||
|
|
||||||
|
// List all devices
|
||||||
|
foreach (self::deviceList($request) as $device) {
|
||||||
|
$device_list[] = ['id' => $device->device_id, 'label' => $device->hostname];
|
||||||
|
|
||||||
|
// List all Device
|
||||||
|
$devices_by_id[] = array_merge(
|
||||||
|
[
|
||||||
|
'id' => $device->device_id,
|
||||||
|
'label' => $device->shortDisplayName(),
|
||||||
|
'title' => Url::deviceLink($device, null, [], 0, 0, 0, 0),
|
||||||
|
'shape' => 'box',
|
||||||
|
],
|
||||||
|
$this->deviceStyle($device, $highlight_node)
|
||||||
|
);
|
||||||
|
|
||||||
|
// List all Device Dependencies
|
||||||
|
$parents = $device->parents;
|
||||||
|
foreach ($parents as $parent) {
|
||||||
|
$dependencies[] = [
|
||||||
|
'from' => $device->device_id,
|
||||||
|
'to' => $parent->device_id,
|
||||||
|
'width' => 2,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
array_multisort(array_column($device_list, 'label'), SORT_ASC, $device_list);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'device_list' => $device_list,
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'highlight_node' => $highlight_node,
|
||||||
|
'node_count' => count($devices_by_id),
|
||||||
|
'options' => $this->visOptions(),
|
||||||
|
'nodes' => json_encode(array_values($devices_by_id)),
|
||||||
|
'edges' => json_encode($dependencies),
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('map.device-dependency', $data);
|
||||||
|
}
|
||||||
|
}
|
96
app/Http/Controllers/Maps/MapController.php
Normal file
96
app/Http/Controllers/Maps/MapController.php
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DependencyController.php
|
||||||
|
*
|
||||||
|
* Controller for graphing Relationships
|
||||||
|
*
|
||||||
|
* 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 2019 Thomas Berberich
|
||||||
|
* @author Thomas Berberich <sourcehhdoctor@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Maps;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use LibreNMS\Config;
|
||||||
|
|
||||||
|
class MapController extends Controller
|
||||||
|
{
|
||||||
|
protected function visOptions()
|
||||||
|
{
|
||||||
|
return Config::get('network_map_vis_options');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function nodeDisabledStyle()
|
||||||
|
{
|
||||||
|
return ['color' => [
|
||||||
|
'highlight' => [
|
||||||
|
'background' => Config::get('network_map_legend.di.node'),
|
||||||
|
],
|
||||||
|
'border' => Config::get('network_map_legend.di.border'),
|
||||||
|
'background' => Config::get('network_map_legend.di.node'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function nodeHighlightStyle()
|
||||||
|
{
|
||||||
|
return ['color' => [
|
||||||
|
'highlight' => [
|
||||||
|
'border' => Config::get('network_map_legend.highlight.border'),
|
||||||
|
],
|
||||||
|
'border' => Config::get('network_map_legend.highlight.border'),
|
||||||
|
],
|
||||||
|
'borderWidth' => Config::get('network_map_legend.highlight.borderWidth'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function nodeDownStyle()
|
||||||
|
{
|
||||||
|
return ['color' => [
|
||||||
|
'highlight' => [
|
||||||
|
'background' => Config::get('network_map_legend.dn.node'),
|
||||||
|
'border' => Config::get('network_map_legend.dn.border'),
|
||||||
|
],
|
||||||
|
'border' => Config::get('network_map_legend.dn.border'),
|
||||||
|
'background' => Config::get('network_map_legend.dn.node'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function nodeUpStyle()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function deviceStyle($device, $highlight_node = 0)
|
||||||
|
{
|
||||||
|
if ($device->disabled) {
|
||||||
|
$device_style = $this->nodeDisabledStyle();
|
||||||
|
} elseif (! $device->status) {
|
||||||
|
$device_style = $this->nodeDownStyle();
|
||||||
|
} else {
|
||||||
|
$device_style = $this->nodeUpStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($device->device_id == $highlight_node) {
|
||||||
|
$device_style = array_merge($device_style, $this->nodeHighlightStyle());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $device_style;
|
||||||
|
}
|
||||||
|
}
|
@@ -34,6 +34,20 @@
|
|||||||
<li><a href="{{ url('availability-map') }}"><i class="fa fa-arrow-circle-up fa-fw fa-lg"
|
<li><a href="{{ url('availability-map') }}"><i class="fa fa-arrow-circle-up fa-fw fa-lg"
|
||||||
aria-hidden="true"></i> @lang('Availability')
|
aria-hidden="true"></i> @lang('Availability')
|
||||||
</a></li>
|
</a></li>
|
||||||
|
<li><a href="{{ url('maps/devicedependency') }}"><i class="fa fa-chain fa-fw fa-lg"
|
||||||
|
aria-hidden="true"></i> @lang('Device Dependency')</a></li>
|
||||||
|
@if($device_groups->isNotEmpty())
|
||||||
|
<li class="dropdown-submenu"><a><i class="fa fa-chain fa-fw fa-lg"
|
||||||
|
aria-hidden="true"></i> @lang('Device Groups Dependencies')
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu scrollable-menu">
|
||||||
|
@foreach($device_groups as $group)
|
||||||
|
<li><a href="{{ url("maps/devicedependency?group=$group->id") }}" title="{{ $group->desc }}"><i class="fa fa-chain fa-fw fa-lg" aria-hidden="true"></i>
|
||||||
|
{{ ucfirst($group->name) }}
|
||||||
|
</a></li>
|
||||||
|
@endforeach
|
||||||
|
</ul></li>
|
||||||
|
@endif
|
||||||
<li><a href="{{ url('map') }}"><i class="fa fa-sitemap fa-fw fa-lg"
|
<li><a href="{{ url('map') }}"><i class="fa fa-sitemap fa-fw fa-lg"
|
||||||
aria-hidden="true"></i> @lang('Network')</a></li>
|
aria-hidden="true"></i> @lang('Network')</a></li>
|
||||||
@if($device_groups->isNotEmpty())
|
@if($device_groups->isNotEmpty())
|
||||||
|
59
resources/views/map/device-dependency.blade.php
Normal file
59
resources/views/map/device-dependency.blade.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
@extends('layouts.librenmsv1')
|
||||||
|
|
||||||
|
@section('title', __('Device Dependency Map'))
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
@if($node_count)
|
||||||
|
<div class="pull-right">
|
||||||
|
<select name="highlight_node" id="highlight_node" class="input-sm" onChange="highlightNode()";>
|
||||||
|
<option value="0">None</option>
|
||||||
|
@foreach($device_list as $device)
|
||||||
|
<option value="{{ $device['id'] }}">{{ $device['label'] }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div id="visualization"></div>
|
||||||
|
@else
|
||||||
|
<div class="alert alert-success" role="alert">@lang('No devices found')</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('javascript')
|
||||||
|
<script type="text/javascript" src="{{ asset('js/vis.min.js') }}"></script>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('scripts')
|
||||||
|
<script type="text/javascript">
|
||||||
|
var height = $(window).height() - 100;
|
||||||
|
$('#visualization').height(height + 'px');
|
||||||
|
// create an array with nodes
|
||||||
|
var nodes = {!! $nodes !!};
|
||||||
|
|
||||||
|
// create an array with edges
|
||||||
|
var edges = {!! $edges !!};
|
||||||
|
// create a network
|
||||||
|
var container = document.getElementById('visualization');
|
||||||
|
var data = {
|
||||||
|
nodes: nodes,
|
||||||
|
edges: edges,
|
||||||
|
stabilize: true
|
||||||
|
};
|
||||||
|
var options = {!! $options !!};
|
||||||
|
var network = new vis.Network(container, data, options);
|
||||||
|
network.on('click', function (properties) {
|
||||||
|
if (properties.nodes > 0) {
|
||||||
|
window.location.href = "device/device="+properties.nodes+"/"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function highlightNode(e) {
|
||||||
|
highlight_node = document.getElementById("highlight_node").value;
|
||||||
|
window.location.href = 'maps/devicedependency?group={{ $group_id }}&highlight_node=' + highlight_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#highlight_node option[value="{{$highlight_node}}"]').prop('selected', true);
|
||||||
|
</script>
|
||||||
|
@endsection
|
||||||
|
|
@@ -29,6 +29,11 @@ Route::group(['middleware' => ['auth', '2fa'], 'guard' => 'auth'], function () {
|
|||||||
Route::get('about', 'AboutController@index');
|
Route::get('about', 'AboutController@index');
|
||||||
Route::get('authlog', 'UserController@authlog');
|
Route::get('authlog', 'UserController@authlog');
|
||||||
|
|
||||||
|
// Maps
|
||||||
|
Route::group(['prefix' => 'maps', 'namespace' => 'Maps'], function () {
|
||||||
|
Route::get('devicedependency', 'DeviceDependencyController@dependencyMap');
|
||||||
|
});
|
||||||
|
|
||||||
// admin pages
|
// admin pages
|
||||||
Route::group(['guard' => 'admin'], function () {
|
Route::group(['guard' => 'admin'], function () {
|
||||||
Route::get('settings/{tab?}/{section?}', 'SettingsController@index')->name('settings');
|
Route::get('settings/{tab?}/{section?}', 'SettingsController@index')->name('settings');
|
||||||
|
Reference in New Issue
Block a user