mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
* MAC Vendor OUI use scheduler Add command to update `lnms maintenance:fetch-ouis` Show vendor column in tables if mac_oui.enabled is set to true Improve scheduler validation handle non-standard install directories and systems without systemd Add index to table to improve speed and improve mac->vendor lookup speed Scheduled weekly with random wait to prevent stampeding herd issues for upstream drop oui update from daily * MAC Vendor OUI use scheduler Add command to update `lnms maintenance:fetch-ouis` Show vendor column in tables if mac_oui.enabled is set to true * Lint fixes and better prefix detection * update schema file
137 lines
4.5 KiB
PHP
137 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Console\LnmsCommand;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use LibreNMS\Config;
|
|
use Symfony\Component\Console\Input\InputOption;
|
|
use Symfony\Component\Console\Output\OutputInterface;
|
|
|
|
class MaintenanceFetchOuis extends LnmsCommand
|
|
{
|
|
/**
|
|
* The name of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $name = 'maintenance:fetch-ouis';
|
|
|
|
protected string $mac_oui_url = 'https://www.wireshark.org/download/automated/data/manuf';
|
|
protected int $min_refresh_days = 6;
|
|
protected int $max_wait_seconds = 900;
|
|
protected int $upsert_chunk_size = 1000;
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
$this->addOption('force', null, InputOption::VALUE_NONE);
|
|
$this->addOption('wait', null, InputOption::VALUE_NONE);
|
|
}
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*/
|
|
public function handle(): int
|
|
{
|
|
$force = $this->option('force');
|
|
|
|
if (Config::get('mac_oui.enabled') !== true && ! $force) {
|
|
$this->line(trans('commands.maintenance:fetch-ouis.disabled', ['setting' => 'mac_oui.enabled']));
|
|
|
|
if (! $this->confirm(trans('commands.maintenance:fetch-ouis.enable_question'))) {
|
|
return 0;
|
|
}
|
|
|
|
Config::persist('mac_oui.enabled', true);
|
|
}
|
|
|
|
// We want to refresh after at least 6 days
|
|
$lock = Cache::lock('vendor_oui_db_refresh', 86400 * $this->min_refresh_days);
|
|
if (! $lock->get() && ! $force) {
|
|
$this->warn(trans('commands.maintenance:fetch-ouis.recently_fetched'));
|
|
|
|
return 0;
|
|
}
|
|
|
|
// wait for 0-15 minutes to prevent stampeding herd
|
|
if ($this->option('wait')) {
|
|
$seconds = rand(1, $this->max_wait_seconds);
|
|
$minutes = (int) round($seconds / 60);
|
|
$this->info(trans_choice('commands.maintenance:fetch-ouis.waiting', $minutes, ['minutes' => $minutes]));
|
|
sleep($seconds);
|
|
}
|
|
|
|
$this->line(trans('commands.maintenance:fetch-ouis.starting'));
|
|
|
|
try {
|
|
$this->line(' -> ' . trans('commands.maintenance:fetch-ouis.downloading') . ' ...');
|
|
$csv_data = \LibreNMS\Util\Http::client()->get($this->mac_oui_url)->body();
|
|
|
|
// convert the csv into an array to be consumed by upsert
|
|
$this->line(' -> ' . trans('commands.maintenance:fetch-ouis.processing') . ' ...');
|
|
$ouis = $this->buildOuiList($csv_data);
|
|
|
|
$this->line(' -> ' . trans('commands.maintenance:fetch-ouis.saving') . ' ...');
|
|
$count = 0;
|
|
foreach (array_chunk($ouis, $this->upsert_chunk_size) as $oui_chunk) {
|
|
$count += DB::table('vendor_ouis')->upsert($oui_chunk, 'oui');
|
|
}
|
|
|
|
$this->info(trans_choice('commands.maintenance:fetch-ouis.success', $count, ['count' => $count]));
|
|
|
|
return 0;
|
|
} catch (\Exception|\ErrorException $e) {
|
|
$this->error(trans('commands.maintenance:fetch-ouis.error'));
|
|
$this->error('Exception: ' . get_class($e));
|
|
$this->error($e);
|
|
|
|
$lock->release(); // We did not succeed, so we'll try again next time
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
private function buildOuiList(string $csv_data): array
|
|
{
|
|
$ouis = [];
|
|
|
|
foreach (explode("\n", rtrim($csv_data)) as $csv_line) {
|
|
// skip comments
|
|
if (str_starts_with($csv_line, '#')) {
|
|
continue;
|
|
}
|
|
|
|
[$oui, $vendor] = str_getcsv($csv_line, "\t");
|
|
|
|
$oui = strtolower(str_replace(':', '', $oui)); // normalize oui
|
|
$prefix_index = strpos($oui, '/');
|
|
|
|
// check for non-/24 oui
|
|
if ($prefix_index !== false) {
|
|
// find prefix length
|
|
$prefix_length = (int) substr($oui, $prefix_index + 1);
|
|
|
|
// 4 bits per character: /28 = 7 /36 = 9
|
|
$substring_length = (int) floor($prefix_length / 4);
|
|
|
|
$oui = substr($oui, 0, $substring_length);
|
|
}
|
|
|
|
// Add to the list of vendor ids
|
|
$ouis[] = [
|
|
'vendor' => $vendor,
|
|
'oui' => $oui,
|
|
];
|
|
|
|
if ($this->verbosity == OutputInterface::VERBOSITY_DEBUG) {
|
|
$this->line(trans('commands.maintenance:fetch-ouis.vendor_update', ['vendor' => $vendor, 'oui' => $oui]));
|
|
}
|
|
}
|
|
|
|
return $ouis;
|
|
}
|
|
}
|