Files
librenms-librenms/includes/discovery/entity-physical/mrv-od.inc.php

361 lines
19 KiB
PHP
Raw Normal View History

Convert OS mrv-od to yaml, discover more sensors, discover entity-physical (#10266) * Dynamic entPhysicalIndex values for YamlDiscovery * Use degree symbol when displaying temperature values * Adjust SNMP options for new snmp_get_multi() The OS polling module for mrv-od was using snmpget commands with -Ovqs, rather than -OQUs, which meant that the equal sign was stripped in the snmpget output. But that equal sign is now used as the explode() delimiter so it broke the construction of the returned array for the snmp_get_multi() function. Additionally, I removed the NBS-CMMC-MIB:: prefix which is no longer returned by snmp_get_multi() as part of the OID. Now, the mrv-od.inc.php OS polling module is retrieving data from positions in the array with actual content. * Convert mrv-od to yaml, improve sensors discovery Converted sensors discovery for mrv-od to yaml, retaining all functionality for pre-cache, dbm, and temperature. Replaced specific SFF-8472 Digital Diagnostics state sensors with generic ones, given that we are now reading out detailed values through new dbm, current, voltage sensors. Reasoning: the generic Digital Diagnostics state sensors report state diagsOk, or else the worst severity level measured among all of the Digital Diagnostics values for that optical data point. You'd really only want to set a generic "alarm" so the box can report that it thinks something is wrong, whereafter a human can look at the graphs and/or the CLI to draw their conclusions about the alarm. Otherwise, things would quickly become too spammy as you are essentially duplicating every sensor across both regular measurements and state measurements. Further changes: - Increase maximum number of detected PSUs from 4 to 8 per the MIB. - State sensor to detect (in)sufficient power budget for all modules. - Use skip_values to hide state sensors with the notSupported value. - Use skip_values to hide sensors which are unsupported per the MIB, signified by the device returning special values -1 or -2147483648. - Add dBm, temperature "over" graphs to the mrv-od device header bar. * Add mrv-od entity-physical support MRV does not use the ENTITY-MIB data format, so we had to reconstruct the inventory from their proprietary format using the following tables from their NBS-CMMC-MIB: - nbsCmmcChassisTable - nbsCmmcSlotTable - nbsCmmcPortTable Additionally, since sensors didn't have their own ifindex in the NBS-CMMC-MIB, I went ahead and appended the last OID digit to the "containing" ifindex create a unique number. The same was done for the sensors in the yaml-discovery. * Test data for mrv-od, fix 2* pre-commit.php issues * Fix entPhysicalIndex returning 0 instead of null Some unit test breakage was caused by 62167ebcb which changed the code to return 0 instead of null when {{ $index }} was set as the entPhysicalIndex in the YamlDiscovery. So now we detect if it returns some value which may be interpreted as false, and if so we set null rather than 0.
2019-05-29 20:30:33 +02:00
<?php
/*
* LibreNMS entity-physical module for the discovery of components in the MRV® OptiDriver® Optical Transport Platform
*
* Copyright (c) 2019 Martijn Schmidt <martijn.schmidt@gmail.com>
*
* 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. Please see LICENSE.txt at the top level of
* the source code distribution for details.
*/
echo "\nCaching OIDs:";
$entity_array = [];
echo ' MRV OptiDriver';
$chassis_array = snmpwalk_cache_multi_oid($device, 'nbsCmmcChassisTable', $chassis_array, 'NBS-CMMC-MIB');
$slot_array = snmpwalk_cache_multi_oid($device, 'nbsCmmcSlotTable', $slot_array, 'NBS-CMMC-MIB');
$port_array = snmpwalk_cache_multi_oid($device, 'nbsCmmcPortTable', $port_array, 'NBS-CMMC-MIB');
// We use the last digit in the OID to define an entPhysicalIndex for Power Supply state sensors
$nbsCmmcChassisPSStatus_array = [
7 => 'nbsCmmcChassisPS1Status',
8 => 'nbsCmmcChassisPS2Status',
9 => 'nbsCmmcChassisPS3Status',
10 => 'nbsCmmcChassisPS4Status',
];
// We use the last digit in the OID to define an entPhysicalIndex for Fan state sensors
$nbsCmmcChassisFanStatus_array = [
11 => 'nbsCmmcChassisFan1Status',
12 => 'nbsCmmcChassisFan2Status',
13 => 'nbsCmmcChassisFan3Status',
14 => 'nbsCmmcChassisFan4Status',
36 => 'nbsCmmcChassisFan5Status',
37 => 'nbsCmmcChassisFan6Status',
38 => 'nbsCmmcChassisFan7Status',
39 => 'nbsCmmcChassisFan8Status',
];
// Define all the types of pluggable port form factors recognized by nbsCmmcPortType in NBS-CMMC-MIB,
// if nbsCmmcPortType returns a value that is not in this array, it should be a built-in port in the card.
$nbsCmmcPortType_array = [
125 => 'SFP',
147 => 'GBIC',
197 => 'XFP',
219 => 'QSFP+',
220 => 'CXP',
221 => 'CFP',
223 => 'QSFP28',
224 => 'CFP2',
];
$nbsCmmcPortSensor_array = [
30 => [
'objectType' => 'nbsCmmcPortTemperature',
'skipValue' => '-2147483648',
'entPhysicalName' => 'Port Temperature',
],
31 => [
'objectType' => 'nbsCmmcPortTxPower',
'skipValue' => '-2147483648',
'entPhysicalName' => 'Port Tx Power',
],
32 => [
'objectType' => 'nbsCmmcPortRxPower',
'skipValue' => '-2147483648',
'entPhysicalName' => 'Port Rx Power',
],
33 => [
'objectType' => 'nbsCmmcPortBiasAmps',
'skipValue' => '-1',
'entPhysicalName' => 'Port Tx Bias Current',
],
34 => [
'objectType' => 'nbsCmmcPortSupplyVolts',
'skipValue' => '-1',
'entPhysicalName' => 'Port Tx Supply Voltage',
],
38 => [
'objectType' => 'nbsCmmcPortDigitalDiags',
'skipValue' => '1',
'entPhysicalName' => 'Port Overall DigiDiags State',
],
];
foreach ($chassis_array as $nbsCmmcChassis => $chassis_contents) {
list($chassisHardwareRev, $chassisFirmwareRev) = explode(', ', $chassis_contents['nbsCmmcChassisHardwareRevision']);
// Discover the chassis
$entity_array[] = [
'entPhysicalIndex' => $chassis_contents['nbsCmmcChassisIfIndex']."00",
'entPhysicalDescr' => "MRV OptiDriver {$chassis_contents['nbsCmmcChassisModel']}",
'entPhysicalClass' => 'chassis',
'entPhysicalName' => "Chassis $nbsCmmcChassis",
'entPhysicalModelName' => $chassis_contents['nbsCmmcChassisModel'],
'entPhysicalSerialNum' => $chassis_contents['nbsCmmcChassisSerialNum'],
'entPhysicalContainedIn' => '0',
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => $chassis_contents['nbsCmmcChassisIndex'],
'entPhysicalVendorType' => $chassis_contents['nbsCmmcChassisType'],
'entPhysicalHardwareRev' => $chassisHardwareRev,
'entPhysicalFirmwareRev' => $chassisFirmwareRev,
'entPhysicalIsFRU' => 'true',
'entPhysicalAlias' => $chassis_contents['nbsCmmcChassisName'],
];
// Discover the chassis temperature sensor
if (isset($chassis_contents['nbsCmmcChassisTemperature']) && $chassis_contents['nbsCmmcChassisTemperature'] != '-2147483648') {
$entity_array[] = [
'entPhysicalIndex' => "{$chassis_contents['nbsCmmcChassisIfIndex']}15",
'entPhysicalDescr' => "Chassis Temperature Sensor",
'entPhysicalClass' => 'sensor',
'entPhysicalName' => "Chassis Temperature",
'entPhysicalContainedIn' => "{$chassis_contents['nbsCmmcChassisIfIndex']}00",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => '-1',
'entPhysicalIsFRU' => 'false',
];
}
// Discover the chassis power budget status sensor
if (isset($chassis_contents['nbsCmmcChassisPowerStatus']) && $chassis_contents['nbsCmmcChassisPowerStatus'] != 'notSupported') {
$entity_array[] = [
'entPhysicalIndex' => "{$chassis_contents['nbsCmmcChassisIfIndex']}51",
'entPhysicalDescr' => "Chassis Power Budget Status Sensor",
'entPhysicalClass' => 'sensor',
'entPhysicalName' => "Chassis Power Budget Status",
'entPhysicalContainedIn' => "{$chassis_contents['nbsCmmcChassisIfIndex']}00",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => '-1',
'entPhysicalIsFRU' => 'false',
];
}
// Discover the chassis power supplies and state sensors
foreach ($nbsCmmcChassisPSStatus_array as $index => $item) {
if (isset($chassis_contents[$item]) && $chassis_contents[$item] != 'notSupported') {
$position = substr($item, 16, 1);
$entity_array[] = [
'entPhysicalIndex' => $chassis_contents['nbsCmmcChassisIfIndex'].$position,
'entPhysicalDescr' => "Power Supply",
'entPhysicalClass' => 'powerSupply',
'entPhysicalName' => "Power Supply $position",
'entPhysicalContainedIn' => "{$chassis_contents['nbsCmmcChassisIfIndex']}00",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => $position,
'entPhysicalIsFRU' => 'false',
];
$entity_array[] = [
'entPhysicalIndex' => $chassis_contents['nbsCmmcChassisIfIndex'].$index,
'entPhysicalDescr' => "Power Supply State",
'entPhysicalClass' => 'sensor',
'entPhysicalName' => "Power Supply $position",
'entPhysicalContainedIn' => $chassis_contents['nbsCmmcChassisIfIndex'].$position,
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => '-1',
'entPhysicalIsFRU' => 'true',
];
}
}
// Discover the chassis fan trays and state sensors
foreach ($nbsCmmcChassisFanStatus_array as $index => $item) {
if (isset($chassis_contents[$item]) && $chassis_contents[$item] != 'notSupported') {
$position = substr($item, 17, 1);
$entity_array[] = [
'entPhysicalIndex' => "{$chassis_contents['nbsCmmcChassisIfIndex']}0$position",
'entPhysicalDescr' => "Fan Tray",
'entPhysicalClass' => 'fan',
'entPhysicalName' => "Fan Tray $position",
'entPhysicalContainedIn' => "{$chassis_contents['nbsCmmcChassisIfIndex']}00",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => $position,
'entPhysicalIsFRU' => 'false',
];
$entity_array[] = [
'entPhysicalIndex' => $chassis_contents['nbsCmmcChassisIfIndex'].$index,
'entPhysicalDescr' => "Fan State",
'entPhysicalClass' => 'sensor',
'entPhysicalName' => "Fan $position",
'entPhysicalContainedIn' => "{$chassis_contents['nbsCmmcChassisIfIndex']}0$position",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => '-1',
'entPhysicalIsFRU' => 'true',
];
}
}
}
foreach ($slot_array as $nbsCmmcSlot => $slot_contents) {
// Obtain the nbsCmmcChassisIfIndex of the chassis which houses this slot
$nbsCmmcChassisIfIndex = $chassis_array[$slot_contents['nbsCmmcSlotChassisIndex']]['nbsCmmcChassisIfIndex'];
// Calculate the nbsCmmcSlotIfIndex since an empty slot has nbsCmmcSlotIfIndex == -1
$nbsCmmcSlotIfIndex = $nbsCmmcChassisIfIndex + $slot_contents['nbsCmmcSlotIndex'] * 1000;
// Discover the slot
$entity_array[] = [
'entPhysicalIndex' => $nbsCmmcSlotIfIndex."00",
'entPhysicalDescr' => 'MRV OptiDriver Slot',
'entPhysicalClass' => 'container',
'entPhysicalName' => "Card Slot $nbsCmmcSlot",
'entPhysicalContainedIn' => $nbsCmmcChassisIfIndex."00",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => $slot_contents['nbsCmmcSlotIndex'],
'entPhysicalIsFRU' => 'false',
];
if (isset($slot_contents['nbsCmmcSlotIfIndex']) && $slot_contents['nbsCmmcSlotIfIndex'] != '-1') {
list($cardHardwareRev, $cardFirmwareRev, $cardOtherRev) = explode(', ', $slot_contents['nbsCmmcSlotHardwareRevision']);
// Discover the card
$entity_array[] = [
'entPhysicalIndex' => $slot_contents['nbsCmmcSlotIfIndex']."01",
'entPhysicalDescr' => "MRV ".ucfirst($slot_contents['nbsCmmcSlotOperationType'])." Card",
'entPhysicalClass' => 'module',
'entPhysicalName' => "Card $nbsCmmcSlot",
'entPhysicalModelName' => $slot_contents['nbsCmmcSlotModel'],
'entPhysicalSerialNum' => $slot_contents['nbsCmmcSlotSerialNum'],
'entPhysicalContainedIn' => "{$slot_contents['nbsCmmcSlotIfIndex']}00",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => '-1',
'entPhysicalVendorType' => $slot_contents['nbsCmmcSlotType'],
'entPhysicalHardwareRev' => "$cardHardwareRev, $cardOtherRev",
'entPhysicalFirmwareRev' => $cardFirmwareRev,
'entPhysicalIsFRU' => 'true',
'entPhysicalAlias' => $slot_contents['nbsCmmcSlotName'],
];
// Discover the module temperature sensor
if (isset($slot_contents['nbsCmmcSlotTemperature']) && $slot_contents['nbsCmmcSlotTemperature'] != '-2147483648') {
$entity_array[] = [
'entPhysicalIndex' => "{$slot_contents['nbsCmmcSlotIfIndex']}34",
'entPhysicalDescr' => "Card Temperature Sensor",
'entPhysicalClass' => 'sensor',
'entPhysicalName' => "Card Temperature",
'entPhysicalContainedIn' => "{$slot_contents['nbsCmmcSlotIfIndex']}01",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => '-1',
'entPhysicalIsFRU' => 'false',
];
}
}
}
foreach ($port_array as $nbsCmmcPort => $port_contents) {
// Obtain the nbsCmmcSlotIfIndex of the slot which houses this port
$nbsCmmcSlot = $port_contents['nbsCmmcPortChassisIndex'].".".$port_contents['nbsCmmcPortSlotIndex'];
$nbsCmmcSlotIfIndex = $slot_array[$nbsCmmcSlot]['nbsCmmcSlotIfIndex'];
// We only need to discover a transceiver container if the port type is pluggable
if (array_key_exists($port_contents['nbsCmmcPortType'], $nbsCmmcPortType_array)) {
$nbsCmmcPortType = $nbsCmmcPortType_array[$port_contents['nbsCmmcPortType']];
// Discover the transceiver container
$entity_array[] = [
'entPhysicalIndex' => $port_contents['nbsCmmcPortIfIndex']."00",
'entPhysicalDescr' => "$nbsCmmcPortType Transceiver Container",
'entPhysicalClass' => 'container',
'entPhysicalName' => "Transceiver Container $nbsCmmcPort",
'entPhysicalContainedIn' => $nbsCmmcSlotIfIndex."01",
'entPhysicalMfgName' => 'MRV Communications',
'entPhysicalParentRelPos' => $port_contents['nbsCmmcPortIndex'],
'entPhysicalIsFRU' => 'false',
];
// Set a few variables for the port discovery
$nbsCmmcPortContainedIn = $port_contents['nbsCmmcPortIfIndex']."00";
$nbsCmmcPortVendorInfo = $port_contents['nbsCmmcPortVendorInfo'];
$nbsCmmcPortIsFRU = 'true';
$nbsCmmcPortParentRelPos = '-1';
// If one runs a command like "show 1.1.1 | grep Part" on a port with a genuine pluggable transceiver,
// CLI output like "Part #/Rev: SFP-10GDWZR-22/0001" indicates / is considered to be the string delimiter.
// However, non-genuine pluggable transceivers may not adhere to this format.
list($nbsCmmcPortModelName, $nbsCmmcPortHardwareRev) = explode('/', $port_contents['nbsCmmcPortPartRev']);
} else {
$nbsCmmcPortType = 'Built-in';
// Set a few variables for the port discovery
$nbsCmmcPortContainedIn = $nbsCmmcSlotIfIndex."01";
$nbsCmmcPortVendorInfo = "MRV Communications";
$nbsCmmcPortIsFRU = 'false';
$nbsCmmcPortParentRelPos = $port_contents['nbsCmmcPortIndex'];
$nbsCmmcPortModelName = '';
$nbsCmmcPortHardwareRev = '';
}
if (isset($port_contents['nbsCmmcPortConnector']) && $port_contents['nbsCmmcPortConnector'] != 'removed') {
// Determine the correct entPhysicalDescr for the port
if (isset($port_contents['nbsCmmcPortWavelengthX']) && $port_contents['nbsCmmcPortWavelengthX'] != 'N/A') {
$portEntPhysicalDescr = "$nbsCmmcPortType Port, {$port_contents['nbsCmmcPortWavelengthX']}nm Tx Signal, {$port_contents['nbsCmmcPortConnector']} Connector";
} elseif (!empty($port_contents['nbsCmmcPortDescription'])) {
$portEntPhysicalDescr = "$nbsCmmcPortType Port, {$port_contents['nbsCmmcPortDescription']}, {$port_contents['nbsCmmcPortConnector']} Connector";
} else {
$portEntPhysicalDescr = "$nbsCmmcPortType Port, {$port_contents['nbsCmmcPortConnector']} Connector";
}
// Discover the port
$entity_array[] = [
'entPhysicalIndex' => "{$port_contents['nbsCmmcPortIfIndex']}01",
'entPhysicalDescr' => $portEntPhysicalDescr,
'entPhysicalClass' => 'port',
'entPhysicalName' => "Port $nbsCmmcPort",
'entPhysicalModelName' => $nbsCmmcPortModelName,
'entPhysicalSerialNum' => $port_contents['nbsCmmcPortSerialNumber'],
'entPhysicalContainedIn' => $nbsCmmcPortContainedIn,
'entPhysicalMfgName' => $nbsCmmcPortVendorInfo,
'entPhysicalParentRelPos' => $nbsCmmcPortParentRelPos,
'entPhysicalVendorType' => $port_contents['nbsCmmcPortType'],
'entPhysicalHardwareRev' => $nbsCmmcPortHardwareRev,
'entPhysicalIsFRU' => $nbsCmmcPortIsFRU,
'entPhysicalAlias' => $port_contents['nbsCmmcPortName'],
'ifIndex' => $port_contents['nbsCmmcPortIfIndex'],
];
// Discover the port sensors
foreach ($nbsCmmcPortSensor_array as $index => $nbsCmmcPortSensor) {
if (isset($port_contents[$nbsCmmcPortSensor['objectType']]) && $port_contents[$nbsCmmcPortSensor['objectType']] != $nbsCmmcPortSensor['skipValue']) {
$entity_array[] = [
'entPhysicalIndex' => $port_contents['nbsCmmcPortIfIndex'].$index,
'entPhysicalDescr' => "{$nbsCmmcPortSensor['entPhysicalName']} Sensor",
'entPhysicalClass' => 'sensor',
'entPhysicalName' => $nbsCmmcPortSensor['entPhysicalName'],
'entPhysicalContainedIn' => "{$port_contents['nbsCmmcPortIfIndex']}01",
'entPhysicalMfgName' => $nbsCmmcPortVendorInfo,
'entPhysicalParentRelPos' => '-1',
'entPhysicalIsFRU' => 'false',
];
}
}
}
}
foreach ($entity_array as $entPhysicalIndex => $entry) {
$entPhysicalIndex = array_key_exists('entPhysicalIndex', $entry) ? $entry['entPhysicalIndex'] : '';
$entPhysicalDescr = array_key_exists('entPhysicalDescr', $entry) ? $entry['entPhysicalDescr'] : '';
$entPhysicalClass = array_key_exists('entPhysicalClass', $entry) ? $entry['entPhysicalClass'] : '';
$entPhysicalName = array_key_exists('entPhysicalName', $entry) ? $entry['entPhysicalName'] : '';
$entPhysicalModelName = array_key_exists('entPhysicalModelName', $entry) ? $entry['entPhysicalModelName'] : '';
$entPhysicalSerialNum = array_key_exists('entPhysicalSerialNum', $entry) ? $entry['entPhysicalSerialNum'] : '';
$entPhysicalContainedIn = array_key_exists('entPhysicalContainedIn', $entry) ? $entry['entPhysicalContainedIn'] : '';
$entPhysicalMfgName = array_key_exists('entPhysicalMfgName', $entry) ? $entry['entPhysicalMfgName'] : '';
$entPhysicalParentRelPos = array_key_exists('entPhysicalParentRelPos', $entry) ? $entry['entPhysicalParentRelPos'] : '';
$entPhysicalVendorType = array_key_exists('entPhysicalVendorType', $entry) ? $entry['entPhysicalVendorType'] : '';
$entPhysicalHardwareRev = array_key_exists('entPhysicalHardwareRev', $entry) ? $entry['entPhysicalHardwareRev'] : '';
$entPhysicalFirmwareRev = array_key_exists('entPhysicalFirmwareRev', $entry) ? $entry['entPhysicalFirmwareRev'] : '';
$entPhysicalSoftwareRev = array_key_exists('entPhysicalSoftwareRev', $entry) ? $entry['entPhysicalSoftwareRev'] : '';
$entPhysicalIsFRU = array_key_exists('entPhysicalIsFRU', $entry) ? $entry['entPhysicalIsFRU'] : '';
$entPhysicalAlias = array_key_exists('entPhysicalAlias', $entry) ? $entry['entPhysicalAlias'] : '';
$entPhysicalAssetID = array_key_exists('entPhysicalAssetID', $entry) ? $entry['entPhysicalAssetID'] : '';
$ifIndex = array_key_exists('ifIndex', $entry) ? $entry['ifIndex'] : '';
discover_entity_physical($valid, $device, $entPhysicalIndex, $entPhysicalDescr, $entPhysicalClass, $entPhysicalName, $entPhysicalModelName, $entPhysicalSerialNum, $entPhysicalContainedIn, $entPhysicalMfgName, $entPhysicalParentRelPos, $entPhysicalVendorType, $entPhysicalHardwareRev, $entPhysicalFirmwareRev, $entPhysicalSoftwareRev, $entPhysicalIsFRU, $entPhysicalAlias, $entPhysicalAssetID, $ifIndex);
}//end foreach
echo "\n";
unset(
$update_data,
$insert_data,
$entry,
$entity_array
);