Allow SnmpQuery to optionally abort walks if one fails (#14255)

* Allow SnmpQuery to optionally abort walks if one fails

* style

* remove baseline
This commit is contained in:
Tony Murray
2022-08-28 19:47:20 -05:00
committed by GitHub
parent 969159f77a
commit 08c4d7f3b3
4 changed files with 79 additions and 22 deletions

View File

@@ -87,6 +87,10 @@ class NetSnmpQuery implements SnmpQueryInterface
* @var \App\Models\Device
*/
private $device;
/**
* @var bool
*/
private $abort = false;
public function __construct()
{
@@ -159,6 +163,17 @@ class NetSnmpQuery implements SnmpQueryInterface
return $this;
}
/**
* When walking multiple OIDs, stop if one fails. Used when the first OID indicates if the rest are supported.
* OIDs will be walked in order, so you may want to put your OIDs in a specific order.
*/
public function abortOnFailure(): SnmpQueryInterface
{
$this->abort = true;
return $this;
}
/**
* Do not error on out of order indexes.
* Use with caution as we could get stuck in an infinite loop.
@@ -330,17 +345,20 @@ class NetSnmpQuery implements SnmpQueryInterface
}
}
private function execMultiple(string $command, array $oids): ?SnmpResponse
private function execMultiple(string $command, array $oids): SnmpResponse
{
$combined = null;
$response = new SnmpResponse('');
foreach ($oids as $oid) {
$response = $this->exec($command, [$oid]);
$response = $response->append($this->exec($command, [$oid]));
$combined = $combined ? $combined->append($response) : $response;
// if abort on failure is set, return after first failure
if ($this->abort && ! $response->isValid()) {
return $response;
}
}
return $combined;
return $response;
}
private function exec(string $command, array $oids): SnmpResponse

View File

@@ -58,6 +58,12 @@ interface SnmpQueryInterface
*/
public function mibDir(?string $dir): SnmpQueryInterface;
/**
* When walking multiple OIDs, stop if one fails. Used when the first OID indicates if the rest are supported.
* OIDs will be walked in order, so you may want to put your OIDs in a specific order.
*/
public function abortOnFailure(): SnmpQueryInterface;
/**
* Do not error on out of order indexes.
* Use with caution as we could get stuck in an infinite loop.

View File

@@ -10835,11 +10835,6 @@ parameters:
count: 1
path: tests/MibTest.php
-
message: "#^Property LibreNMS\\\\Tests\\\\Mocks\\\\SnmpQueryMock\\:\\:\\$context is never read, only written\\.$#"
count: 1
path: tests/Mocks/SnmpQueryMock.php
-
message: "#^Method LibreNMS\\\\Tests\\\\OSDiscoveryTest\\:\\:checkOS\\(\\) has no return type specified\\.$#"
count: 1

View File

@@ -67,6 +67,10 @@ class SnmpQueryMock implements SnmpQueryInterface
* @var array|mixed
*/
private $options = [];
/**
* @var bool
*/
private $abort = false;
public static function make(): SnmpQueryInterface
{
@@ -114,6 +118,13 @@ class SnmpQueryMock implements SnmpQueryInterface
->translate($oid, $mib);
}
public function abortOnFailure(): SnmpQueryInterface
{
$this->abort = true;
return $this;
}
public function allowUnordered(): SnmpQueryInterface
{
return $this;
@@ -157,7 +168,7 @@ class SnmpQueryMock implements SnmpQueryInterface
public function get($oid): SnmpResponse
{
$community = $this->device->community;
$community = $this->community();
$num_oid = $this->translateNumber($oid);
$data = $this->getSnmprec($community)[$num_oid] ?? [0, ''];
@@ -166,27 +177,43 @@ class SnmpQueryMock implements SnmpQueryInterface
return new SnmpResponse($this->outputLine($oid, $num_oid, $data[0], $data[1]));
}
public function walk($oid): SnmpResponse
/**
* @param array|string $oids
* @return \LibreNMS\Data\Source\SnmpResponse
*
* @throws \Exception
*/
public function walk($oids): SnmpResponse
{
$community = $this->device->community;
$num_oid = $this->translateNumber($oid);
$community = $this->community();
$dev = $this->getSnmprec($community);
$response = new SnmpResponse('');
$output = '';
foreach ($dev as $key => $data) {
if (Str::startsWith($key, $num_oid)) {
$output .= $this->outputLine($oid, $num_oid, $data[0], $data[1]);
foreach (Arr::wrap($oids) as $oid) {
$num_oid = $this->translateNumber($oid);
$output = '';
foreach ($dev as $key => $data) {
if (Str::startsWith($key, $num_oid)) {
$output .= $this->outputLine($oid, $num_oid, $data[0], $data[1]);
}
}
$response = $response->append(new SnmpResponse($output));
if ($this->abort && ! $response->isValid()) {
return $response;
}
Log::debug("[SNMP] snmpwalk $community $num_oid");
}
Log::debug("[SNMP] snmpwalk $community $num_oid");
return new SnmpResponse($output);
return $response;
}
public function next($oid): SnmpResponse
{
$community = $this->device->community;
$community = $this->community();
$num_oid = $this->translateNumber($oid);
$dev = $this->getSnmprec($community);
@@ -324,6 +351,17 @@ class SnmpQueryMock implements SnmpQueryInterface
return ltrim($number, '.');
}
private function community(): string
{
$community = $this->device->community;
if (! empty($this->context)) {
$community .= '_' . $this->context;
}
return $community;
}
private function extractMib(string $oid): ?string
{
if (Str::contains($oid, '::')) {