Fully convert core to a modern module (#13347)

* Core module WIP

* update OS::make()

* core WIP

* try to finish up

* switch all core do os Model

* Mock WIP

* Working tests

* cleanup

* phpstan fixes

* style fixes

* fix agent

* trim space too
and a couple of cleanups

* corrected ios test data

* missed space

* update test data

* put escapes back

* another net-snmp difference

* Fix class description

* revert snmp.inc.php change, that can be a different PR

* revert snmp.inc.php change, that can be a different PR
This commit is contained in:
Tony Murray
2021-10-19 15:43:43 -05:00
committed by GitHub
parent 17b97abbd2
commit f94f7f23b8
24 changed files with 639 additions and 503 deletions

View File

@@ -1,5 +1,5 @@
<?php
/*
/**
* Core.php
*
* -Description-
@@ -17,37 +17,137 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link https://www.librenms.org
* @copyright 2020 Tony Murray
*
* @copyright 2021 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Modules;
use App\Models\Device;
use Illuminate\Support\Str;
use LibreNMS\Config;
use LibreNMS\Interfaces\Module;
use LibreNMS\OS;
use LibreNMS\RRD\RrdDefinition;
use LibreNMS\Util\Time;
use Log;
use SnmpQuery;
class Core
class Core implements Module
{
public function discover(OS $os)
{
$snmpdata = SnmpQuery::numeric()->get(['SNMPv2-MIB::sysObjectID.0', 'SNMPv2-MIB::sysDescr.0', 'SNMPv2-MIB::sysName.0'])
->values();
$device = $os->getDevice();
$device->fill([
'sysObjectID' => $snmpdata['.1.3.6.1.2.1.1.2.0'] ?? null,
'sysName' => strtolower(trim($snmpdata['.1.3.6.1.2.1.1.5.0'] ?? '')),
'sysDescr' => isset($snmpdata['.1.3.6.1.2.1.1.1.0']) ? str_replace(chr(218), "\n", $snmpdata['.1.3.6.1.2.1.1.1.0']) : null,
]);
foreach ($device->getDirty() as $attribute => $value) {
Log::event($value . ' -> ' . $device->$attribute, $device, 'system', 3);
$os->getDeviceArray()[$attribute] = $value; // update device array
}
// detect OS
$device->os = self::detectOS($device, false);
if ($device->isDirty('os')) {
Log::event('Device OS changed: ' . $device->getOriginal('os') . ' -> ' . $device->os, $device, 'system', 3);
$os->getDeviceArray()['os'] = $device->os;
echo 'Changed ';
}
// Set type to a predefined type for the OS if it's not already set
$loaded_os_type = Config::get("os.$device->os.type");
if (! $device->getAttrib('override_device_type') && $loaded_os_type != $device->type) {
$device->type = $loaded_os_type;
Log::debug("Device type changed to $loaded_os_type!");
}
$device->save();
echo 'OS: ' . Config::getOsSetting($device->os, 'text') . " ($device->os)\n\n";
}
public function poll(OS $os)
{
global $agent_data;
$snmpdata = SnmpQuery::numeric()
->get(['SNMPv2-MIB::sysDescr.0', 'SNMPv2-MIB::sysObjectID.0', 'SNMPv2-MIB::sysUpTime.0', 'SNMPv2-MIB::sysName.0'])
->values();
$device = $os->getDevice();
$device->fill([
'uptime' => $snmpdata['.1.3.6.1.2.1.1.3.0'],
'sysName' => str_replace("\n", '', strtolower($snmpdata['.1.3.6.1.2.1.1.5.0'])),
'sysObjectID' => $snmpdata['.1.3.6.1.2.1.1.2.0'],
'sysDescr' => str_replace(chr(218), "\n", $snmpdata['.1.3.6.1.2.1.1.1.0']),
]);
if (! empty($agent_data['uptime'])) {
[$uptime] = explode(' ', $agent_data['uptime']);
$uptime = round((float) $uptime);
echo "Using UNIX Agent Uptime ($uptime)\n";
} else {
$uptime_data = SnmpQuery::make()->get(['SNMP-FRAMEWORK-MIB::snmpEngineTime.0', 'HOST-RESOURCES-MIB::hrSystemUptime.0'])->values();
$uptime = max(
round($device->uptime / 100),
Config::get("os.$device->os.bad_snmpEngineTime") ? 0 : $uptime_data['SNMP-FRAMEWORK-MIB::snmpEngineTime.0'],
Config::get("os.$device->os.bad_hrSystemUptime") ? 0 : round($uptime_data['HOST-RESOURCES-MIB::hrSystemUptime.0'] / 100)
);
Log::debug("Uptime seconds: $uptime\n");
}
if ($uptime != 0 && Config::get("os.$device->os.bad_uptime") !== true) {
if ($uptime < $device->uptime) {
Log::event('Device rebooted after ' . Time::formatInterval($device->uptime) . " -> {$uptime}s", $device, 'reboot', 4, $device->uptime);
}
app('Datastore')->put($os->getDeviceArray(), 'uptime', [
'rrd_def' => RrdDefinition::make()->addDataset('uptime', 'GAUGE', 0),
], $uptime);
$os->enableGraph('uptime');
echo 'Uptime: ' . Time::formatInterval($uptime) . PHP_EOL;
$device->uptime = $uptime;
$device->save();
}
}
public function cleanup(OS $os)
{
// nothing to cleanup
}
/**
* Detect the os of the given device.
*
* @param array $device device to check
* @param Device $device device to check
* @param bool $fetch fetch sysDescr and sysObjectID fresh from the device
* @return string the name of the os
*
* @throws \Exception
*/
public static function detectOS($device, $fetch = true)
public static function detectOS(Device $device, bool $fetch = true): string
{
if ($fetch) {
// some devices act odd when getting both oids at once
$device['sysDescr'] = snmp_get($device, 'SNMPv2-MIB::sysDescr.0', '-Ovq');
$device['sysObjectID'] = snmp_get($device, 'SNMPv2-MIB::sysObjectID.0', '-Ovqn');
// some devices act oddly when getting both OIDs at once
$device->sysDescr = SnmpQuery::device($device)->get('SNMPv2-MIB::sysDescr.0')->value();
$device->sysObjectID = SnmpQuery::device($device)->numeric()->get('SNMPv2-MIB::sysObjectID.0')->value();
}
d_echo("| {$device['sysDescr']} | {$device['sysObjectID']} | \n");
Log::debug("| $device->sysDescr | $device->sysObjectID | \n");
$deferred_os = [];
$generic_os = [
@@ -96,12 +196,12 @@ class Core
*
* Appending _except to any condition will invert the match.
*
* @param array $device
* @param Device $device
* @param array $array Array of items, keys should be sysObjectID, sysDescr, or sysDescr_regex
* @param string|array $mibdir MIB directory for evaluated OS
* @return bool the result (all items passed return true)
*/
protected static function checkDiscovery($device, $array, $mibdir)
protected static function checkDiscovery(Device $device, array $array, $mibdir): bool
{
// all items must be true
foreach ($array as $key => $value) {
@@ -126,24 +226,20 @@ class Core
return false;
}
} elseif ($key == 'snmpget') {
$get_value = snmp_get(
$device,
$value['oid'],
$value['options'] ?? '-Oqv',
$value['mib'] ?? null,
$value['mib_dir'] ?? $mibdir
);
$get_value = SnmpQuery::device($device)
->options($value['options'] ?? [])
->mibDir($value['mib_dir'] ?? $mibdir)
->get(isset($value['mib']) ? "{$value['mib']}::{$value['oid']}" : $value['oid'])
->value();
if (compare_var($get_value, $value['value'], $value['op'] ?? 'contains') == $check) {
return false;
}
} elseif ($key == 'snmpwalk') {
$walk_value = snmp_walk(
$device,
$value['oid'],
$value['options'] ?? '-Oqv',
$value['mib'] ?? null,
$value['mib_dir'] ?? $mibdir
);
$walk_value = SnmpQuery::device($device)
->options($value['options'] ?? [])
->mibDir($value['mib_dir'] ?? $mibdir)
->walk(isset($value['mib']) ? "{$value['mib']}::{$value['oid']}" : $value['oid'])
->raw();
if (compare_var($walk_value, $value['value'], $value['op'] ?? 'contains') == $check) {
return false;
}
@@ -153,7 +249,7 @@ class Core
return true;
}
protected static function discoveryIsSlow($def)
protected static function discoveryIsSlow($def): bool
{
foreach ($def['discovery'] as $item) {
if (array_key_exists('snmpget', $item) || array_key_exists('snmpwalk', $item)) {