refactor: OS Discovery cleanup (Part 1) (#4335)

* refactor: OS Discovery cleanup (Part 1)
Convert linux.inc.php to use new string functions
Create OS discovery tests
Use glob instead of readdir in os discovery (could change discovery order)
Stop discovering once $os is set

* Remove duplicate file header.
This commit is contained in:
Tony Murray
2016-09-06 05:43:04 -05:00
committed by Neil Lathwood
parent f42406e2b0
commit f6134f429c
5 changed files with 269 additions and 56 deletions

View File

@@ -7,73 +7,50 @@ if (!$os) {
'.1.3.6.1.4.1.17713.21',
'.1.3.6.1.4.1.2.3.51.3'
);
if (preg_match('/^Linux/', $sysDescr) && !in_array($sysObjectId, $skip_oids)) {
if (starts_with($sysDescr, 'Linux') && !in_array($sysObjectId, $skip_oids)) {
$os = 'linux';
}
// Specific Linux-derivatives
if ($os == 'linux') {
// Check for QNAP Systems TurboNAS
$entPhysicalMfgName = snmp_get($device, 'ENTITY-MIB::entPhysicalMfgName.1', '-Osqnv');
if (str_contains($sysObjectId, '.1.3.6.1.4.1.5528.100.20.10.2014') || str_contains($sysObjectId, '.1.3.6.1.4.1.5528.100.20.10.2016')) {
// Specific Linux-derivatives
if (starts_with($sysObjectId, array('.1.3.6.1.4.1.5528.100.20.10.2014', '.1.3.6.1.4.1.5528.100.20.10.2016'))) {
$os = 'netbotz';
} elseif (str_contains($sysDescr, 'endian')) {
$os = 'endian';
} elseif (preg_match('/Cisco Small Business/', $sysDescr)) {
} elseif (str_contains($sysDescr, 'Cisco Small Business')) {
$os = 'ciscosmblinux';
} elseif (strpos($entPhysicalMfgName, 'QNAP') !== false) {
} elseif (str_contains(snmp_get($device, 'ENTITY-MIB::entPhysicalMfgName.1', '-Osqnv'), 'QNAP')) {
$os = 'qnap';
} elseif (stristr($sysObjectId, 'packetlogic') || str_contains($sysObjectId, '.1.3.6.1.4.1.15397.2')) {
} elseif (starts_with($sysObjectId, '.1.3.6.1.4.1.15397.2')) {
$os = 'procera';
} elseif (str_contains($sysObjectId, '.1.3.6.1.4.1.10002.1') || str_contains($sysObjectId, '.1.3.6.1.4.1.41112.1.4') || strpos(trim(snmp_get($device, 'dot11manufacturerName.5', '-Osqnv', 'IEEE802dot11-MIB')), 'Ubiquiti') !== false) {
} elseif (starts_with($sysObjectId, array('.1.3.6.1.4.1.10002.1', '.1.3.6.1.4.1.41112.1.4')) || str_contains(snmp_get($device, 'dot11manufacturerName.5', '-Osqnv', 'IEEE802dot11-MIB'), 'Ubiquiti')) {
$os = 'airos';
if (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.5', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) {
if (str_contains(snmp_walk($device, 'dot11manufacturerProductName', '-Osqnv', 'IEEE802dot11-MIB'), 'UAP')) {
$os = 'unifi';
} elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.2', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) {
$os = 'unifi';
} elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.3', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) {
$os = 'unifi';
} elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.4', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) {
$os = 'unifi';
} elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.6', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) {
$os = 'unifi';
} elseif (trim(snmp_get($device, 'fwVersion.1', '-Osqnv', 'UBNT-AirFIBER-MIB')) != '') {
} elseif (snmp_get($device, 'fwVersion.1', '-Osqnv', 'UBNT-AirFIBER-MIB') !== false) {
$os = 'airos-af';
}
} elseif (snmp_get($device, 'GANDI-MIB::rxCounter.0', '-Osqnv', 'GANDI-MIB') !== false) {
$os = 'pktj';
$pktj_mibs = array (
"rxCounter" => "GANDI-MIB", // RX Packets
"txCounter" => "GANDI-MIB", // TX Packets
"dropCounter" => "GANDI-MIB", // Dropped counters
"acldropCounter" => "GANDI-MIB", // ACL Dropped counter
"ratedropCounter" => "GANDI-MIB", // Rate Dropped counter
"KNIrxCounter" => "GANDI-MIB", // KNI RX counter
"KNItxCounter" => "GANDI-MIB", // KNI TX counter
"KNIdropCounter" => "GANDI-MIB", // KNI DROP counter
"rxCounter" => "GANDI-MIB", // RX Packets
"txCounter" => "GANDI-MIB", // TX Packets
"dropCounter" => "GANDI-MIB", // Dropped counters
"acldropCounter" => "GANDI-MIB", // ACL Dropped counter
"ratedropCounter" => "GANDI-MIB", // Rate Dropped counter
"KNIrxCounter" => "GANDI-MIB", // KNI RX counter
"KNItxCounter" => "GANDI-MIB", // KNI TX counter
"KNIdropCounter" => "GANDI-MIB", // KNI DROP counter
);
register_mibs($device, $pktj_mibs, "include/discovery/os/linux.inc.php");
} elseif (stristr($sysObjectId, 'cumulusMib') || str_contains($sysObjectId, '.1.3.6.1.4.1.40310')) {
} elseif (starts_with($sysObjectId, '.1.3.6.1.4.1.40310')) {
$os = 'cumulus';
} elseif (str_contains($sysDescr, array('g56fa85e', 'gc80f187', 'g829be90', 'g63c0044', 'gba768e5'))) {
$os = 'sophos';
} elseif (snmp_get($device, 'SFA-INFO::systemName.0', '-Osqnv', 'SFA-INFO') !== false) {
$os = 'ddnos';
} else {
// Check for Synology DSM
$hrSystemInitialLoadParameters = trim(snmp_get($device, 'HOST-RESOURCES-MIB::hrSystemInitialLoadParameters.0', '-Osqnv'));
if (strpos($hrSystemInitialLoadParameters, 'syno_hw_version') !== false) {
$os = 'dsm';
} else {
// Check for Carel PCOweb
$roomTemp = trim(snmp_get($device, 'roomTemp.0', '-OqvU', 'CAREL-ug40cdz-MIB'));
if (is_numeric($roomTemp)) {
$os = 'pcoweb';
}
}
} elseif (str_contains(snmp_get($device, 'HOST-RESOURCES-MIB::hrSystemInitialLoadParameters.0', '-Osqnv'), 'syno_hw_version')) {
$os = 'dsm'; // Synology DSM
} elseif (is_numeric(trim(snmp_get($device, 'roomTemp.0', '-OqvU', 'CAREL-ug40cdz-MIB')))) {
$os = 'pcoweb'; // Carel PCOweb
}
}
}

View File

@@ -106,20 +106,15 @@ function getHostOS($device)
d_echo("| $sysDescr | $sysObjectId | ");
$path = $config['install_dir'] . "/includes/discovery/os";
$dir_handle = @opendir($path) or die("Unable to open $path");
while ($file = readdir($dir_handle)) {
if (preg_match("/.php$/", $file)) {
include($config['install_dir'] . "/includes/discovery/os/" . $file);
$pattern = $config['install_dir'] . '/includes/discovery/os/*.inc.php';
foreach (glob($pattern) as $file) {
include $file;
if (isset($os)) {
return $os;
}
}
closedir($dir_handle);
if ($os) {
return $os;
} else {
return "generic";
}
return "generic";
}
function percent_colour($perc)

174
tests/OSDiscoveryTest.php Normal file
View File

@@ -0,0 +1,174 @@
<?php
/**
* DiscoveryTest.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 2016 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Tests;
include 'tests/mocks/mock.snmp.inc.php';
class DiscoveryTest extends \PHPUnit_Framework_TestCase
{
public function testAiros()
{
$this->checkOS('airos', 'Linux', '.1.3.6.1.4.1.10002.1');
$this->checkOS('airos', 'Linux', '.1.3.6.1.4.1.41112.1.4');
$mockSnmp = array(
'dot11manufacturerName.5' => 'Ubiquiti',
);
$this->checkOS('airos', 'Linux', '', $mockSnmp);
}
/**
* Set up variables and include os discovery
*
* @param string $expectedOS the OS to test for
* @param string $sysDescr set the snmp sysDescr variable
* @param string $sysObjectId set the snmp sysObjectId variable
* @param array $snmpMock set arbitrary snmp variables with an associative array
* @param array $device device array to send
*/
private function checkOS($expectedOS, $sysDescr = '', $sysObjectId = '', $mockSnmp = array(), $device = array())
{
global $config;
setSnmpMock($mockSnmp);
$os = null;
// cannot use getHostOS() because of functions.php includes
$pattern = $config['install_dir'] . '/includes/discovery/os/*.inc.php';
foreach (glob($pattern) as $file) {
include $file;
if (isset($os)) {
break;
}
}
$this->assertEquals($expectedOS, $os);
}
public function testAirosAf()
{
$mockSnmp = array(
'fwVersion.1' => '1.0',
);
$this->checkOS('airos-af', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp);
}
public function testCiscosmblinux()
{
$this->checkOS('ciscosmblinux', 'Linux Cisco Small Business');
}
public function testCumulus()
{
$this->checkOS('cumulus', 'Linux', '.1.3.6.1.4.1.40310');
}
public function testDdnos()
{
$mockSnmp = array(
'SFA-INFO::systemName.0' => 1,
);
$this->checkOS('ddnos', 'Linux', '', $mockSnmp);
}
public function testDsm()
{
$mockSnmp = array(
'HOST-RESOURCES-MIB::hrSystemInitialLoadParameters.0' => 'syno_hw_version',
);
$this->checkOS('dsm', 'Linux', '', $mockSnmp);
}
public function testEndian()
{
$this->checkOS('endian', 'Linux endian');
}
public function testLinux()
{
$this->checkOS('linux', 'Linux');
}
public function testNetbotz()
{
$this->checkOS('netbotz', 'Linux', '.1.3.6.1.4.1.5528.100.20.10.2014');
$this->checkOS('netbotz', 'Linux', '.1.3.6.1.4.1.5528.100.20.10.2016');
}
public function testPcoweb()
{
$mockSnmp = array(
'roomTemp.0' => 1,
);
$this->checkOS('pcoweb', 'Linux', '', $mockSnmp);
}
public function testPktj()
{
$mockSnmp = array(
'GANDI-MIB::rxCounter.0' => 1,
);
$this->checkOS('pktj', 'Linux', '', $mockSnmp);
}
public function testProcera()
{
$this->checkOS('procera', 'Linux', '.1.3.6.1.4.1.15397.2');
}
public function testQnap()
{
$mockSnmp = array(
'ENTITY-MIB::entPhysicalMfgName.1' => 'QNAP',
);
$this->checkOS('qnap', 'Linux', '', $mockSnmp);
}
public function testSophos()
{
$this->checkOS('sophos', 'Linux g56fa85e');
$this->checkOS('sophos', 'Linux gc80f187');
$this->checkOS('sophos', 'Linux g829be90');
$this->checkOS('sophos', 'Linux g63c0044');
}
public function testUnifi()
{
$mockSnmp = array(
'dot11manufacturerProductName.6' => 'UAP',
);
$this->checkOS('unifi', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp);
$mockSnmp = array(
'dot11manufacturerProductName.4' => 'UAP-PRO',
);
$this->checkOS('unifi', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp);
$mockSnmp = array(
'dot11manufacturerProductName.0' => 'UAP-AC2',
);
$this->checkOS('unifi', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp);
}
}

View File

@@ -33,3 +33,6 @@ $classLoader->registerDir($install_dir . '/tests', 'LibreNMS\Tests');
require_once $install_dir . '/includes/common.php';
require_once $install_dir . '/includes/rrdtool.inc.php';
require_once $install_dir . '/includes/syslog.php';
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);

View File

@@ -0,0 +1,64 @@
<?php
/**
* mock.snmp.inc.php
*
* Mock functions from includes/snmp.inc.php to allow tests to run without real snmp
*
* 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 2016 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
function setSnmpMock($mockSnmpArray)
{
global $mockSnmp;
$mockSnmp = $mockSnmpArray;
}
function snmp_get($device, $oid)
{
global $mockSnmp;
if (isset($mockSnmp) && !empty($mockSnmp)) {
if (isset($mockSnmp[$oid])) {
return $mockSnmp[$oid];
}
}
return false;
}
function snmp_walk($device, $oid)
{
global $mockSnmp;
$output = '';
foreach ($mockSnmp as $key => $value) {
if (starts_with($key, $oid)) {
$output .= $value . PHP_EOL;
}
}
if (empty($output)) {
// does this match the behavior of the real snmp_walk()?
return false;
} else {
return $output;
}
}
function register_mibs()
{
// stub
}