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:
Tony Murray
2020-06-08 08:27:03 -05:00
committed by GitHub
parent 946e90b68d
commit 300645388f
29 changed files with 1134 additions and 86 deletions
+68 -6
View File
@@ -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')
+22
View File
@@ -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]);
}
}
+195
View File
@@ -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');
+6 -1
View File
@@ -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');
+106
View File
@@ -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();
}
}
+1
View File
@@ -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
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+9 -9
View File
@@ -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
View File
@@ -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",
+22
View File
@@ -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 }
+41 -26
View File
@@ -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
View File
@@ -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
View File
@@ -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 '';
+24 -11
View File
@@ -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>
+103
View File
@@ -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',
],
],
];
+6
View File
@@ -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';
+3 -2
View File
@@ -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>
-1
View File
@@ -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">
+7 -1
View File
@@ -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>
-1
View File
@@ -6,7 +6,6 @@
@parent
<br />
@if( $pollers->isNotEmpty() )
<div class="panel panel-default">
<div class="panel-heading">
+29
View File
@@ -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
View File
@@ -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');