Some Poller page cleanups (#11287)
* Some Poller page cleanups Some queries loaded all devices into memory and the counted them, we should have sql count them if we only need a count. Models should be singular Use named routes for url generation Try to keep presentation and data collection separated in blade and controller. * Update PollerController.php * Fix style * Fix new PollerGroup references
This commit is contained in:
parent
7e7320139a
commit
43a8616efd
|
@ -5,26 +5,18 @@ namespace App\Http\Controllers;
|
|||
use App\Models\Device;
|
||||
use App\Models\Poller;
|
||||
use App\Models\PollerCluster;
|
||||
use App\Models\PollerGroups;
|
||||
use App\Models\PollerGroup;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use LibreNMS\Config;
|
||||
|
||||
class PollerController extends Controller
|
||||
{
|
||||
public $rrdstep;
|
||||
public $defaultPollerId;
|
||||
|
||||
public $defaultGroup = [
|
||||
'id' => 0,
|
||||
'group_name' => 'General',
|
||||
'descr' => ''
|
||||
];
|
||||
public $defaultPollerMarker = '(default Poller)';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(PollerGroups::class, 'poller_groups'); // FIXME is this correct? not a resource anymore
|
||||
$this->rrdstep = \LibreNMS\Config::get('rrd.step');
|
||||
$this->defaultPollerId = \LibreNMS\Config::get('distributed_poller_group');
|
||||
$this->rrdstep = Config::get('rrd.step');
|
||||
}
|
||||
|
||||
public function logTab(Request $request)
|
||||
|
@ -35,33 +27,16 @@ class PollerController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
// output for poller groups
|
||||
public function groupsTab()
|
||||
{
|
||||
$group_list = PollerGroups::get();
|
||||
|
||||
# default poller_group
|
||||
$defaultGroup = $this->defaultGroup;
|
||||
$defaultGroup['devices'] = Device::where('poller_group', $defaultGroup['id'])->get();
|
||||
$defaultGroup['is_default_poller'] = ($defaultGroup['id'] == $this->defaultPollerId) ? true : false;
|
||||
|
||||
# poller_groups
|
||||
$poller_group_list = [];
|
||||
foreach ($group_list as $group) {
|
||||
$group['is_default_poller'] = ($group['id'] == $this->defaultPollerId) ? true : false;
|
||||
|
||||
$poller_group_list[] = $group;
|
||||
}
|
||||
|
||||
return view('poller.groups', [
|
||||
'current_tab' => 'groups',
|
||||
'default_poller_marker' => $this->defaultPollerMarker,
|
||||
'poller_groups' => $poller_group_list,
|
||||
'default_poller_group' => $defaultGroup,
|
||||
'poller_groups' => PollerGroup::query()->withCount('devices')->get(),
|
||||
'default_group_id' => Config::get('distributed_poller_group'),
|
||||
'ungrouped_count' => Device::where('poller_group', 0)->count(),
|
||||
]);
|
||||
}
|
||||
|
||||
// data output for poller view
|
||||
public function pollerTab()
|
||||
{
|
||||
return view('poller.poller', [
|
||||
|
@ -76,54 +51,38 @@ class PollerController extends Controller
|
|||
return view('poller.performance', ['current_tab' => 'performance']);
|
||||
}
|
||||
|
||||
protected function pollerStatus($poller)
|
||||
protected function pollerStatus($poller, $last)
|
||||
{
|
||||
$old = $poller['now'] - strtotime($poller['last_polled']);
|
||||
$since_last_poll = Carbon::parse($last)->diffInSeconds();
|
||||
|
||||
if ($old >= $this->rrdstep) {
|
||||
$poller['row_class'] = 'danger';
|
||||
} elseif ($old >= ($this->rrdstep * 0.95)) {
|
||||
$poller['row_class'] = 'warning';
|
||||
} else {
|
||||
$poller['row_class'] = 'success';
|
||||
}
|
||||
|
||||
$poller['long_not_polled'] = (\Auth::user()->hasGlobalAdmin() && ($old > ($this->rrdstep * 2))) ? true : false;
|
||||
$poller->row_class = $this->checkTimeSinceLastPoll($since_last_poll);
|
||||
$poller->long_not_polled = (\Auth::user()->hasGlobalAdmin() && ($since_last_poll > ($this->rrdstep * 2)));
|
||||
|
||||
return $poller;
|
||||
}
|
||||
|
||||
private function poller()
|
||||
{
|
||||
$rows = Poller::orderBy('poller_name')->get();
|
||||
|
||||
$time = time();
|
||||
|
||||
$groups = [];
|
||||
|
||||
foreach ($rows as $poller) {
|
||||
$poller['now'] = $time;
|
||||
|
||||
$poller = $this->pollerStatus($poller);
|
||||
|
||||
$groups[] = $poller;
|
||||
}
|
||||
|
||||
return $groups;
|
||||
return Poller::query()->orderBy('poller_name')->get()->map(function ($poller) {
|
||||
return $this->pollerStatus($poller, $poller->last_polled);
|
||||
});
|
||||
}
|
||||
|
||||
private function pollerCluster()
|
||||
{
|
||||
$rows = PollerCluster::orderBy('poller_name')->get();
|
||||
return PollerCluster::with('stats')->orderBy('poller_name')->get()->map(function ($poller) {
|
||||
return $this->pollerStatus($poller, $poller->last_report);
|
||||
});
|
||||
}
|
||||
|
||||
$cluster = [];
|
||||
|
||||
foreach ($rows as $poller) {
|
||||
$poller = $this->pollerStatus($poller);
|
||||
|
||||
$cluster[] = $poller;
|
||||
private function checkTimeSinceLastPoll($seconds)
|
||||
{
|
||||
if ($seconds >= $this->rrdstep) {
|
||||
return 'danger';
|
||||
} elseif ($seconds >= ($this->rrdstep * 0.95)) {
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
return $cluster;
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Device;
|
||||
use App\Models\PollerGroups;
|
||||
use App\Models\PollerGroup;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PollerGroupController extends Controller
|
||||
{
|
||||
public function destroy(Request $request, PollerGroups $pollergroup)
|
||||
public function destroy(Request $request, PollerGroup $pollergroup)
|
||||
{
|
||||
if ($request->user()->isAdmin()) {
|
||||
$pollergroup->delete();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Widget.php
|
||||
* PollerCluster.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
|
@ -36,6 +36,6 @@ class PollerCluster extends Model
|
|||
|
||||
public function stats()
|
||||
{
|
||||
return $this->hasMany('App\Models\PollerClusterStats', 'parent_poller', 'id');
|
||||
return $this->hasMany('App\Models\PollerClusterStat', 'parent_poller', 'id');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Widget.php
|
||||
* PollerClusterStat.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
|
@ -27,7 +27,7 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PollerClusterStats extends Model
|
||||
class PollerClusterStat extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $primaryKey = 'id';
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Widget.php
|
||||
* PollerGroup.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
|
@ -27,7 +27,7 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PollerGroups extends Model
|
||||
class PollerGroup extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $primaryKey = 'id';
|
||||
|
@ -40,7 +40,7 @@ class PollerGroups extends Model
|
|||
{
|
||||
parent::boot();
|
||||
|
||||
static::deleting(function (PollerGroups $pollergroup) {
|
||||
static::deleting(function (PollerGroup $pollergroup) {
|
||||
// handle device pollergroup fallback to default poller
|
||||
$default_poller_id = \LibreNMS\Config::get('distributed_poller_group');
|
||||
$pollergroup->devices()->update(['poller_group' => $default_poller_id]);
|
|
@ -528,12 +528,12 @@
|
|||
<li class="dropdown-submenu">
|
||||
<a href="{{ url('poller') }}"><i class="fa fa-th-large fa-fw fa-lg" aria-hidden="true"></i> @lang('Poller')</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ url('poller') }}"><i class="fa fa-th-large fa-fw fa-lg" aria-hidden="true"></i> @lang('Poller')</a></li>
|
||||
<li><a href="{{ route('poller') }}"><i class="fa fa-th-large fa-fw fa-lg" aria-hidden="true"></i> @lang('Poller')</a></li>
|
||||
@config('distributed_poller')
|
||||
<li><a href="{{ url('poller/groups') }}"><i class="fa fa-th fa-fw fa-lg" aria-hidden="true"></i> @lang('Groups')</a></li>
|
||||
<li><a href="{{ route('poller.groups') }}"><i class="fa fa-th fa-fw fa-lg" aria-hidden="true"></i> @lang('Groups')</a></li>
|
||||
@endconfig
|
||||
<li><a href="{{ url('poller/performance') }}"><i class="fa fa-line-chart fa-fw fa-lg" aria-hidden="true"></i> @lang('Performance')</a></li>
|
||||
<li><a href="{{ url('poller/log') }}"><i class="fa fa-file-text fa-fw fa-lg" aria-hidden="true"></i> @lang('Log')</a></li>
|
||||
<li><a href="{{ route('poller.performance') }}"><i class="fa fa-line-chart fa-fw fa-lg" aria-hidden="true"></i> @lang('Performance')</a></li>
|
||||
<li><a href="{{ route('poller.log') }}"><i class="fa fa-file-text fa-fw fa-lg" aria-hidden="true"></i> @lang('Log')</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
|
|
|
@ -18,24 +18,22 @@
|
|||
<th>@lang('Description')</th>
|
||||
<th>@lang('Action')</th>
|
||||
</tr>
|
||||
<tr id="{{ $default_poller_group['id'] }}">
|
||||
<td>{{ $default_poller_group['id'] }}</td>
|
||||
<td>{{ $default_poller_group['group_name'] }}@if($default_poller_group['is_default_poller']) {{ $default_poller_marker }}@endif</td>
|
||||
<td><a href="/devices/poller_group={{ $default_poller_group['id'] }}">{{ $default_poller_group['devices']->count() }}</a></td>
|
||||
<td>{{ $default_poller_group['descr'] }}</td>
|
||||
<tr id="0">
|
||||
<td>0</td>
|
||||
<td>General @if($default_group_id == 0) (@lang('default')) @endif</td>
|
||||
<td><a href="{{ url('devices/poller_group=0') }}">{{ $ungrouped_count }}</a></td>
|
||||
<td></td>
|
||||
<td>
|
||||
</tr>
|
||||
@foreach ($poller_groups as $group)
|
||||
<tr id="{{ $group['id'] }}">
|
||||
<td>{{ $group['id'] }}</td>
|
||||
<td>{{ $group['group_name'] }}@if($group['is_default_poller']) {{ $default_poller_marker }}@endif</td>
|
||||
<td><a href="/devices/poller_group={{ $group['id'] }}">{{ $group['devices']->count() }}</a></td>
|
||||
<td>{{ $group['descr'] }}</td>
|
||||
<tr id="{{ $group->id }}">
|
||||
<td>{{ $group->id }}</td>
|
||||
<td>{{ $group->group_name }}@if($group->id == $default_group_id) (@lang('default')) @endif</td>
|
||||
<td><a href="{{ url('devices/poller_group=' . $group->id) }}">{{ $group->devices_count }}</a></td>
|
||||
<td>{{ $group->descr }}</td>
|
||||
<td>
|
||||
@if($group['id'])
|
||||
<button type="button" class="btn btn-success btn-xs" id="{{$group['id']}}" data-group_id="{{$group['id']}}" data-toggle="modal" data-target="#poller-groups">@lang('Edit')</button>
|
||||
<button type="button" class="btn btn-danger btn-xs" id="{{$group['id']}}" data-group_id="{{$group['id']}}" data-toggle="modal" data-target="#confirm-delete">@lang('Delete')</button>
|
||||
@endif
|
||||
<button type="button" class="btn btn-success btn-xs" data-group_id="{{ $group->id }}" data-toggle="modal" data-target="#poller-groups">@lang('Edit')</button>
|
||||
<button type="button" class="btn btn-danger btn-xs" data-group_id="{{ $group->id }}" data-toggle="modal" data-target="#confirm-delete">@lang('Delete')</button>
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
|
|
|
@ -5,20 +5,23 @@
|
|||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<ul class="nav nav-tabs">
|
||||
<li role="presentation" @if( $current_tab == 'poller' ) ' class="active"' @endif>
|
||||
<a href="/poller"><i class="fa fa-th-large fa-lg icon-theme" aria-hidden="true"></i>@lang('Poller')</a>
|
||||
<li role="presentation" @if( $current_tab == 'poller' ) class="active" @endif>
|
||||
<a href="{{ route('poller') }}"><i class="fa fa-th-large fa-lg icon-theme" aria-hidden="true"></i> @lang('Poller')</a>
|
||||
</li>
|
||||
<li role="presentation" @if( $current_tab == 'groups' ) ' class="active"' @endif>
|
||||
<a href="/poller/groups"><i class="fa fa-th fa-lg icon-theme" aria-hidden="true"></i>@lang('Groups')</a>
|
||||
@config('distributed_poller')
|
||||
<li role="presentation" @if( $current_tab == 'groups' ) class="active" @endif>
|
||||
<a href="{{ route('poller.groups') }}"><i class="fa fa-th fa-lg icon-theme" aria-hidden="true"></i> @lang('Groups')</a>
|
||||
</li>
|
||||
<li role="presentation" @if( $current_tab == 'performance' ) ' class="active"' @endif>
|
||||
<a href="/poller/performance"><i class="fa fa-line-chart fa-lg icon-theme" aria-hidden="true"></i>@lang('Performance')</a>
|
||||
@endconfig
|
||||
<li role="presentation" @if( $current_tab == 'performance' ) class="active" @endif>
|
||||
<a href="{{ route('poller.performance') }}"><i class="fa fa-line-chart fa-lg icon-theme" aria-hidden="true"></i> @lang('Performance')</a>
|
||||
</li>
|
||||
<li role="presentation" @if( $current_tab == 'log' ) ' class="active"' @endif>
|
||||
<a href="/poller/log"><i class="fa fa-file-text fa-lg icon-theme" aria-hidden="true"></i>@lang('Log')</a>
|
||||
<li role="presentation" @if( $current_tab == 'log' ) class="active" @endif>
|
||||
<a href="{{ route('poller.log') }}"><i class="fa fa-file-text fa-lg icon-theme" aria-hidden="true"></i> @lang('Log')</a>
|
||||
</li>
|
||||
</ul>
|
||||
@endsection
|
||||
|
||||
@section('content_footer')
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<th data-column-id="hostname">@lang('Hostname')</th>
|
||||
<th data-column-id="last_polled">@lang('Last Polled')</th>
|
||||
<th data-column-id="poller_group">@lang('Poller Group')</th>
|
||||
<th data-column-id="last_polled_timetaken" data-order="desc">@lang('Polling Duration (Seconds)')</th>
|
||||
<th data-column-id="last_polled_timetaken" data-order="desc">@lang('Polling Duration') (@lang('Seconds'))</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
@ -22,8 +22,8 @@
|
|||
<script>
|
||||
searchbar = "<div id=\"\{\{ctx.id\}\}\" class=\"\{\{css.header\}\}\"><div class=\"row\">"+
|
||||
"<div class=\"col-sm-8 actionBar\"><span class=\"pull-left\">"+
|
||||
"<a href='poller/log' class='btn btn-primary btn-sm @if($filter == 'unpolled') 'active' @endif'>All devices</a> "+
|
||||
"<a href='poller/log?filter=unpolled' class='btn btn-danger btn-sm @if($filter == 'unpolled') 'active' @endif'>Unpolled devices</a>"+
|
||||
"<a href='{{ route('poller.log') }}' class='btn btn-primary btn-sm @if($filter == 'unpolled') 'active' @endif'>All devices</a> "+
|
||||
"<a href='{{ route('poller.log') }}?filter=unpolled' class='btn btn-danger btn-sm @if($filter == 'unpolled') 'active' @endif'>Unpolled devices</a>"+
|
||||
"</div><div class=\"col-sm-4 actionBar\"><p class=\"\{\{css.search\}\}\"></p><p class=\"\{\{css.actions\}\}\"></p></div>";
|
||||
|
||||
var grid = $("#poll-log").bootgrid({
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
@parent
|
||||
|
||||
<br />
|
||||
@if( $pollers )
|
||||
@if( $pollers->isNotEmpty() )
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">@lang('Standard Pollers')</h3>
|
||||
|
@ -37,7 +37,7 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
@if( $poller_cluster )
|
||||
@if( $poller_cluster->isNotEmpty() )
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">@lang('Poller Cluster Health')</h3>
|
||||
|
@ -60,26 +60,26 @@
|
|||
<th>@lang('Actions')</th>
|
||||
</tr>
|
||||
@foreach($poller_cluster as $poller)
|
||||
@foreach($poller['stats'] as $stats)
|
||||
<tr class="{{ $poller['row_class'] }}" id="row_{{ $poller['id'] }}">
|
||||
@if( $loop->first )
|
||||
<td rowspan="{{ $poller['stats']->count() }}">{{ $poller['poller_name'] }}</td>
|
||||
<td rowspan="{{ $poller['stats']->count() }}"@if($poller['node_id'] == '') ' class="danger"' @endif>{{ $poller['node_id'] }}</td>
|
||||
<td rowspan="{{ $poller['stats']->count() }}">{{ $poller['poller_version'] }}</td>
|
||||
<td rowspan="{{ $poller['stats']->count() }}">{{ $poller['poller_groups'] }}</td>
|
||||
<td rowspan="{{ $poller['stats']->count() }}">{{ $poller['last_report'] }}</td>
|
||||
<td rowspan="{{ $poller['stats']->count() }}">@if( $poller['master'] ) "@lang('Yes')" @else "@lang('No')" @endif</td>
|
||||
@endif
|
||||
<td>{{ $stats['poller_type'] }}</td>
|
||||
<td>{{ $stats['workers'] }}</td>
|
||||
<td>{{ $stats['devices'] }}</td>
|
||||
<td>{{ $stats['depth'] }}</td>
|
||||
<td>{{ $stats['worker_seconds'] }} / {{ $stats['frequency'] * $stats['workers'] }}</td>
|
||||
@if( $loop->first )
|
||||
<td rowspan="{{ $poller['stats']->count() }}">@if( $poller['long_not_polled'] )<button type='button' class='btn btn-danger btn-sm' aria-label=@lang('Delete') data-toggle='modal' data-target='#confirm-delete' data-id='{{ $poller['id'] }}' data-pollertype='delete-cluster-poller' name='delete-cluster-poller'><i class='fa fa-trash' aria-hidden='true'></i></button>@endif</td>
|
||||
@endif
|
||||
</tr>
|
||||
@endforeach
|
||||
@foreach($poller->stats as $stat)
|
||||
<tr class="{{ $poller['row_class'] }}" id="row_{{ $poller->id }}">
|
||||
@if( $loop->first )
|
||||
<td rowspan="{{ $poller->stats->count() }}">{{ $poller->poller_name }}</td>
|
||||
<td rowspan="{{ $poller->stats->count() }}" @if($poller->node_id == '') class="danger" @endif>{{ $poller->node_id }}</td>
|
||||
<td rowspan="{{ $poller->stats->count() }}">{{ $poller->poller_version }}</td>
|
||||
<td rowspan="{{ $poller->stats->count() }}">{{ $poller->poller_groups }}</td>
|
||||
<td rowspan="{{ $poller->stats->count() }}">{{ $poller->last_report }}</td>
|
||||
<td rowspan="{{ $poller->stats->count() }}">@lang($poller->master ? 'Yes' : 'No')</td>
|
||||
@endif
|
||||
<td>{{ $stat->poller_type }}</td>
|
||||
<td>{{ $stat->workers }}</td>
|
||||
<td>{{ $stat->devices }}</td>
|
||||
<td>{{ $stat->depth }}</td>
|
||||
<td>{{ $stat->worker_seconds }} / {{ $stat->frequency * $stat->workers }}</td>
|
||||
@if( $loop->first )
|
||||
<td rowspan="{{ $poller->stats->count() }}">@if($poller->long_not_polled)<button type='button' class='btn btn-danger btn-sm' aria-label=@lang('Delete') data-toggle='modal' data-target='#confirm-delete' data-id='{{ $poller->id }}' data-pollertype='delete-cluster-poller' name='delete-cluster-poller'><i class='fa fa-trash' aria-hidden='true'></i></button>@endif</td>
|
||||
@endif
|
||||
</tr>
|
||||
@endforeach
|
||||
@endforeach
|
||||
</table>
|
||||
<small>
|
||||
|
|
|
@ -23,10 +23,10 @@ Route::group(['middleware' => ['auth', '2fa'], 'guard' => 'auth'], function () {
|
|||
|
||||
// pages
|
||||
Route::resource('device-groups', 'DeviceGroupController');
|
||||
Route::get('poller', 'PollerController@pollerTab');
|
||||
Route::get('poller/log', 'PollerController@logTab');
|
||||
Route::get('poller/groups', 'PollerController@groupsTab');
|
||||
Route::get('poller/performance', 'PollerController@performanceTab');
|
||||
Route::get('poller', 'PollerController@pollerTab')->name('poller');
|
||||
Route::get('poller/log', 'PollerController@logTab')->name('poller.log');
|
||||
Route::get('poller/groups', 'PollerController@groupsTab')->name('poller.groups');
|
||||
Route::get('poller/performance', 'PollerController@performanceTab')->name('poller.performance');
|
||||
Route::get('locations', 'LocationController@index');
|
||||
Route::resource('preferences', 'UserPreferencesController', ['only' => ['index', 'store']]);
|
||||
Route::resource('users', 'UserController');
|
||||
|
|
Loading…
Reference in New Issue