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

Consolidate and improve snmptranslate usage #14567

Merged
merged 20 commits into from Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
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
33 changes: 25 additions & 8 deletions LibreNMS/Data/Source/NetSnmpQuery.php
Expand Up @@ -33,6 +33,7 @@
use LibreNMS\Config;
use LibreNMS\Enum\Alert;
use LibreNMS\Util\Debug;
use LibreNMS\Util\Oid;
use LibreNMS\Util\Rewrite;
use Log;
use Symfony\Component\Process\Process;
Expand Down Expand Up @@ -76,9 +77,9 @@ class NetSnmpQuery implements SnmpQueryInterface
*/
private $context = '';
/**
* @var string
* @var string[]
*/
private $mibDir;
private array $mibDirs = [];
/**
* @var array|string
*/
Expand Down Expand Up @@ -158,7 +159,7 @@ public function context(?string $context, ?string $v3_prefix = null): SnmpQueryI
*/
public function mibDir(?string $dir): SnmpQueryInterface
{
$this->mibDir = $dir;
$this->mibDirs[] = $dir;

return $this;
}
Expand Down Expand Up @@ -283,13 +284,29 @@ public function next($oid): SnmpResponse
* Translate an OID.
* call numeric() on the query to output numeric OID
*/
public function translate(string $oid, ?string $mib = null): SnmpResponse
public function translate(string $oid, ?string $mib = null): string
{
$this->options = array_diff($this->options, [self::DEFAULT_FLAGS]); // remove default options

$this->options[] = '-Pu'; // don't error on _

// user did not specify numeric, output full text
if (! in_array('-On', $this->options)) {
$this->options[] = '-OS';
} elseif (Oid::isNumeric($oid)) {
return Str::start($oid, '.'); // numeric to numeric optimization
}

// if mib is not directly specified and it doesn't have a numeric root
if (! str_contains($oid, '::') && ! Oid::hasNumericRoot($oid)) {
$this->options[] = '-IR'; // search for mib
}

if ($mib) {
$this->options = array_merge($this->options, ['-m', $mib]);
array_push($this->options, '-m', $mib);
}

return $this->exec('snmptranslate', [$oid]);
return $this->exec('snmptranslate', [$oid])->value();
}

private function buildCli(string $command, array $oids): array
Expand Down Expand Up @@ -438,8 +455,8 @@ private function mibDirectories(): string
$dirs[] = $base . '/' . $this->device->os;
}

if ($this->mibDir) {
$dirs[] = "$base/$this->mibDir";
foreach ($this->mibDirs as $mibDir) {
$dirs[] = "$base/$mibDir";
}

// remove trailing /, remove empty dirs, and remove duplicates
Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/Data/Source/SnmpQueryInterface.php
Expand Up @@ -127,5 +127,5 @@ public function next($oid): SnmpResponse;
* Translate an OID.
* Call numeric method prior output numeric OID.
*/
public function translate(string $oid, ?string $mib = null): SnmpResponse;
public function translate(string $oid, ?string $mib = null): string;
}
5 changes: 5 additions & 0 deletions LibreNMS/Data/Source/SnmpResponse.php
Expand Up @@ -242,4 +242,9 @@ public function append(SnmpResponse $response): SnmpResponse

return $this;
}

public function __toString(): string
{
return $this->raw;
}
}
49 changes: 2 additions & 47 deletions LibreNMS/Device/YamlDiscovery.php
Expand Up @@ -26,19 +26,16 @@
namespace LibreNMS\Device;

use App\View\SimpleTemplate;
use Cache;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use LibreNMS\Config;
use LibreNMS\Exceptions\InvalidOidException;
use LibreNMS\Interfaces\Discovery\DiscoveryItem;
use LibreNMS\OS;
use LibreNMS\Util\Compare;
use LibreNMS\Util\Oid;

class YamlDiscovery
{
private static $cache_time = 1800; // 30 min, Used for oid translation cache

/**
* @param OS $os
* @param DiscoveryItem|string $class
Expand Down Expand Up @@ -145,7 +142,7 @@ public static function computeNumericalOID(OS $os, array $data): string
}

try {
$num_oid = static::oidToNumeric($data['value'], $os->getDeviceArray(), $search_mib);
$num_oid = Oid::toNumeric($data['value'], $search_mib);
} catch (\Exception $e) {
throw $e;
}
Expand Down Expand Up @@ -380,46 +377,4 @@ public static function canSkipItem($value, $index, array $yaml_item_data, array

return false;
}

/**
* Translate an oid to numeric format (if already numeric, return as-is)
*
* @param string $oid
* @param array|null $device
* @param string $mib
* @return string numeric oid
*
* @throws \LibreNMS\Exceptions\InvalidOidException
*/
public static function oidToNumeric($oid, $device = null, $mib = 'ALL')
{
if (self::oidIsNumeric($oid)) {
return $oid;
}
$key = 'YamlDiscovery:oidToNumeric:' . $mib . '/' . $oid;
if (Cache::has($key)) {
$numeric_oid = Cache::get($key);
} else {
foreach (explode(':', $mib) as $mib_name) {
$numeric_oid = snmp_translate($oid, $mib_name, null, null, $device);
if ($numeric_oid) {
break;
}
}
}

//Store the value
Cache::put($key, $numeric_oid, self::$cache_time);

if (empty($numeric_oid)) {
throw new InvalidOidException("Unable to translate oid $oid");
}

return $numeric_oid;
}

public static function oidIsNumeric($oid)
{
return (bool) preg_match('/^[.\d]+$/', $oid);
}
}
6 changes: 3 additions & 3 deletions LibreNMS/OS/Edgecos.php
Expand Up @@ -30,10 +30,10 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use LibreNMS\Device\Processor;
use LibreNMS\Device\YamlDiscovery;
use LibreNMS\Interfaces\Discovery\MempoolsDiscovery;
use LibreNMS\Interfaces\Discovery\ProcessorDiscovery;
use LibreNMS\OS;
use LibreNMS\Util\Oid;

class Edgecos extends OS implements MempoolsDiscovery, ProcessorDiscovery
{
Expand All @@ -56,9 +56,9 @@ public function discoverMempools()
]);

if (! empty($data['memoryAllocated.0'])) {
$mempool->mempool_used_oid = YamlDiscovery::oidToNumeric('memoryAllocated.0', $this->getDeviceArray(), $mib);
$mempool->mempool_used_oid = Oid::toNumeric('memoryAllocated.0', $mib);
} else {
$mempool->mempool_free_oid = YamlDiscovery::oidToNumeric('memoryFreed.0', $this->getDeviceArray(), $mib);
$mempool->mempool_free_oid = Oid::toNumeric('memoryFreed.0', $mib);
}

$mempool->fillUsage($data['memoryAllocated.0'] ?? null, $data['memoryTotal.0'] ?? null, $data['memoryFreed.0']);
Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/OS/Junose.php
Expand Up @@ -37,7 +37,7 @@ public function discoverOS(Device $device): void
return;
}

$junose_hardware = \SnmpQuery::translate($device->sysObjectID, 'Juniper-Products-MIB')->value();
$junose_hardware = \SnmpQuery::translate($device->sysObjectID, 'Juniper-Products-MIB');
$device->hardware = $this->rewriteHardware($junose_hardware) ?: null;

$junose_version = \SnmpQuery::get('Juniper-System-MIB::juniSystemSwVersion.0')->value();
Expand Down
9 changes: 5 additions & 4 deletions LibreNMS/OS/Traits/YamlMempoolsDiscovery.php
Expand Up @@ -28,6 +28,7 @@
use App\Models\Mempool;
use Illuminate\Support\Collection;
use LibreNMS\Device\YamlDiscovery;
use LibreNMS\Util\Oid;

trait YamlMempoolsDiscovery
{
Expand Down Expand Up @@ -107,12 +108,12 @@ private function getData($field, $index, $yaml)

private function getOid($field, $index, $yaml)
{
if (YamlDiscovery::oidIsNumeric($yaml[$field] ?? '')) {
if (Oid::isNumeric($yaml[$field] ?? '')) {
return $yaml[$field];
}

if (isset($this->mempoolsOids[$field])) {
return YamlDiscovery::oidToNumeric("{$this->mempoolsOids[$field]}.$index", $this->getDeviceArray());
return Oid::toNumeric("{$this->mempoolsOids[$field]}.$index", 'ALL');
}

return null;
Expand All @@ -137,15 +138,15 @@ private function fetchData($yaml, $mib)
foreach ($this->mempoolsFields as $field) {
if (isset($yaml[$field]) && ! is_numeric($yaml[$field])) { // allow for hard-coded values
$oid = $yaml[$field];
if (YamlDiscovery::oidIsNumeric($oid)) { // if numeric oid, it is not a table, just fetch it
if (Oid::isNumeric($oid)) { // if numeric oid, it is not a table, just fetch it
$this->mempoolsData[0][$oid] = snmp_get($this->getDeviceArray(), $oid, '-Oqv');
continue;
}

if (empty($yaml['oid'])) { // if table given, skip individual oids
$this->mempoolsData = snmpwalk_cache_oid($this->getDeviceArray(), $oid, $this->mempoolsData, null, null, $options);
}
$this->mempoolsOids[$field] = YamlDiscovery::oidToNumeric($oid, $this->getDeviceArray(), $mib);
$this->mempoolsOids[$field] = Oid::toNumeric($oid, $mib);
}
}
}
Expand Down
18 changes: 4 additions & 14 deletions LibreNMS/OS/Traits/YamlOSDiscovery.php
Expand Up @@ -29,6 +29,7 @@
use App\Models\Location;
use App\View\SimpleTemplate;
use Illuminate\Support\Arr;
use LibreNMS\Util\Oid;
use LibreNMS\Util\StringHelpers;
use Log;

Expand Down Expand Up @@ -62,7 +63,7 @@ public function discoverOS(Device $device): void

$oids = Arr::only($os_yaml, $this->osFields);
$fetch_oids = array_unique(Arr::flatten($oids));
$numeric = $this->isNumeric($fetch_oids);
$numeric = Oid::hasNumeric($fetch_oids);
$data = $this->fetch($fetch_oids, $numeric);

Log::debug('Yaml OS data:', $data);
Expand Down Expand Up @@ -93,7 +94,7 @@ public function fetchLocation(): Location
$lng = $os_yaml['long'] ?? null;

$oids = array_filter([$name, $lat, $lng]);
$numeric = $this->isNumeric($oids);
$numeric = Oid::hasNumeric($oids);
$data = $this->fetch($oids, $numeric);

Log::debug('Yaml location data:', $data);
Expand All @@ -111,7 +112,7 @@ private function findFirst($data, $oids, $numeric = false)
{
foreach (Arr::wrap($oids) as $oid) {
// translate all to numeric to make it easier to match
$oid = ($numeric && ! oid_is_numeric($oid)) ? snmp_translate($oid, 'ALL', null, null, $this->getDeviceArray()) : $oid;
$oid = ($numeric && ! Oid::isNumeric($oid)) ? snmp_translate($oid, 'ALL', null, null, $this->getDeviceArray()) : $oid;
if (! empty($data[$oid])) {
return $data[$oid];
}
Expand Down Expand Up @@ -150,17 +151,6 @@ private function fetch(array $oids, $numeric)
return snmp_get_multi_oid($this->getDeviceArray(), $oids, $numeric ? '-OUQn' : '-OUQ');
}

private function isNumeric($oids)
{
foreach ($oids as $oid) {
if (oid_is_numeric($oid)) {
return true;
}
}

return false;
}

private function replaceStringsInFields(Device $device, array $os_yaml): void
{
foreach ($this->osFields as $field) {
Expand Down
82 changes: 82 additions & 0 deletions LibreNMS/Util/Oid.php
@@ -0,0 +1,82 @@
<?php
/*
* Snmp.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 2022 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/

namespace LibreNMS\Util;

use Cache;
use LibreNMS\Exceptions\InvalidOidException;

class Oid
{
public static function isNumeric(string $oid): bool
{
return (bool) preg_match('/^[.\d]+$/', $oid);
}

public static function hasNumericRoot(string $oid): bool
{
return (bool) preg_match('/^\.?1/', $oid);
}

public static function hasNumeric(array $oids): bool
{
foreach ($oids as $oid) {
if (self::isNumeric($oid)) {
return true;
}
}

return false;
}

/**
* Converts an oid to numeric and caches the result
*
* @throws \LibreNMS\Exceptions\InvalidOidException
*/
public static function toNumeric(string $oid, string $mib = 'ALL', int $cache = 1800): string
{
if (Oid::isNumeric($oid)) {
return $oid;
}

// we already have a specific mib, don't add a bunch of others
if (str_contains($oid, '::')) {
$mib = null;
}

$key = 'Oid:toNumeric:' . $oid . '/' . $mib;

$numeric_oid = Cache::remember($key, $cache, function () use ($oid, $mib) {
murrant marked this conversation as resolved.
Show resolved Hide resolved
return \SnmpQuery::numeric()->translate($oid, $mib);
});

if (empty($numeric_oid)) {
throw new InvalidOidException("Unable to translate oid $oid");
}

return $numeric_oid;
}
}