mirror of
https://github.com/librenms/librenms.git
synced 2024-09-21 10:28:13 +00:00
Device Availability Calculation (#11784)
* Device Availability Calculation * Travis fix * . * schema corrections * flexible duration * travis * . * . * . * . * remove not needed code * line Text to RRD * update humantime * . * only set up again if device was marked as down * set RRD area transparency * save uptime also, to keep last availability as good as possible * file description correction * look for outages even if uptime > duration
This commit is contained in:
parent
7264ab7ff7
commit
4e6a7291a2
120
LibreNMS/Device/Availability.php
Normal file
120
LibreNMS/Device/Availability.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* Availability.php
|
||||
*
|
||||
* Availability calculation
|
||||
*
|
||||
* 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 Thomas Berberich
|
||||
* @author Thomas Berberich <sourcehhdoctor@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Device;
|
||||
|
||||
use \App\Models\DeviceOutage;
|
||||
|
||||
class Availability
|
||||
{
|
||||
/*
|
||||
* 1 day 1 * 24 * 60 * 60 = 86400
|
||||
* 1 week 7 * 24 * 60 * 60 = 604800
|
||||
* 1 month 30 * 24 * 60 * 60 = 2592000
|
||||
* 1 year 365 * 24 * 60 * 60 = 31536000
|
||||
*/
|
||||
|
||||
public static function day($device, $precision = 3)
|
||||
{
|
||||
$duration = 86400;
|
||||
return self::availability($device, $duration, $precision);
|
||||
}
|
||||
|
||||
public static function week($device, $precision = 3)
|
||||
{
|
||||
$duration = 604800;
|
||||
return self::availability($device, $duration, $precision);
|
||||
}
|
||||
|
||||
public static function month($device, $precision = 3)
|
||||
{
|
||||
$duration = 2592000;
|
||||
return self::availability($device, $duration, $precision);
|
||||
}
|
||||
|
||||
public static function year($device, $precision = 3)
|
||||
{
|
||||
$duration = 31536000;
|
||||
return self::availability($device, $duration, $precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the availability of this device
|
||||
*
|
||||
* @param int $duration timeperiod in seconds
|
||||
* @param int $precision after comma precision
|
||||
* @return availability in %
|
||||
*/
|
||||
public static function availability($device, $duration, $precision = 3)
|
||||
{
|
||||
if (!is_numeric($device['uptime'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
|
||||
$query = DeviceOutage::where('device_id', '=', $device['device_id'])
|
||||
->where('up_again', '>=', $now - $duration)
|
||||
->orderBy('going_down');
|
||||
|
||||
$found_outages = $query->get();
|
||||
|
||||
# no recorded outages found, so use current uptime
|
||||
if (!count($found_outages)) {
|
||||
# uptime is greater duration interval -> full availability
|
||||
if ($device['uptime'] >= $duration) {
|
||||
return 100 * 1;
|
||||
} else {
|
||||
return round(100 * $device['uptime'] / $duration, $precision);
|
||||
}
|
||||
}
|
||||
|
||||
$oldest_date_going_down = $query->first()->value('going_down');
|
||||
$oldest_uptime = $query->first()->value('uptime');
|
||||
$recorded_duration = $now - ($oldest_date_going_down - $oldest_uptime);
|
||||
|
||||
if ($recorded_duration > $duration) {
|
||||
$recorded_duration = $duration;
|
||||
}
|
||||
|
||||
# sum up time period of all outages
|
||||
$outage_summary = 0;
|
||||
foreach ($found_outages as $outage) {
|
||||
# if device is still down, outage goes till $now
|
||||
$up_again = $outage->up_again ?: $now;
|
||||
|
||||
if ($outage->going_down >= ($now - $duration)) {
|
||||
# outage complete in duration period
|
||||
$going_down = $outage->going_down;
|
||||
} else {
|
||||
# outage partial in duration period, so consider only relevant part
|
||||
$going_down = $now - $duration;
|
||||
}
|
||||
$outage_summary += ($up_again - $going_down);
|
||||
}
|
||||
|
||||
return round(100 * ($recorded_duration - $outage_summary) / $duration, $precision);
|
||||
}
|
||||
}
|
@ -83,4 +83,54 @@ class Time
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param integer seconds of a time period
|
||||
* @return string human readably time period
|
||||
*/
|
||||
public static function humanTime($s)
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
if ($s >= 86400) {
|
||||
$d = floor($s / 86400);
|
||||
$s -= $d * 86400;
|
||||
if ($d == 1) {
|
||||
$ret[] = $d . " day";
|
||||
} else {
|
||||
$ret[] = $d . " days";
|
||||
}
|
||||
}
|
||||
|
||||
if ($s >= 3600) {
|
||||
$h = floor($s / 3600);
|
||||
$s -= $h * 3600;
|
||||
if ($h == 1) {
|
||||
$ret[] = $h . " hour";
|
||||
} else {
|
||||
$ret[] = $h . " hours";
|
||||
}
|
||||
}
|
||||
|
||||
if ($s >= 60) {
|
||||
$m = floor($s / 60);
|
||||
$s -= $m * 60;
|
||||
if ($m == 1) {
|
||||
$ret[] = $m . " minute";
|
||||
} else {
|
||||
$ret[] = $m . " minutes";
|
||||
}
|
||||
}
|
||||
|
||||
if ($s > 0) {
|
||||
if ($s == 1) {
|
||||
$ret[] = $s . " second";
|
||||
} else {
|
||||
$ret[] = $s . " seconds";
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ,', $ret);
|
||||
}
|
||||
}
|
||||
|
34
app/Models/Availability.php
Normal file
34
app/Models/Availability.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* Availability.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 Thomas Berberich
|
||||
* @author Thomas Berberich <sourcehhdoctor@gmail.com>
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Availability extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $table = 'availability';
|
||||
}
|
34
app/Models/DeviceOutage.php
Normal file
34
app/Models/DeviceOutage.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* DeviceOutage.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 Thomas Berberich
|
||||
* @author Thomas Berberich <sourcehhdoctor@gmail.com>
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class DeviceOutage extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $primaryKey = null;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateDeviceOutagesTable extends Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('device_outages', function (Blueprint $table) {
|
||||
$table->unsignedInteger('device_id')->index();
|
||||
$table->bigInteger('going_down');
|
||||
$table->bigInteger('up_again')->nullable();
|
||||
$table->bigInteger('uptime')->nullable();
|
||||
$table->unique(['device_id', 'going_down']);
|
||||
});
|
||||
Schema::create('availability', function (Blueprint $table) {
|
||||
$table->increments('availability_id');
|
||||
$table->unsignedInteger('device_id')->index();
|
||||
$table->bigInteger('duration');
|
||||
$table->float('availability_perc', 6, 6)->default(0.000000);
|
||||
$table->unique(['device_id','duration']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('device_outages');
|
||||
Schema::drop('availability');
|
||||
}
|
||||
}
|
@ -99,6 +99,7 @@ $config['poller_modules']['aruba-controller'] = false;
|
||||
$config['poller_modules']['entity-physical'] = true;
|
||||
$config['poller_modules']['entity-state'] = false;
|
||||
$config['poller_modules']['applications'] = true;
|
||||
$config['poller_modules']['availability'] = true;
|
||||
$config['poller_modules']['mib'] = false;
|
||||
$config['poller_modules']['stp'] = true;
|
||||
$config['poller_modules']['ntp'] = true;
|
||||
@ -190,6 +191,8 @@ configured to be ignored by config options.
|
||||
|
||||
`applications`: Device application support.
|
||||
|
||||
`availability`: Device Availability Calculation.
|
||||
|
||||
`cisco-asa-firewall`: Cisco ASA firewall support.
|
||||
|
||||
`mib`: Support for generic MIB parsing.
|
||||
|
@ -2109,9 +2109,32 @@ function device_is_up($device, $record_perf = false)
|
||||
if ($response['status']) {
|
||||
$type = 'up';
|
||||
$reason = $device['status_reason'];
|
||||
|
||||
if ($device['uptime']) {
|
||||
$going_down = dbFetchCell('SELECT going_down FROM device_outages WHERE device_id=? AND up_again IS NULL', array($device['device_id']));
|
||||
if (!empty($going_down)) {
|
||||
$up_again = time() - $device['uptime'];
|
||||
if ($up_again <= $going_down) {
|
||||
# network connection loss, not device down
|
||||
$up_again = time();
|
||||
}
|
||||
dbUpdate(
|
||||
array('device_id' => $device['device_id'], 'up_again' => $up_again),
|
||||
'device_outages',
|
||||
'device_id=? and up_again is NULL',
|
||||
array($device['device_id'])
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$type = 'down';
|
||||
$reason = $response['status_reason'];
|
||||
if ($device['uptime']) {
|
||||
$data = ['device_id' => $device['device_id'],
|
||||
'uptime' => $device['uptime'],
|
||||
'going_down' => strtotime($device['last_polled'])];
|
||||
dbInsert($data, 'device_outages');
|
||||
}
|
||||
}
|
||||
|
||||
log_event('Device status changed to ' . ucfirst($type) . " from $reason check.", $device, $type);
|
||||
|
25
includes/html/graphs/device/availability.inc.php
Normal file
25
includes/html/graphs/device/availability.inc.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
$scale_min = '0';
|
||||
$scale_max = '100';
|
||||
$float_precision = '3';
|
||||
|
||||
$rrd_filename = rrd_name($device['hostname'], array('availability', $vars['duration']));
|
||||
|
||||
$ds = 'availability';
|
||||
|
||||
$colour_line = '000000';
|
||||
$colour_area = '8B8BEB44';
|
||||
|
||||
$colour_area_max = 'cc9999';
|
||||
|
||||
$line_text = \LibreNMS\Util\Time::humanTime($vars['duration']);
|
||||
|
||||
$graph_title .= '::'.$line_text;
|
||||
|
||||
$graph_max = 1;
|
||||
$graph_min = 0;
|
||||
|
||||
$unit_text = 'Availability(%)';
|
||||
|
||||
require 'includes/html/graphs/generic_simplex.inc.php';
|
@ -54,9 +54,14 @@ unset($sep);
|
||||
|
||||
print_optionbar_end();
|
||||
|
||||
$graph_enable = $graph_enable[$vars['group']];
|
||||
$group = $vars['group'];
|
||||
$graph_enable = $graph_enable[$group];
|
||||
|
||||
foreach ($graph_enable as $graph => $entry) {
|
||||
$metric = basename($vars['metric']);
|
||||
if (is_file("includes/html/pages/device/graphs/$group.inc.php")) {
|
||||
include "includes/html/pages/device/graphs/$group.inc.php";
|
||||
} else {
|
||||
foreach ($graph_enable as $graph => $entry) {
|
||||
$graph_array = array();
|
||||
if ($graph_enable[$graph]) {
|
||||
if ($graph == 'customoid') {
|
||||
@ -76,6 +81,6 @@ foreach ($graph_enable as $graph => $entry) {
|
||||
include 'includes/html/print-device-graph.php';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pagetitle[] = 'Graphs';
|
||||
|
31
includes/html/pages/device/graphs/availability.inc.php
Normal file
31
includes/html/pages/device/graphs/availability.inc.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
$graph_type = 'availability';
|
||||
|
||||
$row = 1;
|
||||
|
||||
$duration_list = dbFetchRows("SELECT * FROM `availability` WHERE `device_id` = ? ORDER BY `duration`", array($device['device_id']));
|
||||
foreach ($duration_list as $duration) {
|
||||
if (is_integer($row / 2)) {
|
||||
$row_colour = \LibreNMS\Config::get('list_colour.even');
|
||||
} else {
|
||||
$row_colour = \LibreNMS\Config::get('list_colour.odd');
|
||||
}
|
||||
|
||||
$graph_array['device'] = $duration['device_id'];
|
||||
$graph_array['type'] = 'device_'.$graph_type;
|
||||
$graph_array['duration'] = $duration['duration'];
|
||||
|
||||
$human_duration = \LibreNMS\Util\Time::humanTime($duration['duration']);
|
||||
$graph_title = $device['hostname'].' - '.$human_duration;
|
||||
|
||||
echo "<div class='panel panel-default'>
|
||||
<div class='panel-heading'>
|
||||
<h3 class='panel-title'>".$human_duration."<div class='pull-right'>".$duration['availability_perc']."%</div></h3>
|
||||
</div>";
|
||||
echo "<div class='panel-body'>";
|
||||
include 'includes/html/print-graphrow.inc.php';
|
||||
echo "</div></div>";
|
||||
|
||||
$row++;
|
||||
}
|
46
includes/polling/availability.inc.php
Normal file
46
includes/polling/availability.inc.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use LibreNMS\RRD\RrdDefinition;
|
||||
use LibreNMS\Config;
|
||||
|
||||
if (isset($device['uptime']) && ($device['uptime'] > 0 )) {
|
||||
$graphs['availability'] = true;
|
||||
|
||||
$col = dbFetchColumn('SELECT duration FROM availability WHERE device_id = ?', array($device['device_id']));
|
||||
foreach (Config::get('graphing.availability') as $duration) {
|
||||
if (!in_array($duration, $col)) {
|
||||
$data = ['device_id' => $device['device_id'],
|
||||
'duration' => $duration];
|
||||
dbInsert($data, 'availability');
|
||||
}
|
||||
}
|
||||
|
||||
echo 'Availability: ' . PHP_EOL;
|
||||
|
||||
foreach (dbFetchRows('SELECT * FROM availability WHERE device_id = ?', array($device['device_id'])) as $row) {
|
||||
//delete not more interested availabilities
|
||||
if (!in_array($row['duration'], Config::get('graphing.availability'))) {
|
||||
dbDelete('availability', 'availability_id=?', array($row['availability_id']));
|
||||
continue;
|
||||
}
|
||||
|
||||
$avail = \LibreNMS\Device\Availability::availability($device, $row['duration']);
|
||||
$human_time = \LibreNMS\Util\Time::humanTime($row['duration']);
|
||||
|
||||
$rrd_name = array('availability', $row['duration']);
|
||||
$rrd_def = RrdDefinition::make()
|
||||
->addDataset('availability', 'GAUGE', 0);
|
||||
|
||||
$fields = array(
|
||||
'availability' => $avail,
|
||||
);
|
||||
|
||||
$tags = array('name' => $row['duration'], 'rrd_def' => $rrd_def, 'rrd_name' => $rrd_name);
|
||||
data_update($device, 'availability', $tags, $fields);
|
||||
|
||||
dbUpdate(array('availability_perc' => $avail), 'availability', '`availability_id` = ?', array($row['availability_id']));
|
||||
|
||||
echo $human_time . ' : ' . $avail . '%'. PHP_EOL;
|
||||
}
|
||||
unset($duration);
|
||||
}
|
@ -612,6 +612,18 @@
|
||||
"/-K9W8-/"
|
||||
]
|
||||
},
|
||||
"graphing.availability": {
|
||||
"group": "graphing",
|
||||
"section": "availability",
|
||||
"order": 0,
|
||||
"default": [
|
||||
"86400",
|
||||
"604800",
|
||||
"2592000",
|
||||
"31536000"
|
||||
],
|
||||
"type": "array"
|
||||
},
|
||||
"bad_disk_regexp": {
|
||||
"default": [],
|
||||
"type": "array"
|
||||
@ -2783,6 +2795,14 @@
|
||||
},
|
||||
"type": "graph"
|
||||
},
|
||||
"graph_types.device.availability": {
|
||||
"default": {
|
||||
"section": "availability",
|
||||
"order": 0,
|
||||
"descr": "Device Availability"
|
||||
},
|
||||
"type": "graph"
|
||||
},
|
||||
"graph_types.device.sub10_sub10RadioLclAFER": {
|
||||
"default": {
|
||||
"section": "wireless",
|
||||
@ -4013,6 +4033,13 @@
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"poller_modules.availability": {
|
||||
"order": 25,
|
||||
"group": "poller",
|
||||
"section": "poller_modules",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"poller_modules.os": {
|
||||
"order": 320,
|
||||
"group": "poller",
|
||||
|
@ -189,6 +189,17 @@ authlog:
|
||||
- { Field: result, Type: text, 'Null': false, Extra: '' }
|
||||
Indexes:
|
||||
PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE }
|
||||
availability:
|
||||
Columns:
|
||||
- { Field: availability_id, Type: 'int unsigned', 'Null': false, Extra: auto_increment }
|
||||
- { Field: device_id, Type: 'int unsigned', 'Null': false, Extra: '' }
|
||||
- { Field: duration, Type: bigint, 'Null': false, Extra: '' }
|
||||
- { Field: availability_perc, Type: 'double(6,6)', 'Null': false, Extra: '', Default: '0.000000' }
|
||||
Indexes:
|
||||
PRIMARY: { Name: PRIMARY, Columns: [availability_id], Unique: true, Type: BTREE }
|
||||
availability_device_id_index: { Name: availability_device_id_index, Columns: [device_id], Unique: false, Type: BTREE }
|
||||
availability_device_id_duration_unique: { Name: availability_device_id_duration_unique, Columns: [device_id, duration], Unique: true, Type: BTREE }
|
||||
|
||||
bgpPeers:
|
||||
Columns:
|
||||
- { Field: bgpPeer_id, Type: 'int unsigned', 'Null': false, Extra: auto_increment }
|
||||
@ -559,6 +570,15 @@ device_groups:
|
||||
Indexes:
|
||||
PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE }
|
||||
device_groups_name_unique: { Name: device_groups_name_unique, Columns: [name], Unique: true, Type: BTREE }
|
||||
device_outages:
|
||||
Columns:
|
||||
- { Field: device_id, Type: 'int unsigned', 'Null': false, Extra: '' }
|
||||
- { Field: going_down, Type: bigint, 'Null': false, Extra: '' }
|
||||
- { Field: up_again, Type: bigint, 'Null': true, Extra: '' }
|
||||
- { Field: uptime, Type: bigint, 'Null': true, Extra: '' }
|
||||
Indexes:
|
||||
device_outages_device_id_index: { Name: device_outages_device_id_index, Columns: [device_id], Unique: false, Type: BTREE }
|
||||
device_outages_device_id_going_down_unique: { Name: device_outages_device_id_going_down_unique, Columns: [device_id, going_down], Unique: true, Type: BTREE }
|
||||
device_group_device:
|
||||
Columns:
|
||||
- { Field: device_group_id, Type: 'int unsigned', 'Null': false, Extra: '' }
|
||||
|
@ -11,6 +11,7 @@ return [
|
||||
'global' => 'Global',
|
||||
'os' => 'OS',
|
||||
'discovery' => 'Discovery',
|
||||
'graphing' => 'Graphing',
|
||||
'poller' => 'Poller',
|
||||
'system' => 'System',
|
||||
'webui' => 'Web UI',
|
||||
@ -45,6 +46,9 @@ return [
|
||||
'unix-agent' => 'Unix-Agent Integration',
|
||||
'smokeping' => 'Smokeping Integration'
|
||||
],
|
||||
'graphing' => [
|
||||
'availability' => 'Device Availability',
|
||||
],
|
||||
'poller' => [
|
||||
'distributed' => 'Distributed Poller',
|
||||
'graphite' => 'Datastore: Graphite',
|
||||
@ -636,6 +640,12 @@ return [
|
||||
'help' => 'Will add the prefix to the start of all metrics. Must be alphanumeric separated by dots'
|
||||
]
|
||||
],
|
||||
'graphing' => [
|
||||
'availability' => [
|
||||
'description' => 'Duration',
|
||||
'help' => 'Calculate Device Availability for listed durations. (Durations are defined in seconds)'
|
||||
],
|
||||
],
|
||||
'graylog' => [
|
||||
'base_uri' => [
|
||||
'description' => 'Base URI',
|
||||
@ -1001,6 +1011,9 @@ return [
|
||||
'aruba-controller' => [
|
||||
'description' => 'Aruba Controller'
|
||||
],
|
||||
'availability' => [
|
||||
'description' => 'Availability'
|
||||
],
|
||||
'entity-physical' => [
|
||||
'description' => 'Entity Physical'
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user