Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Rewrite Wireless Controller polling #13198

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
42d348b
Remove duplicate access points
ottorei Sep 7, 2021
6f5a9be
Poller
ottorei Sep 8, 2021
2d6b1ed
Implement keyable
ottorei Sep 8, 2021
8ac9ff1
synmodels test
ottorei Sep 8, 2021
86978ef
syncmodels
ottorei Sep 8, 2021
ee1d118
syncmodels test
ottorei Sep 8, 2021
5777603
add cleanup
ottorei Sep 9, 2021
6188520
keyable
ottorei Sep 9, 2021
b73261c
fix relationship
ottorei Sep 9, 2021
b01dd71
Implement softdelete
ottorei Sep 10, 2021
890868e
Merge branch 'librenms:master' into accesspoint-duplicates
ottorei Sep 10, 2021
75bc1d2
switchcounters
ottorei Sep 10, 2021
eec0144
softdelete restore, switchcounters
ottorei Sep 10, 2021
a3d1535
softdelete restore, switchcounters
ottorei Sep 10, 2021
b3c97de
todo
ottorei Sep 10, 2021
dffc2c2
a
ottorei Sep 10, 2021
ee50d79
Restore soft-deleted before update
ottorei Sep 10, 2021
fa61310
Add controller RRD
ottorei Sep 11, 2021
d8b4483
Comments
ottorei Sep 11, 2021
f8aa2d6
Merge branch 'librenms:master' into accesspoint-duplicates
ottorei Sep 12, 2021
73984a5
Modules
ottorei Sep 12, 2021
0a642cd
Merge branch 'accesspoint-duplicates' of https://github.com/ottorei/l…
ottorei Sep 12, 2021
f0c91c1
Update module
ottorei Sep 12, 2021
f37e959
Apply fixes from StyleCI
ottorei Sep 12, 2021
0c3561b
Merge pull request #39 from ottorei/analysis-QM95NP
ottorei Sep 12, 2021
c429b54
Schema
ottorei Sep 12, 2021
3384274
Merge remote-tracking branch 'origin/accesspoint-duplicates' into acc…
ottorei Sep 12, 2021
5768886
Schema
ottorei Sep 12, 2021
b5ed4fa
Sensors
ottorei Sep 12, 2021
533d413
Remove total clients
ottorei Sep 12, 2021
610467e
Use devicearray
ottorei Sep 12, 2021
0e855b5
Variable type
ottorei Sep 12, 2021
f6a2891
Change composite key to allow wlc clusters
ottorei Sep 13, 2021
7a72a6a
Merge branch 'librenms:master' into accesspoint-duplicates
ottorei Sep 26, 2021
2ee6135
Merge branch 'librenms:master' into accesspoint-duplicates
ottorei Oct 29, 2021
347408c
Rename module
ottorei Nov 5, 2021
43579f6
Initial Cisco WLC support
ottorei Nov 5, 2021
e555b6a
Rename module, fixes
ottorei Nov 5, 2021
94ca817
Merge branch 'librenms:master' into accesspoint-duplicates
ottorei Nov 5, 2021
082ae3d
Fixes
ottorei Nov 6, 2021
ebeccf7
Merge branch 'accesspoint-duplicates' of https://github.com/ottorei/l…
ottorei Nov 6, 2021
aa36678
Merge upstream, remove ciscowlc ospolling
ottorei Nov 21, 2021
f7809e9
Use osname for prefixes, change composite key
ottorei Nov 28, 2021
777be4a
Convert Vrp to use new module
ottorei Nov 28, 2021
6262faa
Apply fixes from StyleCI
ottorei Nov 28, 2021
8ed0d26
Merge pull request #51 from ottorei/analysis-kaxRGG
ottorei Nov 28, 2021
6ff74da
Web page query
ottorei Nov 28, 2021
945eb3f
Merge branch 'accesspoint-duplicates' of https://github.com/ottorei/l…
ottorei Nov 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -35,6 +35,7 @@ _ide_helper.php
_ide_helper_models.php
resources/views/menu/custom.blade.php
resources/js/vue-i18n-locales.generated.js
debug.txt

# Docs #
########
Expand Down
5 changes: 4 additions & 1 deletion LibreNMS/DB/SyncsModels.php
Expand Up @@ -45,7 +45,10 @@ protected function syncModels($device, $relationship, $models): Collection

foreach ($existing as $exist_key => $exist_value) {
if ($models->offsetExists($exist_key)) {
// update
// update or restore soft-deleted model
if ($exist_value->trashed()) {
$exist_value->restore();
ottorei marked this conversation as resolved.
Show resolved Hide resolved
}
$exist_value->fill($models->get($exist_key)->getAttributes())->save();
} else {
// delete
Expand Down
8 changes: 8 additions & 0 deletions LibreNMS/Interfaces/Polling/WirelessAccessPointPolling.php
@@ -0,0 +1,8 @@
<?php

namespace LibreNMS\Interfaces\Polling;

interface WirelessAccessPointPolling
{
public function pollWirelessAccessPoints();
}
8 changes: 8 additions & 0 deletions LibreNMS/Interfaces/Polling/WirelessCountersPolling.php
@@ -0,0 +1,8 @@
<?php

namespace LibreNMS\Interfaces\Polling;

interface WirelessCountersPolling
{
public function pollWirelessCounters();
}
131 changes: 131 additions & 0 deletions LibreNMS/Modules/Wireless.php
@@ -0,0 +1,131 @@
<?php
/**
* Wireless.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/>.
*
* @link http://librenms.org
*
* @copyright 2021 Otto Reinikainen
* @author Otto Reinikainen <otto@ottorei.fi>
*/

namespace LibreNMS\Modules;

use App\Observers\ModuleModelObserver;
use Illuminate\Support\Collection;
use LibreNMS\DB\SyncsModels;
use LibreNMS\Device\WirelessSensor;
use LibreNMS\Interfaces\Module;
use LibreNMS\Interfaces\Polling\WirelessAccessPointPolling;
use LibreNMS\OS;
use LibreNMS\RRD\RrdDefinition;

class Wireless implements Module
ottorei marked this conversation as resolved.
Show resolved Hide resolved
{
use SyncsModels;

/**
* Discover this module. Heavier processes can be run here
* Run infrequently (default 4 times a day)
*
* @param OS $os
*/
public function discover(OS $os)
{
// Discover wireless sensors
WirelessSensor::runDiscovery($os);
}

/**
* Poll data for this module and update the DB / RRD.
* Try to keep this efficient and only run if discovery has indicated there is a reason to run.
* Run frequently (default every 5 minutes)
*
* @param OS $os
*/
public function poll(OS $os)
{
echo "\nPoll Wireless sensors: ";
WirelessSensor::poll($os);

if ($os instanceof WirelessAccessPointPolling) {
echo "\nPoll Wireless Access Points: ";
$access_points = new Collection;

// Get APs from controller. Uniquely identify by CompositeKey (apmac+radionumber)
// Each logical unit has it's own record
$access_points = $os->pollWirelessAccessPoints()->keyBy(function ($item) {
return $item->getCompositeKey();
});

// Sync models. In a situation where controller is changed, update existing APs
// TODO: Test restoring soft deleted models
ModuleModelObserver::observe('\App\Models\AccessPoint');
$this->syncModels($os->getDevice(), 'accessPoints', $access_points);

// Update RRD-files for AccessPoints and calculate total counters for the controller
foreach ($access_points as $ap) {
$rrd_name = [$os->getAccessPointDatastorePrefix(), $ap->name . $ap->radionum];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we should try to make common RRD files and point the uniquely named graph files at those.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we should try to make common RRD files and point the uniquely named graph files at those.

What kind of approach you had in mind? I tried to use the same name for the files in order to preserve existing graphs.

Copy link
Member

@murrant murrant Oct 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look for // enable migration in #13268 rrd can use another file as a data source during creation. Maybe we should implement that in the existing code.

Copy link
Contributor Author

@ottorei ottorei Nov 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed something interesting - Aruba, Cisco and Huawei are currently using the same prefixes for the RRD-files. Should I migrate the existing data or just continue to use the same naming convention?


$rrd_def = RrdDefinition::make()
->addDataset('channel', 'GAUGE', 0, 200)
->addDataset('txpow', 'GAUGE', 0, 200)
->addDataset('radioutil', 'GAUGE', 0, 100)
->addDataset('nummonclients', 'GAUGE', 0, 500)
->addDataset('nummonbssid', 'GAUGE', 0, 200)
->addDataset('numasoclients', 'GAUGE', 0, 500)
->addDataset('interference', 'GAUGE', 0, 2000);

$fields = [
'channel' => $ap->channel,
'txpow' => $ap->txpow,
'radioutil' => $ap->radioutil,
'nummonclients' => $ap->nummonclients,
'nummonbssid' => $ap->nummonbssid,
'numasoclients' => $ap->numasoclients,
'interference' => $ap->interference,
];

$tags = [
'name' => $ap->name,
'radionum' => $ap->radionum,
'rrd_name' => $rrd_name,
'rrd_def' => $rrd_def,
];

data_update($os->getDeviceArray(), $os->getDatastoreMeasurementName(), $tags, $fields);
}

echo PHP_EOL;
}
}

/**
* Remove all DB data for this module.
* This will be run when the module is disabled.
*
* @param OS $os
*/
public function cleanup(OS $os)
{
// Delete all AccessPoints from the controller
$os->getDevice()->accessPoints()->delete();

// Delete all WirelessSensors from the device
$os->getDevice()->wirelessSensors()->delete();
}
}
61 changes: 60 additions & 1 deletion LibreNMS/OS/Arubaos.php
Expand Up @@ -25,7 +25,9 @@

namespace LibreNMS\OS;

use App\Models\AccessPoint;
use App\Models\Device;
use Illuminate\Support\Collection;
use LibreNMS\Device\WirelessSensor;
use LibreNMS\Interfaces\Discovery\OSDiscovery;
use LibreNMS\Interfaces\Discovery\Sensors\WirelessApCountDiscovery;
Expand All @@ -35,6 +37,7 @@
use LibreNMS\Interfaces\Discovery\Sensors\WirelessPowerDiscovery;
use LibreNMS\Interfaces\Discovery\Sensors\WirelessUtilizationDiscovery;
use LibreNMS\Interfaces\Polling\Sensors\WirelessFrequencyPolling;
use LibreNMS\Interfaces\Polling\WirelessAccessPointPolling;
use LibreNMS\OS;

class Arubaos extends OS implements
Expand All @@ -45,7 +48,8 @@ class Arubaos extends OS implements
WirelessFrequencyPolling,
WirelessNoiseFloorDiscovery,
WirelessPowerDiscovery,
WirelessUtilizationDiscovery
WirelessUtilizationDiscovery,
WirelessAccessPointPolling
{
public function discoverOS(Device $device): void
{
Expand Down Expand Up @@ -214,4 +218,59 @@ public function pollWirelessFrequency(array $sensors)
{
return $this->pollWirelessChannelAsFrequency($sensors, [$this, 'decodeChannel']);
}

public function getDatastoreMeasurementName()
{
// Datastore measurement name
return 'aruba';
}

public function getWirelessControllerDatastorePrefix()
{
// Prefix used to name RRD-files for AccessPoints
return 'aruba-controller';
}

public function getAccessPointDatastorePrefix()
{
// Prefix used to name RRD-files for AccessPoints
return 'arubaap';
}

/**
* Poll wireless access points data from the controller
* Return collection of AccessPoints
*/
public function pollWirelessAccessPoints()
{
$access_points = new Collection;
$wlsxWlanRadioTable = snmpwalk_group($this->getDeviceArray(), 'WLSX-WLAN-MIB::wlsxWlanRadioTable', '1');
$wlsxWlanAPChStatsTable = snmpwalk_group($this->getDeviceArray(), 'WLSX-WLAN-MIB::wlsxWlanAPChStatsTable', '1');

// Loop through the polled data. Array format: $table[mac-of-ap][oid][radio number]
foreach ($wlsxWlanRadioTable as $ap => $val1) {
foreach ($wlsxWlanRadioTable[$ap]['wlanAPRadioAPName'] as $radio_id => $val2) {
$attributes = [
'device_id' => $this->getDeviceId(),
'name' => $wlsxWlanRadioTable[$ap]['wlanAPRadioAPName'][$radio_id],
'radio_number' => $radio_id,
'type' => $wlsxWlanRadioTable[$ap]['wlanAPRadioType'][$radio_id],
'mac_addr' => $ap,
'channel' => $wlsxWlanRadioTable[$ap]['wlanAPRadioChannel'][$radio_id],
'txpow' => $wlsxWlanRadioTable[$ap]['wlanAPRadioUtilization'][$radio_id] / 2,
'radioutil' => $wlsxWlanRadioTable[$ap]['wlanAPRadioUtilization'][$radio_id],
'numasoclients' => $wlsxWlanRadioTable[$ap]['wlanAPRadioNumAssociatedClients'][$radio_id],
'nummonclients' => $wlsxWlanRadioTable[$ap]['wlanAPRadioNumMonitoredClients'][$radio_id],
'numactbssid' => $wlsxWlanRadioTable[$ap]['wlanAPRadioNumActiveBSSIDs'][$radio_id],
'nummonbssid' => $wlsxWlanRadioTable[$ap]['wlanAPRadioNumMonitoredBSSIDs'][$radio_id],
'interference' => $wlsxWlanAPChStatsTable[$ap]['wlanAPChInterferenceIndex'][$radio_id],
];

// Create AccessPoint models
$access_points->push(new AccessPoint($attributes));
}
}
// Return the collection of AccessPoint models
return $access_points;
}
}
32 changes: 30 additions & 2 deletions app/Models/AccessPoint.php
Expand Up @@ -2,8 +2,36 @@

namespace App\Models;

class AccessPoint extends DeviceRelatedModel
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use LibreNMS\Interfaces\Models\Keyable;

class AccessPoint extends DeviceRelatedModel implements Keyable
{
protected $primaryKey = 'accesspoint_id';
use HasFactory;
use SoftDeletes;

public $primaryKey = 'accesspoint_id';
public $timestamps = false;

protected $fillable = [
'device_id',
'name',
'radio_number',
'type',
'mac_addr',
'channel',
'txpow',
'radioutil',
'numasoclients',
'nummonclients',
'numactbssid',
'nummonbssid',
'interference',
];

public function getCompositeKey()
{
return "$this->device_id-$this->mac_addr-$this->radio_number";
}
}
2 changes: 1 addition & 1 deletion app/Models/Device.php
Expand Up @@ -553,7 +553,7 @@ public function scopeNotInServiceTemplate($query, $serviceTemplate)

public function accessPoints(): HasMany
{
return $this->hasMany(AccessPoint::class, 'device_id');
return $this->hasMany(\App\Models\AccessPoint::class, 'device_id');
}

public function alerts(): HasMany
Expand Down
34 changes: 34 additions & 0 deletions database/migrations/2021_10_09_1830_alter_access_points_table.php
@@ -0,0 +1,34 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AlterAccessPointsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('access_points', function (Blueprint $table) {
$table->dropColumn('deleted');
$table->softDeletes();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('access_points', function (Blueprint $table) {
$table->dropSoftDeletes();
$table->boolean('deleted')->default(0)->index();
});
}
}
7 changes: 5 additions & 2 deletions includes/discovery/wireless.inc.php
Expand Up @@ -23,6 +23,9 @@
* @author Tony Murray <murraytony@gmail.com>
*/

use LibreNMS\Device\WirelessSensor;
use LibreNMS\OS;

WirelessSensor::runDiscovery($os);
if (! $os instanceof OS) {
$os = OS::make($device);
}
(new \LibreNMS\Modules\Wireless())->discover($os);