mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Dispatcher Service settings (#11760)
* Poller settings WIP * Poller settings WIP2 * working on SettingMultiple * setting multiple working * settings sent with all required info * fix translation * Fix keys * fix groups setting * Apply settings to service fixes and validations for setting * don't error when no poller_cluster entry exists * hid tab when no poller cluster entries * Authorization * make prod * daily maintenance toggle should be advanced * Update schema def
This commit is contained in:
+68
-6
@@ -59,7 +59,7 @@ class ServiceConfig:
|
||||
services = PollerConfig(8, 300)
|
||||
discovery = PollerConfig(16, 21600)
|
||||
billing = PollerConfig(2, 300, 60)
|
||||
ping = PollerConfig(1, 120)
|
||||
ping = PollerConfig(1, 60)
|
||||
down_retry = 60
|
||||
update_enabled = True
|
||||
update_frequency = 86400
|
||||
@@ -118,7 +118,7 @@ class ServiceConfig:
|
||||
self.alerting.enabled = config.get('service_alerting_enabled', True)
|
||||
self.alerting.frequency = config.get('service_alerting_frequency', ServiceConfig.alerting.frequency)
|
||||
self.ping.enabled = config.get('service_ping_enabled', False)
|
||||
self.ping.frequency = config.get('ping_rrd_step', ServiceConfig.billing.calculate)
|
||||
self.ping.frequency = config.get('ping_rrd_step', ServiceConfig.ping.frequency)
|
||||
self.down_retry = config.get('service_poller_down_retry', ServiceConfig.down_retry)
|
||||
self.log_level = config.get('service_loglevel', ServiceConfig.log_level)
|
||||
self.update_enabled = config.get('service_update_enabled', ServiceConfig.update_enabled)
|
||||
@@ -155,6 +155,68 @@ class ServiceConfig:
|
||||
error("Unknown log level {}, must be one of 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'".format(self.log_level))
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
def load_poller_config(self, db):
|
||||
try:
|
||||
settings = {}
|
||||
cursor = db.query('SELECT * FROM `poller_cluster` WHERE `node_id`=%s', self.node_id)
|
||||
if cursor.rowcount == 0:
|
||||
return
|
||||
|
||||
for index, setting in enumerate(cursor.fetchone()):
|
||||
name = cursor.description[index][0]
|
||||
settings[name] = setting
|
||||
|
||||
if settings['poller_name'] is not None:
|
||||
self.set_name(settings['poller_name'])
|
||||
if settings['poller_groups'] is not None:
|
||||
self.group = ServiceConfig.parse_group(settings['poller_groups'])
|
||||
if settings['poller_enabled'] is not None:
|
||||
self.poller.enabled = settings['poller_enabled']
|
||||
if settings['poller_frequency'] is not None:
|
||||
self.poller.frequency = settings['poller_frequency']
|
||||
if settings['poller_workers'] is not None:
|
||||
self.poller.workers = settings['poller_workers']
|
||||
if settings['poller_down_retry'] is not None:
|
||||
self.down_retry = settings['poller_down_retry']
|
||||
if settings['discovery_enabled'] is not None:
|
||||
self.discovery.enabled = settings['discovery_enabled']
|
||||
if settings['discovery_frequency'] is not None:
|
||||
self.discovery.frequency = settings['discovery_frequency']
|
||||
if settings['discovery_workers'] is not None:
|
||||
self.discovery.workers = settings['discovery_workers']
|
||||
if settings['services_enabled'] is not None:
|
||||
self.services.enabled = settings['services_enabled']
|
||||
if settings['services_frequency'] is not None:
|
||||
self.services.frequency = settings['services_frequency']
|
||||
if settings['services_workers'] is not None:
|
||||
self.services.workers = settings['services_workers']
|
||||
if settings['billing_enabled'] is not None:
|
||||
self.billing.enabled = settings['billing_enabled']
|
||||
if settings['billing_frequency'] is not None:
|
||||
self.billing.frequency = settings['billing_frequency']
|
||||
if settings['billing_calculate_frequency'] is not None:
|
||||
self.billing.calculate = settings['billing_calculate_frequency']
|
||||
if settings['alerting_enabled'] is not None:
|
||||
self.alerting.enabled = settings['alerting_enabled']
|
||||
if settings['alerting_frequency'] is not None:
|
||||
self.alerting.frequency = settings['alerting_frequency']
|
||||
if settings['ping_enabled'] is not None:
|
||||
self.ping.enabled = settings['ping_enabled']
|
||||
if settings['ping_frequency'] is not None:
|
||||
self.ping.frequency = settings['ping_frequency']
|
||||
if settings['update_enabled'] is not None:
|
||||
self.update_enabled = settings['update_enabled']
|
||||
if settings['update_frequency'] is not None:
|
||||
self.update_frequency = settings['update_frequency']
|
||||
if settings['loglevel'] is not None:
|
||||
self.log_level = settings['loglevel']
|
||||
if settings['watchdog_enabled'] is not None:
|
||||
self.watchdog_enabled = settings['watchdog_enabled']
|
||||
if settings['watchdog_log'] is not None:
|
||||
self.watchdog_logfile = settings['watchdog_log']
|
||||
except pymysql.err.Error:
|
||||
warning('Unable to load poller (%s) config', self.node_id)
|
||||
|
||||
def _get_config_data(self):
|
||||
try:
|
||||
import dotenv
|
||||
@@ -205,11 +267,11 @@ class Service:
|
||||
|
||||
def __init__(self):
|
||||
self.config.populate()
|
||||
threading.current_thread().name = self.config.name # rename main thread
|
||||
|
||||
self.attach_signals()
|
||||
|
||||
self._db = LibreNMS.DB(self.config)
|
||||
self.config.load_poller_config(self._db)
|
||||
|
||||
threading.current_thread().name = self.config.name # rename main thread
|
||||
self.attach_signals()
|
||||
|
||||
self._lm = self.create_lock_manager()
|
||||
self.daily_timer = LibreNMS.RecurringTimer(self.config.update_frequency, self.run_maintenance, 'maintenance')
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Models\PollerCluster;
|
||||
use App\Models\PollerGroup;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use LibreNMS\Config;
|
||||
|
||||
class PollerController extends Controller
|
||||
@@ -21,6 +22,7 @@ class PollerController extends Controller
|
||||
|
||||
public function logTab(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', PollerCluster::class);
|
||||
return view('poller.log', [
|
||||
'current_tab' => 'log',
|
||||
'filter' => $request->input('filter', 'active')
|
||||
@@ -29,6 +31,7 @@ class PollerController extends Controller
|
||||
|
||||
public function groupsTab()
|
||||
{
|
||||
$this->authorize('manage', PollerCluster::class);
|
||||
return view('poller.groups', [
|
||||
'current_tab' => 'groups',
|
||||
'poller_groups' => PollerGroup::query()->withCount('devices')->get(),
|
||||
@@ -39,6 +42,7 @@ class PollerController extends Controller
|
||||
|
||||
public function pollerTab()
|
||||
{
|
||||
$this->authorize('viewAny', PollerCluster::class);
|
||||
return view('poller.poller', [
|
||||
'current_tab' => 'poller',
|
||||
'pollers' => $this->poller(),
|
||||
@@ -46,8 +50,20 @@ class PollerController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function settingsTab()
|
||||
{
|
||||
$this->authorize('manage', PollerCluster::class);
|
||||
$pollerClusters = PollerCluster::all()->keyBy('id');
|
||||
return view('poller.settings', [
|
||||
'current_tab' => 'settings',
|
||||
'settings' => $this->pollerSettings($pollerClusters),
|
||||
'poller_cluster' => $pollerClusters,
|
||||
]);
|
||||
}
|
||||
|
||||
public function performanceTab()
|
||||
{
|
||||
$this->authorize('viewAny', PollerCluster::class);
|
||||
return view('poller.performance', ['current_tab' => 'performance']);
|
||||
}
|
||||
|
||||
@@ -85,4 +101,10 @@ class PollerController extends Controller
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
private function pollerSettings($pollers): Collection
|
||||
{
|
||||
$groups = PollerGroup::list();
|
||||
return $pollers->map->configDefinition($groups);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* PollerSettingsController.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* 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 2020 Tony Murray
|
||||
* @author Tony Murray <[email protected]>
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\PollerCluster;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PollerSettingsController extends Controller
|
||||
{
|
||||
public function update(Request $request, $id, $setting)
|
||||
{
|
||||
$poller = PollerCluster::findOrFail($id);
|
||||
$this->authorize('update', $poller);
|
||||
|
||||
$definition = collect($poller->configDefinition())->keyBy('name');
|
||||
if (!$definition->has($setting)) {
|
||||
return response()->json(['error' => 'Invalid setting'], 422);
|
||||
}
|
||||
|
||||
$poller->$setting = $request->get('value');
|
||||
$poller->save();
|
||||
return response()->json(['value' => $poller->$setting]);
|
||||
}
|
||||
|
||||
public function destroy($id, $setting)
|
||||
{
|
||||
$poller = PollerCluster::findOrFail($id);
|
||||
$this->authorize('delete', $poller);
|
||||
|
||||
$definition = collect($poller->configDefinition())->keyBy('name');
|
||||
if (!$definition->has($setting)) {
|
||||
return response()->json(['error' => 'Invalid setting'], 422);
|
||||
}
|
||||
|
||||
$poller->$setting = $definition->get($setting)['default'];
|
||||
$poller->save();
|
||||
return response()->json(['value' => $poller->$setting]);
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,201 @@ class PollerCluster extends Model
|
||||
protected $primaryKey = 'id';
|
||||
protected $fillable = ['poller_name'];
|
||||
|
||||
// ---- Accessors/Mutators ----
|
||||
|
||||
public function setPollerGroupsAttribute($groups)
|
||||
{
|
||||
$this->attributes['poller_groups'] = is_array($groups) ? implode(',', $groups) : $groups;
|
||||
}
|
||||
|
||||
// ---- Helpers ----
|
||||
|
||||
/**
|
||||
* Get the frontend config definition for this poller
|
||||
*
|
||||
* @param \Illuminate\Support\Collection $groups optionally supply full list of poller groups to avoid fetching multiple times
|
||||
* @return array[]
|
||||
*/
|
||||
public function configDefinition($groups = null)
|
||||
{
|
||||
if (empty($groups)) {
|
||||
$groups = PollerGroup::list();
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'poller_groups',
|
||||
'default' => \LibreNMS\Config::get('distributed_poller_group'),
|
||||
'value' => $poller->poller_groups ?? \LibreNMS\Config::get('distributed_poller_group'),
|
||||
'type' => 'multiple',
|
||||
'options' => $groups,
|
||||
],
|
||||
[
|
||||
'name' => 'poller_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_poller_enabled'),
|
||||
'value' => (bool)($poller->poller_enabled ?? \LibreNMS\Config::get('service_poller_enabled')),
|
||||
'type' => 'boolean',
|
||||
],
|
||||
[
|
||||
'name' => 'poller_workers',
|
||||
'default' => \LibreNMS\Config::get('service_poller_workers'),
|
||||
'value' => $poller->poller_workers ?? \LibreNMS\Config::get('service_poller_workers'),
|
||||
'type' => 'integer',
|
||||
'units' => 'workers',
|
||||
],
|
||||
[
|
||||
'name' => 'poller_frequency',
|
||||
'default' => \LibreNMS\Config::get('service_poller_frequency'),
|
||||
'value' => $poller->poller_workers ?? \LibreNMS\Config::get('service_poller_frequency'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'poller_down_retry',
|
||||
'default' => \LibreNMS\Config::get('service_poller_down_retry'),
|
||||
'value' => $poller->poller_down_retry ?? \LibreNMS\Config::get('service_poller_down_retry'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
],
|
||||
[
|
||||
'name' => 'discovery_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_discovery_enabled'),
|
||||
'value' => (bool)($poller->discovery_enabled ?? \LibreNMS\Config::get('service_discovery_enabled')),
|
||||
'type' => 'boolean',
|
||||
],
|
||||
[
|
||||
'name' => 'discovery_workers',
|
||||
'default' => \LibreNMS\Config::get('service_discovery_workers'),
|
||||
'value' => $poller->discovery_workers ?? \LibreNMS\Config::get('service_discovery_workers'),
|
||||
'type' => 'integer',
|
||||
'units' => 'workers',
|
||||
],
|
||||
[
|
||||
'name' => 'discovery_frequency',
|
||||
'default' => \LibreNMS\Config::get('service_discovery_frequency'),
|
||||
'value' => $poller->discovery_frequency ?? \LibreNMS\Config::get('service_discovery_frequency'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'services_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_services_enabled'),
|
||||
'value' => (bool)($poller->services_enabled ?? \LibreNMS\Config::get('service_services_enabled')),
|
||||
'type' => 'boolean',
|
||||
],
|
||||
[
|
||||
'name' => 'services_workers',
|
||||
'default' => \LibreNMS\Config::get('service_services_workers'),
|
||||
'value' => $poller->services_workers ?? \LibreNMS\Config::get('service_services_workers'),
|
||||
'type' => 'integer',
|
||||
'units' => 'workers',
|
||||
],
|
||||
[
|
||||
'name' => 'services_frequency',
|
||||
'default' => \LibreNMS\Config::get('service_services_frequency'),
|
||||
'value' => $poller->services_frequency ?? \LibreNMS\Config::get('service_services_frequency'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_billing_enabled'),
|
||||
'value' => (bool)($poller->billing_enabled ?? \LibreNMS\Config::get('service_billing_enabled')),
|
||||
'type' => 'boolean',
|
||||
],
|
||||
[
|
||||
'name' => 'billing_frequency',
|
||||
'default' => \LibreNMS\Config::get('service_billing_frequency'),
|
||||
'value' => $poller->billing_frequency ?? \LibreNMS\Config::get('service_billing_frequency'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_calculate_frequency',
|
||||
'default' => \LibreNMS\Config::get('service_billing_calculate_frequency'),
|
||||
'value' => $poller->billing_calculate_frequency ?? \LibreNMS\Config::get('service_billing_calculate_frequency'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'alerting_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_alerting_enabled'),
|
||||
'value' => (bool)($poller->alerting_enabled ?? \LibreNMS\Config::get('service_alerting_enabled')),
|
||||
'type' => 'boolean',
|
||||
],
|
||||
[
|
||||
'name' => 'alerting_frequency',
|
||||
'default' => \LibreNMS\Config::get('service_alerting_frequency'),
|
||||
'value' => $poller->alerting_frequency ?? \LibreNMS\Config::get('service_alerting_frequency'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'ping_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_ping_enabled'),
|
||||
'value' => (bool)($poller->ping_enabled ?? \LibreNMS\Config::get('service_ping_enabled')),
|
||||
'type' => 'boolean',
|
||||
],
|
||||
[
|
||||
'name' => 'ping_frequency',
|
||||
'default' => \LibreNMS\Config::get('ping_rrd_step'),
|
||||
'value' => $poller->ping_frequency ?? \LibreNMS\Config::get('ping_rrd_step'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'update_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_update_enabled'),
|
||||
'value' => (bool)($poller->update_enabled ?? \LibreNMS\Config::get('service_update_enabled')),
|
||||
'type' => 'boolean',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'update_frequency',
|
||||
'default' => \LibreNMS\Config::get('service_update_frequency'),
|
||||
'value' => $poller->update_frequency ?? \LibreNMS\Config::get('service_update_frequency'),
|
||||
'type' => 'integer',
|
||||
'units' => 'seconds',
|
||||
'advanced' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'loglevel',
|
||||
'default' => \LibreNMS\Config::get('service_loglevel'),
|
||||
'value' => $poller->loglevel ?? \LibreNMS\Config::get('service_loglevel'),
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'DEBUG' => 'DEBUG',
|
||||
'INFO' => 'INFO',
|
||||
'WARNING' => 'WARNING',
|
||||
'ERROR' => 'ERROR',
|
||||
'CRITICAL' => 'CRITICAL'
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'watchdog_enabled',
|
||||
'default' => \LibreNMS\Config::get('service_watchdog_enabled'),
|
||||
'value' => (bool)($poller->watchdog_enabled ?? \LibreNMS\Config::get('service_watchdog_enabled')),
|
||||
'type' => 'boolean',
|
||||
],
|
||||
[
|
||||
'name' => 'watchdog_log',
|
||||
'default' => \LibreNMS\Config::get('log_file'),
|
||||
'value' => $poller->watchdog_log ?? \LibreNMS\Config::get('log_file'),
|
||||
'type' => 'text',
|
||||
'advanced' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// ---- Relationships ----
|
||||
|
||||
public function stats()
|
||||
{
|
||||
return $this->hasMany(\App\Models\PollerClusterStat::class, 'parent_poller', 'id');
|
||||
|
||||
@@ -41,12 +41,17 @@ class PollerGroup extends Model
|
||||
parent::boot();
|
||||
|
||||
static::deleting(function (PollerGroup $pollergroup) {
|
||||
// handle device pollergroup fallback to default poller
|
||||
// handle device poller group fallback to default poller
|
||||
$default_poller_id = \LibreNMS\Config::get('default_poller_group');
|
||||
$pollergroup->devices()->update(['poller_group' => $default_poller_id]);
|
||||
});
|
||||
}
|
||||
|
||||
public static function list()
|
||||
{
|
||||
return self::query()->pluck('group_name', 'id')->prepend(__('General'), 0);
|
||||
}
|
||||
|
||||
public function devices()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Device::class, 'poller_group', 'id');
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\PollerCluster;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class PollerClusterPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any poller clusters.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
return $user->hasGlobalAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the poller cluster.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\PollerCluster $pollerCluster
|
||||
* @return mixed
|
||||
*/
|
||||
public function view(User $user, PollerCluster $pollerCluster)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create poller clusters.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the poller cluster.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\PollerCluster $pollerCluster
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(User $user, PollerCluster $pollerCluster)
|
||||
{
|
||||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the poller cluster.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\PollerCluster $pollerCluster
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete(User $user, PollerCluster $pollerCluster)
|
||||
{
|
||||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the poller cluster.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\PollerCluster $pollerCluster
|
||||
* @return mixed
|
||||
*/
|
||||
public function restore(User $user, PollerCluster $pollerCluster)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the poller cluster.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\PollerCluster $pollerCluster
|
||||
* @return mixed
|
||||
*/
|
||||
public function forceDelete(User $user, PollerCluster $pollerCluster)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can manage the poller cluster.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\PollerCluster $pollerCluster
|
||||
* @return mixed
|
||||
*/
|
||||
public function manage(User $user)
|
||||
{
|
||||
return $user->isAdmin();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
\App\Models\User::class => \App\Policies\UserPolicy::class,
|
||||
\App\Models\Device::class => \App\Policies\DevicePolicy::class,
|
||||
\App\Models\DeviceGroup::class => \App\Policies\DeviceGroupPolicy::class,
|
||||
\App\Models\PollerCluster::class => \App\Policies\PollerClusterPolicy::class,
|
||||
\App\Models\Port::class => \App\Policies\PortPolicy::class,
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class PollerClusterSettings extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('poller_cluster', function (Blueprint $table) {
|
||||
$table->boolean('poller_enabled')->nullable();
|
||||
$table->integer('poller_frequency')->nullable();
|
||||
$table->integer('poller_workers')->nullable();
|
||||
$table->integer('poller_down_retry')->nullable();
|
||||
$table->boolean('discovery_enabled')->nullable();
|
||||
$table->integer('discovery_frequency')->nullable();
|
||||
$table->integer('discovery_workers')->nullable();
|
||||
$table->boolean('services_enabled')->nullable();
|
||||
$table->integer('services_frequency')->nullable();
|
||||
$table->integer('services_workers')->nullable();
|
||||
$table->boolean('billing_enabled')->nullable();
|
||||
$table->integer('billing_frequency')->nullable();
|
||||
$table->integer('billing_calculate_frequency')->nullable();
|
||||
$table->boolean('alerting_enabled')->nullable();
|
||||
$table->integer('alerting_frequency')->nullable();
|
||||
$table->boolean('ping_enabled')->nullable();
|
||||
$table->integer('ping_frequency')->nullable();
|
||||
$table->boolean('update_enabled')->nullable();
|
||||
$table->integer('update_frequency')->nullable();
|
||||
$table->string('loglevel', 8)->nullable();
|
||||
$table->boolean('watchdog_enabled')->nullable();
|
||||
$table->string('watchdog_log')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('poller_cluster', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'poller_enabled',
|
||||
'poller_frequency',
|
||||
'poller_workers',
|
||||
'poller_down_retry',
|
||||
'discovery_enabled',
|
||||
'discovery_frequency',
|
||||
'discovery_workers',
|
||||
'services_enabled',
|
||||
'services_frequency',
|
||||
'services_workers',
|
||||
'billing_enabled',
|
||||
'billing_frequency',
|
||||
'billing_calculate_frequency',
|
||||
'alerting_enabled',
|
||||
'alerting_frequency',
|
||||
'ping_enabled',
|
||||
'ping_frequency',
|
||||
'update_enabled',
|
||||
'update_frequency',
|
||||
'loglevel',
|
||||
'watchdog_enabled',
|
||||
'watchdog_log'
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=63189b3aa20a0043cc38",
|
||||
"/css/app.css": "/css/app.css?id=5da3bf931f2f95a17884",
|
||||
"/js/app.js": "/js/app.js?id=4d14830ae8a6dfe54711",
|
||||
"/css/app.css": "/css/app.css?id=ffec4165a9c98d892a32",
|
||||
"/js/manifest.js": "/js/manifest.js?id=3c768977c2574a34506e",
|
||||
"/js/vendor.js": "/js/vendor.js?id=29212a758157c575d7f8",
|
||||
"/js/lang/de.js": "/js/lang/de.js?id=d095b82e431906ea9b0d",
|
||||
"/js/lang/en.js": "/js/lang/en.js?id=de1f054e216295f509a3",
|
||||
"/js/lang/fr.js": "/js/lang/fr.js?id=8e94b3986dc6fce2f3e5",
|
||||
"/js/lang/ru.js": "/js/lang/ru.js?id=dc6cb9314c4903b00501",
|
||||
"/js/lang/uk.js": "/js/lang/uk.js?id=669c4652f87dfd31ce7a",
|
||||
"/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=82383ffa183494fa4a14"
|
||||
"/js/vendor.js": "/js/vendor.js?id=c0e0ebbfd027a8baefb4",
|
||||
"/js/lang/de.js": "/js/lang/de.js?id=b96f6bf4d57d6614e18f",
|
||||
"/js/lang/en.js": "/js/lang/en.js?id=5e41e02c1021ebebaf1d",
|
||||
"/js/lang/fr.js": "/js/lang/fr.js?id=4f329163511445d92a17",
|
||||
"/js/lang/ru.js": "/js/lang/ru.js?id=f818cb1ab0a804b7bd3a",
|
||||
"/js/lang/uk.js": "/js/lang/uk.js?id=c8d4937e3ca47b60b7ac",
|
||||
"/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=a22406ceaffc7c936ed8"
|
||||
}
|
||||
|
||||
+172
-10
@@ -4515,6 +4515,172 @@
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"service_poller_enabled": {
|
||||
"default": true,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 5,
|
||||
"type": "boolean"
|
||||
},
|
||||
"service_poller_workers": {
|
||||
"default": 24,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 6,
|
||||
"type": "integer",
|
||||
"units": "Workers"
|
||||
},
|
||||
"service_poller_frequency": {
|
||||
"default": 300,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 7,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_poller_down_retry": {
|
||||
"default": 60,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 8,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_discovery_enabled": {
|
||||
"default": true,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 9,
|
||||
"type": "boolean"
|
||||
},
|
||||
"service_discovery_workers": {
|
||||
"default": 16,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 10,
|
||||
"type": "integer",
|
||||
"units": "Workers"
|
||||
},
|
||||
"service_discovery_frequency": {
|
||||
"default": 21600,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 11,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_services_enabled": {
|
||||
"default": true,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 12,
|
||||
"type": "boolean"
|
||||
},
|
||||
"service_services_workers": {
|
||||
"default": 8,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 13,
|
||||
"type": "integer",
|
||||
"units": "Workers"
|
||||
},
|
||||
"service_services_frequency": {
|
||||
"default": 300,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 14,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_billing_enabled": {
|
||||
"default": true,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 15,
|
||||
"type": "boolean"
|
||||
},
|
||||
"service_billing_frequency": {
|
||||
"default": 300,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 16,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_billing_calculate_frequency": {
|
||||
"default": 60,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 17,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_alerting_enabled": {
|
||||
"default": true,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 18,
|
||||
"type": "boolean"
|
||||
},
|
||||
"service_alerting_frequency": {
|
||||
"default": 60,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 19,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_ping_enabled": {
|
||||
"default": false,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 20,
|
||||
"type": "boolean"
|
||||
},
|
||||
"ping_rrd_step": {
|
||||
"default": 60,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 21,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_update_enabled": {
|
||||
"default": true,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 22,
|
||||
"type": "boolean"
|
||||
},
|
||||
"service_update_frequency": {
|
||||
"default": 86400,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 23,
|
||||
"type": "integer",
|
||||
"units": "Seconds"
|
||||
},
|
||||
"service_loglevel": {
|
||||
"default": "INFO",
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 24,
|
||||
"type": "select",
|
||||
"options": {
|
||||
"DEBUG": "DEBUG",
|
||||
"INFO": "INFO",
|
||||
"WARNING": "WARNING",
|
||||
"ERROR": "ERROR",
|
||||
"CRITICAL": "CRITICAL"
|
||||
}
|
||||
},
|
||||
"service_watchdog_enabled": {
|
||||
"default": false,
|
||||
"group": "poller",
|
||||
"section": "distributed",
|
||||
"order": 25,
|
||||
"type": "boolean"
|
||||
},
|
||||
"sfdp": {
|
||||
"default": "/usr/bin/sfdp",
|
||||
"group": "external",
|
||||
@@ -4639,8 +4805,12 @@
|
||||
"type": "text"
|
||||
},
|
||||
"smokeping.pings": {
|
||||
"default": 20,
|
||||
"type": "integer"
|
||||
"default": 5,
|
||||
"group": "external",
|
||||
"section": "smokeping",
|
||||
"order": 2,
|
||||
"type": "integer",
|
||||
"units": "pings"
|
||||
},
|
||||
"snmp.community": {
|
||||
"group": "poller",
|
||||
@@ -5023,14 +5193,6 @@
|
||||
"order": 1,
|
||||
"type": "text"
|
||||
},
|
||||
"smokeping.pings": {
|
||||
"default": 5,
|
||||
"group": "external",
|
||||
"section": "smokeping",
|
||||
"order": 2,
|
||||
"type": "integer",
|
||||
"units": "pings"
|
||||
},
|
||||
"smokeping.url": {
|
||||
"group": "external",
|
||||
"section": "smokeping",
|
||||
|
||||
@@ -1326,6 +1326,28 @@ poller_cluster:
|
||||
- { Field: poller_groups, Type: varchar(255), 'Null': false, Extra: '', Default: '' }
|
||||
- { Field: last_report, Type: datetime, 'Null': false, Extra: '' }
|
||||
- { Field: master, Type: tinyint, 'Null': false, Extra: '' }
|
||||
- { Field: poller_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: poller_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: poller_workers, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: poller_down_retry, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: discovery_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: discovery_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: discovery_workers, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: services_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: services_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: services_workers, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: billing_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: billing_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: billing_calculate_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: alerting_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: alerting_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: ping_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: ping_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: update_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: update_frequency, Type: int, 'Null': true, Extra: '' }
|
||||
- { Field: loglevel, Type: varchar(8), 'Null': true, Extra: '' }
|
||||
- { Field: watchdog_enabled, Type: tinyint, 'Null': true, Extra: '' }
|
||||
- { Field: watchdog_log, Type: varchar(255), 'Null': true, Extra: '' }
|
||||
Indexes:
|
||||
PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE }
|
||||
poller_cluster_node_id_unique: { Name: poller_cluster_node_id_unique, Columns: [node_id], Unique: true, Type: BTREE }
|
||||
|
||||
Generated
+41
-26
@@ -1464,6 +1464,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-helper-vue-jsx-merge-props": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
|
||||
"integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg=="
|
||||
},
|
||||
"babel-loader": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz",
|
||||
@@ -1716,9 +1721,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bootstrap": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.4.1.tgz",
|
||||
"integrity": "sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==",
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz",
|
||||
"integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
@@ -2017,9 +2022,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
|
||||
"integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
|
||||
"integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.1",
|
||||
@@ -2029,7 +2034,7 @@
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.3.0"
|
||||
"readdirp": "~3.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"anymatch": {
|
||||
@@ -2067,9 +2072,9 @@
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
|
||||
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
|
||||
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@@ -2098,12 +2103,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
|
||||
"integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
|
||||
"integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.0.7"
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
@@ -5401,9 +5406,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.0.tgz",
|
||||
"integrity": "sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ==",
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
|
||||
"integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==",
|
||||
"dev": true
|
||||
},
|
||||
"js-levenshtein": {
|
||||
@@ -7994,9 +7999,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.26.3",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.26.3.tgz",
|
||||
"integrity": "sha512-5NMHI1+YFYw4sN3yfKjpLuV9B5l7MqQ6FlkTcC4FT+oHbBRUZoSjHrrt/mE0nFXJyY2kQtU9ou9HxvFVjLFuuw==",
|
||||
"version": "1.26.5",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.26.5.tgz",
|
||||
"integrity": "sha512-FG2swzaZUiX53YzZSjSakzvGtlds0lcbF+URuU9mxOv7WBh7NhXEVDa4kPKN4hN6fC2TkOTOKqiqp6d53N9X5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": ">=2.0.0 <4.0.0"
|
||||
@@ -9388,9 +9393,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"vue-i18n": {
|
||||
"version": "8.15.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.15.5.tgz",
|
||||
"integrity": "sha512-lIej02+w8lP0k1PEN1xtXqKpQ1hDh17zvDF+7Oc2qJi+cTMDlfPM771w4euVaHO67AxEz4WL9MIgkyn3tkeCtQ=="
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.18.0.tgz",
|
||||
"integrity": "sha512-7DVu8CfoyPoCRWB5TOqfw2kIhk2umagsri4L1V1c0s+lHUC0VbQYoucFprHUELyHU9Legqzt/FxyLGDpBOlX9w=="
|
||||
},
|
||||
"vue-js-toggle-button": {
|
||||
"version": "1.3.3",
|
||||
@@ -9410,15 +9415,25 @@
|
||||
"vue-style-loader": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"vue-multiselect": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz",
|
||||
"integrity": "sha512-s7jmZPlm9FeueJg1RwJtnE9KNPtME/7C8uRWSfp9/yEN4M8XcS/d+bddoyVwVnvFyRh9msFo0HWeW0vTL8Qv+w=="
|
||||
},
|
||||
"vue-nav-tabs": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/vue-nav-tabs/-/vue-nav-tabs-0.5.7.tgz",
|
||||
"integrity": "sha512-Oqq7qnb0/JPAVSqM0haQ9TdEZaTbQq20TVn5ZCmBOu8m9qju9bI8cDdtWGHXSiMkpmhzsT83ybRb7S/+UYXRsw=="
|
||||
},
|
||||
"vue-resize": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
|
||||
"integrity": "sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg=="
|
||||
},
|
||||
"vue-select": {
|
||||
"version": "3.9.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-select/-/vue-select-3.9.4.tgz",
|
||||
"integrity": "sha512-91vvz2WcmlMTzKI2LbA+jxhHjVwuFhGZXV20F7XxIeF/+A7PLfBTu8mCHh51ELF/UF6YsXAvd8t7BUhx8sydzQ=="
|
||||
"version": "3.10.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-select/-/vue-select-3.10.3.tgz",
|
||||
"integrity": "sha512-SgLmiSwnJwT2erxjq42AA1iTzu1uqhA5MPuF4UDtGot5YSgJLKy71H0LO0hHaBpIjb7d/nJHiufYKcrSakaupw=="
|
||||
},
|
||||
"vue-style-loader": {
|
||||
"version": "4.1.2",
|
||||
|
||||
+8
-5
@@ -13,24 +13,27 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.19.2",
|
||||
"bootstrap": "^4.4.1",
|
||||
"bootstrap": "^4.5.0",
|
||||
"cross-env": "^5.2.1",
|
||||
"jquery": "^3.5",
|
||||
"jquery": "^3.5.1",
|
||||
"laravel-mix": "^4.1.4",
|
||||
"lodash": "^4.17.15",
|
||||
"popper.js": "^1.16.1",
|
||||
"resolve-url-loader": "^2.3.1",
|
||||
"sass": "^1.26.3",
|
||||
"sass": "^1.26.5",
|
||||
"sass-loader": "^7.3.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
||||
"es6-object-assign": "^1.1.0",
|
||||
"v-tooltip": "^2.0.3",
|
||||
"vue-i18n": "^8.15.5",
|
||||
"vue-i18n": "^8.18.0",
|
||||
"vue-js-toggle-button": "^1.3.3",
|
||||
"vue-select": "^3.9.4",
|
||||
"vue-multiselect": "^2.1.6",
|
||||
"vue-nav-tabs": "^0.5.7",
|
||||
"vue-select": "^3.10.3",
|
||||
"vuedraggable": "^2.23.2"
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
@@ -30,11 +30,17 @@ Vue.use(VTooltip);
|
||||
import vSelect from 'vue-select'
|
||||
Vue.component('v-select', vSelect);
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
route: route
|
||||
}
|
||||
});
|
||||
import Multiselect from 'vue-multiselect'
|
||||
Vue.component('multiselect', Multiselect)
|
||||
|
||||
import VueTabs from 'vue-nav-tabs'
|
||||
Vue.use(VueTabs)
|
||||
|
||||
// Vue.mixin({
|
||||
// methods: {
|
||||
// route: route
|
||||
// }
|
||||
// });
|
||||
|
||||
Vue.filter('ucfirst', function (value) {
|
||||
if (!value) return '';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!--
|
||||
- LibrenmsSetting.vue
|
||||
-
|
||||
- Description-
|
||||
-
|
||||
-
|
||||
- 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
|
||||
@@ -26,9 +26,9 @@
|
||||
<div :class="['form-group', 'has-feedback', setting.class, feedback]">
|
||||
<label :for="setting.name" class="col-sm-5 control-label" v-tooltip="{ content: setting.name }">
|
||||
{{ getDescription() }}
|
||||
<span v-if="setting.units !== null">({{ setting.units }})</span>
|
||||
<span v-if="setting.units">({{ getUnits() }})</span>
|
||||
</label>
|
||||
<div class="col-sm-5" v-tooltip="{ content: setting.disabled ? $t('settings.readonly') : false }">
|
||||
<div class="col-sm-5" v-tooltip="{ content: setting.disabled ? $t(this.prefix + '.readonly') : false }">
|
||||
<component :is="getComponent()"
|
||||
:value="value"
|
||||
:name="setting.name"
|
||||
@@ -53,7 +53,9 @@
|
||||
export default {
|
||||
name: "LibrenmsSetting",
|
||||
props: {
|
||||
'setting': {type: Object, required: true}
|
||||
'setting': {type: Object, required: true},
|
||||
'prefix': {type: String, default: 'settings'},
|
||||
'id': {required: false}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -63,7 +65,7 @@
|
||||
},
|
||||
methods: {
|
||||
persistValue(value) {
|
||||
axios.put(route('settings.update', this.setting.name), {value: value})
|
||||
axios.put(route(this.prefix + '.update', this.getRouteParams()), {value: value})
|
||||
.then((response) => {
|
||||
this.value = response.data.value;
|
||||
this.$emit('setting-updated', {name: this.setting.name, value: this.value});
|
||||
@@ -91,7 +93,7 @@
|
||||
this.persistValue(value)
|
||||
}, 500),
|
||||
changeValue(value) {
|
||||
if (['select', 'boolean'].includes(this.setting.type)) {
|
||||
if (['select', 'boolean', 'multiple'].includes(this.setting.type)) {
|
||||
// no need to debounce
|
||||
this.persistValue(value);
|
||||
} else {
|
||||
@@ -99,24 +101,28 @@
|
||||
}
|
||||
this.value = value
|
||||
},
|
||||
getUnits() {
|
||||
let key = this.prefix + '.units.' + this.setting.units;
|
||||
return this.$te(key) ? this.$t(key) : this.setting.units
|
||||
},
|
||||
getDescription() {
|
||||
let key = 'settings.settings.' + this.setting.name + '.description';
|
||||
let key = this.prefix + '.settings.' + this.setting.name + '.description';
|
||||
return (this.$te(key) || this.$te(key, this.$i18n.fallbackLocale)) ? this.$t(key) : this.setting.name;
|
||||
},
|
||||
getHelp() {
|
||||
let help = this.$t('settings.settings.' + this.setting.name + '.help');
|
||||
let help = this.$t(this.prefix + '.settings.' + this.setting.name + '.help');
|
||||
if (this.setting.overridden) {
|
||||
help += "</p><p>" + this.$t('settings.readonly')
|
||||
help += "</p><p>" + this.$t(this.prefix + '.readonly')
|
||||
}
|
||||
|
||||
return help
|
||||
},
|
||||
hasHelp() {
|
||||
var key = 'settings.settings.' + this.setting.name + '.help';
|
||||
let key = this.prefix + '.settings.' + this.setting.name + '.help';
|
||||
return this.$te(key) || this.$te(key, this.$i18n.fallbackLocale)
|
||||
},
|
||||
resetToDefault() {
|
||||
axios.delete(route('settings.destroy', this.setting.name))
|
||||
axios.delete(route(this.prefix + '.destroy', this.getRouteParams()))
|
||||
.then((response) => {
|
||||
this.value = response.data.value;
|
||||
this.feedback = 'has-success';
|
||||
@@ -138,6 +144,13 @@
|
||||
showUndo() {
|
||||
return !_.isEqual(this.setting.value, this.value);
|
||||
},
|
||||
getRouteParams() {
|
||||
let parameters = [this.setting.name];
|
||||
if (this.id) {
|
||||
parameters.unshift(this.id);
|
||||
}
|
||||
return parameters;
|
||||
},
|
||||
getComponent() {
|
||||
// snake to studly
|
||||
const component = 'Setting' + this.setting.type.toString()
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<!--
|
||||
- PollerSettings.vue
|
||||
-
|
||||
- Description-
|
||||
-
|
||||
- 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 2020 Tony Murray
|
||||
- @author Tony Murray <murraytony@gmail.com>
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{{ $t('Poller Settings') }}
|
||||
<span class="pull-right">Advanced <toggle-button v-model="advanced"></toggle-button></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<vue-tabs direction="vertical" type="pills">
|
||||
<v-tab :title="poller.poller_name" v-for="(poller, id) in pollers" :key="id">
|
||||
<div class="setting-container clearfix"
|
||||
v-for="setting in settings[id]"
|
||||
v-if="!setting.advanced || advanced"
|
||||
:key="setting.name">
|
||||
<librenms-setting
|
||||
prefix="poller.settings"
|
||||
:setting='setting'
|
||||
:id="poller.id"
|
||||
></librenms-setting>
|
||||
</div>
|
||||
</v-tab>
|
||||
</vue-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "PollerSettings",
|
||||
props: {
|
||||
'pollers': Object,
|
||||
'settings': Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
advanced: false
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tab-content {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.setting-container {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,75 @@
|
||||
<!--
|
||||
- SettingMultiple.vue
|
||||
-
|
||||
- Setting for multiple select option. Value is expected to be a comma delimited string
|
||||
-
|
||||
- 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 2020 Tony Murray
|
||||
- @author Tony Murray <murraytony@gmail.com>
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<multiselect
|
||||
@input="$emit('input', mutateInputEvent($event))"
|
||||
:value="formattedValue"
|
||||
:required="required"
|
||||
:disabled="disabled"
|
||||
:name="name"
|
||||
label="label"
|
||||
track-by="value"
|
||||
:options="formattedOptions"
|
||||
:allow-empty="false"
|
||||
:multiple="true"
|
||||
>
|
||||
</multiselect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BaseSetting from "./BaseSetting";
|
||||
|
||||
export default {
|
||||
name: "SettingMultiple",
|
||||
mixins: [BaseSetting],
|
||||
computed: {
|
||||
formattedValue() {
|
||||
if (this.value === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
let values = this.value.toString().split(',')
|
||||
return this.formatOptions(_.pick(this.options, ...values))
|
||||
},
|
||||
formattedOptions() {
|
||||
return this.formatOptions(this.options)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatOptions(options) {
|
||||
return Object.entries(options).map(([k, v]) => ({label: v, value: k}))
|
||||
},
|
||||
mutateInputEvent(options) {
|
||||
return options.map(option => option.value).join(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
return [
|
||||
'settings' => [
|
||||
'settings' => [
|
||||
'poller_groups' => [
|
||||
'description' => 'Assigned Groups',
|
||||
'help' => 'This node will only take action on devices in these poller groups.'
|
||||
],
|
||||
'poller_enabled' => [
|
||||
'description' => 'Poller Enabled',
|
||||
'help' => 'Enable poller workers on this node.'
|
||||
],
|
||||
'poller_workers' => [
|
||||
'description' => 'Poller Workers',
|
||||
'help' => 'Amount of poller workers to spawn on this node.'
|
||||
],
|
||||
'poller_frequency' => [
|
||||
'description' => 'Poller Frequency',
|
||||
'help' => 'How often to to poll devices on this node. Warning! Changing this is not recommended. See docs for more info.'
|
||||
],
|
||||
'poller_down_retry' => [
|
||||
'description' => 'Device Down Retry',
|
||||
'help' => 'If a device is down when polling is attempted on this node. This is the amount of time to wait before retrying.'
|
||||
],
|
||||
'discovery_enabled' => [
|
||||
'description' => 'Discovery Enabled',
|
||||
'help' => 'Enable discovery workers on this node.'
|
||||
],
|
||||
'discovery_workers' => [
|
||||
'description' => 'Discovery Workers',
|
||||
'help' => 'Amount of discovery workers to run on this node. Setting too high can cause overload.'
|
||||
],
|
||||
'discovery_frequency' => [
|
||||
'description' => 'Discovery Frequency',
|
||||
'help' => 'How often to run device discovery on this node. Default is 4 times a day.'
|
||||
],
|
||||
'services_enabled' => [
|
||||
'description' => 'Services Enabled',
|
||||
'help' => 'Enable services workers on this node.'
|
||||
],
|
||||
'services_workers' => [
|
||||
'description' => 'Services Workers',
|
||||
'help' => 'Amount of services workers on this node.'
|
||||
],
|
||||
'services_frequency' => [
|
||||
'description' => 'Services Frequency',
|
||||
'help' => 'How often to run services on this node. This should match poller frequency.'
|
||||
],
|
||||
'billing_enabled' => [
|
||||
'description' => 'Billing Enabled',
|
||||
'help' => 'Enable billing workers on this node.'
|
||||
],
|
||||
'billing_frequency' => [
|
||||
'description' => 'Billing Frequency',
|
||||
'help' => 'How often to collect billing data on this node.'
|
||||
],
|
||||
'billing_calculate_frequency' => [
|
||||
'description' => 'Billing Calculate Frequency',
|
||||
'help' => 'How often to calculate bill usage on this node.'
|
||||
],
|
||||
'alerting_enabled' => [
|
||||
'description' => 'Alerting Enabled',
|
||||
'help' => 'Enable the alerting worker on this node.'
|
||||
],
|
||||
'alerting_frequency' => [
|
||||
'description' => 'Alerting Frequency',
|
||||
'help' => 'How often alert rules are checked on this node. Note that data is only updated based on poller frequency.'
|
||||
],
|
||||
'ping_enabled' => [
|
||||
'description' => 'Fast Ping Enabled',
|
||||
'help' => 'Fast Ping just pings devices to check if they are up or down'
|
||||
],
|
||||
'ping_frequency' => [
|
||||
'description' => 'Ping Frequency',
|
||||
'help' => 'How often to check ping on this node. Warning! If you change this you must make additional changes. Check the Fast Ping docs.'
|
||||
],
|
||||
'update_enabled' => [
|
||||
'description' => 'Daily Maintenance Enabled',
|
||||
'help' => 'Run daily.sh maintenance script and restart the dispatcher service afterwards.'
|
||||
],
|
||||
'update_frequency' => [
|
||||
'description' => 'Maintenance Frequency',
|
||||
'help' => 'How often to run daily maintenance on this node. Default is 1 Day. It is highly suggested not to change this.'
|
||||
],
|
||||
'loglevel' => [
|
||||
'description' => 'Log Level',
|
||||
'help' => 'Log level of the dispatch service.'
|
||||
],
|
||||
'watchdog_enabled' => [
|
||||
'description' => 'Watchdog Enabled',
|
||||
'help' => 'Watchdog monitors the log file and restarts the service it it has not been updated'
|
||||
],
|
||||
'watchdog_log' => [
|
||||
'description' => 'Log File to Watch',
|
||||
'help' => 'Default is the LibreNMS log file.'
|
||||
],
|
||||
],
|
||||
'units' => [
|
||||
'seconds' => 'Seconds',
|
||||
'workers' => 'Workers',
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -9,3 +9,9 @@
|
||||
|
||||
// Vue Select
|
||||
@import "~vue-select/src/scss/vue-select.scss";
|
||||
|
||||
// Vue Multiselect
|
||||
@import "~vue-multiselect/dist/vue-multiselect.min.css";
|
||||
|
||||
// Vue Tabs
|
||||
@import '~vue-nav-tabs/themes/vue-tabs.css';
|
||||
|
||||
@@ -540,11 +540,12 @@
|
||||
aria-hidden="true"></i> @lang('Auth History')</a></li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
<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>
|
||||
<a href="{{ route('poller.index') }}"><i class="fa fa-th-large fa-fw fa-lg" aria-hidden="true"></i> @lang('Poller')</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ route('poller') }}"><i class="fa fa-th-large fa-fw fa-lg" aria-hidden="true"></i> @lang('Poller')</a></li>
|
||||
<li><a href="{{ route('poller.index') }}"><i class="fa fa-th-large fa-fw fa-lg" aria-hidden="true"></i> @lang('Poller')</a></li>
|
||||
@config('distributed_poller')
|
||||
<li><a href="{{ route('poller.groups') }}"><i class="fa fa-th fa-fw fa-lg" aria-hidden="true"></i> @lang('Groups')</a></li>
|
||||
<li><a href="{{ route('poller.settings') }}"><i class="fa fa-gears fa-fw fa-lg" aria-hidden="true"></i> @lang('Settings')</a></li>
|
||||
@endconfig
|
||||
<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>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
@parent
|
||||
|
||||
<br />
|
||||
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#poller-groups">@lang('Create new poller group')</button>
|
||||
<br /><br />
|
||||
<div class="table-responsive">
|
||||
|
||||
@@ -6,12 +6,17 @@
|
||||
<div class="col-md-12">
|
||||
<ul class="nav nav-tabs">
|
||||
<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>
|
||||
<a href="{{ route('poller.index') }}"><i class="fa fa-th-large fa-lg icon-theme" aria-hidden="true"></i> @lang('Poller')</a>
|
||||
</li>
|
||||
@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>
|
||||
@if(\App\Models\PollerCluster::exists())
|
||||
<li role="presentation" @if( $current_tab == 'settings' ) class="active" @endif>
|
||||
<a href="{{ route('poller.settings') }}"><i class="fa fa-gears fa-lg icon-theme" aria-hidden="true"></i> @lang('Settings')</a>
|
||||
</li>
|
||||
@endif
|
||||
@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>
|
||||
@@ -20,6 +25,7 @@
|
||||
<a href="{{ route('poller.log') }}"><i class="fa fa-file-text fa-lg icon-theme" aria-hidden="true"></i> @lang('Log')</a>
|
||||
</li>
|
||||
</ul>
|
||||
<br />
|
||||
@endsection
|
||||
|
||||
@section('content_footer')
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
@parent
|
||||
|
||||
<br />
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Total Poller Time</h3>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
@parent
|
||||
|
||||
<br />
|
||||
@if( $pollers->isNotEmpty() )
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
@extends('poller.index')
|
||||
|
||||
@section('title', __('Poller Settings'))
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
<div id="app">
|
||||
<poller-settings
|
||||
:pollers='@json($poller_cluster, JSON_FORCE_OBJECT)'
|
||||
:settings='@json($settings, JSON_FORCE_OBJECT)'
|
||||
></poller-settings>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('styles')
|
||||
<link href="{{ asset(mix('/css/app.css')) }}" rel="stylesheet">
|
||||
@endpush
|
||||
|
||||
@section('javascript')
|
||||
<script src="{{ asset(mix('/js/lang/en.js')) }}"></script>
|
||||
<script src="{{ asset(mix('/js/lang/' . app()->getLocale() . '.js')) }}"></script>
|
||||
<script src="{{ asset(mix('/js/manifest.js')) }}"></script>
|
||||
<script src="{{ asset(mix('/js/vendor.js')) }}"></script>
|
||||
@routes
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script src="{{ asset(mix('/js/app.js')) }}"></script>
|
||||
@endpush
|
||||
+8
-4
@@ -19,10 +19,14 @@ Route::group(['middleware' => ['auth.web'], 'guard' => 'auth'], function () {
|
||||
|
||||
// pages
|
||||
Route::resource('device-groups', 'DeviceGroupController');
|
||||
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::group(['prefix' => 'poller'], function () {
|
||||
Route::get('', 'PollerController@pollerTab')->name('poller.index');
|
||||
Route::get('log', 'PollerController@logTab')->name('poller.log');
|
||||
Route::get('groups', 'PollerController@groupsTab')->name('poller.groups');
|
||||
Route::get('settings', 'PollerController@settingsTab')->name('poller.settings');
|
||||
Route::get('performance', 'PollerController@performanceTab')->name('poller.performance');
|
||||
Route::resource('{id}/settings', 'PollerSettingsController', ['as' => 'poller'])->only(['update', 'destroy']);
|
||||
});
|
||||
Route::get('locations', 'LocationController@index');
|
||||
Route::resource('preferences', 'UserPreferencesController', ['only' => ['index', 'store']]);
|
||||
Route::resource('users', 'UserController');
|
||||
|
||||
Reference in New Issue
Block a user