2018-02-05 07:39:13 -06:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Processor.php
|
|
|
|
*
|
|
|
|
* Processor Module
|
|
|
|
*
|
|
|
|
* 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
|
2021-02-09 00:29:04 +01:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2018-02-05 07:39:13 -06:00
|
|
|
*
|
2021-02-09 00:29:04 +01:00
|
|
|
* @link https://www.librenms.org
|
2018-02-05 07:39:13 -06:00
|
|
|
* @copyright 2017 Tony Murray
|
|
|
|
* @author Tony Murray <murraytony@gmail.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace LibreNMS\Device;
|
|
|
|
|
2020-04-17 17:37:56 -05:00
|
|
|
use Illuminate\Support\Str;
|
2018-02-05 07:39:13 -06:00
|
|
|
use LibreNMS\Interfaces\Discovery\DiscoveryItem;
|
|
|
|
use LibreNMS\Interfaces\Discovery\DiscoveryModule;
|
|
|
|
use LibreNMS\Interfaces\Discovery\ProcessorDiscovery;
|
|
|
|
use LibreNMS\Interfaces\Polling\PollerModule;
|
|
|
|
use LibreNMS\Interfaces\Polling\ProcessorPolling;
|
|
|
|
use LibreNMS\Model;
|
|
|
|
use LibreNMS\OS;
|
|
|
|
use LibreNMS\RRD\RrdDefinition;
|
|
|
|
|
|
|
|
class Processor extends Model implements DiscoveryModule, PollerModule, DiscoveryItem
|
|
|
|
{
|
|
|
|
protected static $table = 'processors';
|
|
|
|
protected static $primaryKey = 'processor_id';
|
|
|
|
|
|
|
|
private $valid = true;
|
|
|
|
|
|
|
|
public $processor_id;
|
|
|
|
public $device_id;
|
|
|
|
public $processor_type;
|
|
|
|
public $processor_usage;
|
|
|
|
public $processor_oid;
|
|
|
|
public $processor_index;
|
|
|
|
public $processor_descr;
|
|
|
|
public $processor_precision;
|
|
|
|
public $entPhysicalIndex;
|
|
|
|
public $hrDeviceIndex;
|
|
|
|
public $processor_perc_warn = 75;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Processor constructor.
|
|
|
|
* @param string $type
|
|
|
|
* @param int $device_id
|
|
|
|
* @param string $oid
|
2018-09-06 17:05:44 -05:00
|
|
|
* @param int|string $index
|
2018-02-05 07:39:13 -06:00
|
|
|
* @param string $description
|
|
|
|
* @param int $precision The returned value will be divided by this number (should be factor of 10) If negative this oid returns idle cpu
|
|
|
|
* @param int $current_usage
|
|
|
|
* @param int $warn_percent
|
|
|
|
* @param int $entPhysicalIndex
|
|
|
|
* @param int $hrDeviceIndex
|
|
|
|
* @return Processor
|
|
|
|
*/
|
|
|
|
public static function discover(
|
|
|
|
$type,
|
|
|
|
$device_id,
|
|
|
|
$oid,
|
|
|
|
$index,
|
|
|
|
$description = 'Processor',
|
|
|
|
$precision = 1,
|
|
|
|
$current_usage = null,
|
|
|
|
$warn_percent = 75,
|
|
|
|
$entPhysicalIndex = null,
|
|
|
|
$hrDeviceIndex = null
|
|
|
|
) {
|
|
|
|
$proc = new static();
|
|
|
|
$proc->processor_type = $type;
|
|
|
|
$proc->device_id = $device_id;
|
2020-09-21 14:54:51 +02:00
|
|
|
$proc->processor_index = (string) $index;
|
2018-02-05 07:39:13 -06:00
|
|
|
$proc->processor_descr = $description;
|
|
|
|
$proc->processor_precision = $precision;
|
|
|
|
$proc->processor_usage = $current_usage;
|
|
|
|
$proc->entPhysicalIndex = $entPhysicalIndex;
|
|
|
|
$proc->hrDeviceIndex = $hrDeviceIndex;
|
|
|
|
|
|
|
|
// handle string indexes
|
2020-04-17 17:37:56 -05:00
|
|
|
if (Str::contains($oid, '"')) {
|
2018-02-05 07:39:13 -06:00
|
|
|
$oid = preg_replace_callback('/"([^"]+)"/', function ($matches) {
|
|
|
|
return string_to_oid($matches[1]);
|
|
|
|
}, $oid);
|
|
|
|
}
|
|
|
|
$proc->processor_oid = '.' . ltrim($oid, '.');
|
|
|
|
|
2020-09-21 14:54:51 +02:00
|
|
|
if (! is_null($warn_percent)) {
|
2018-02-05 07:39:13 -06:00
|
|
|
$proc->processor_perc_warn = $warn_percent;
|
|
|
|
}
|
|
|
|
|
|
|
|
// validity not checked yet
|
|
|
|
if (is_null($proc->processor_usage)) {
|
|
|
|
$data = snmp_get(device_by_id_cache($proc->device_id), $proc->processor_oid, '-Ovq');
|
|
|
|
$proc->valid = ($data !== false);
|
2020-09-21 14:54:51 +02:00
|
|
|
if (! $proc->valid) {
|
2018-02-05 07:39:13 -06:00
|
|
|
return $proc;
|
|
|
|
}
|
|
|
|
$proc->processor_usage = static::processData($data, $proc->processor_precision);
|
|
|
|
}
|
|
|
|
|
|
|
|
d_echo('Discovered ' . get_called_class() . ' ' . print_r($proc->toArray(), true));
|
|
|
|
|
|
|
|
return $proc;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function fromYaml(OS $os, $index, array $data)
|
|
|
|
{
|
|
|
|
$precision = $data['precision'] ?: 1;
|
|
|
|
|
|
|
|
return static::discover(
|
|
|
|
$data['type'] ?: $os->getName(),
|
|
|
|
$os->getDeviceId(),
|
|
|
|
$data['num_oid'],
|
|
|
|
isset($data['index']) ? $data['index'] : $index,
|
|
|
|
$data['descr'] ?: 'Processor',
|
|
|
|
$precision,
|
|
|
|
static::processData($data['value'], $precision),
|
|
|
|
$data['warn_percent'],
|
|
|
|
$data['entPhysicalIndex'],
|
|
|
|
$data['hrDeviceIndex']
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function runDiscovery(OS $os)
|
|
|
|
{
|
|
|
|
// check yaml first
|
|
|
|
$processors = self::processYaml($os);
|
|
|
|
|
|
|
|
// if no processors found, check OS discovery (which will fall back to HR and UCD if not implemented
|
|
|
|
if (empty($processors) && $os instanceof ProcessorDiscovery) {
|
|
|
|
$processors = $os->discoverProcessors();
|
|
|
|
}
|
|
|
|
|
2018-09-11 06:07:45 +02:00
|
|
|
foreach ($processors as $processor) {
|
|
|
|
$processor->processor_descr = substr($processor->processor_descr, 0, 64);
|
|
|
|
$processors[] = $processor;
|
|
|
|
}
|
|
|
|
|
2018-02-05 07:39:13 -06:00
|
|
|
if (isset($processors) && is_array($processors)) {
|
|
|
|
self::sync(
|
|
|
|
$os->getDeviceId(),
|
|
|
|
$processors,
|
2018-10-24 15:15:58 -05:00
|
|
|
['device_id', 'processor_index', 'processor_type'],
|
|
|
|
['processor_usage', 'processor_perc_warn']
|
2018-02-05 07:39:13 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-09-21 14:54:51 +02:00
|
|
|
dbDeleteOrphans(static::$table, ['devices.device_id']);
|
2018-02-05 07:39:13 -06:00
|
|
|
|
|
|
|
echo PHP_EOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function poll(OS $os)
|
|
|
|
{
|
2020-09-21 14:54:51 +02:00
|
|
|
$processors = dbFetchRows('SELECT * FROM processors WHERE device_id=?', [$os->getDeviceId()]);
|
2018-02-05 07:39:13 -06:00
|
|
|
|
|
|
|
if ($os instanceof ProcessorPolling) {
|
|
|
|
$data = $os->pollProcessors($processors);
|
|
|
|
} else {
|
|
|
|
$data = static::pollProcessors($os, $processors);
|
|
|
|
}
|
|
|
|
|
|
|
|
$rrd_def = RrdDefinition::make()->addDataset('usage', 'GAUGE', -273, 1000);
|
|
|
|
|
|
|
|
foreach ($processors as $index => $processor) {
|
|
|
|
extract($processor); // extract db fields to variables
|
|
|
|
/** @var int $processor_id */
|
|
|
|
/** @var string $processor_type */
|
|
|
|
/** @var int $processor_index */
|
|
|
|
/** @var int $processor_usage */
|
Modernize mempools (#12282)
* mempools to modern module
quick hacky hrstorage port
* port ucd-snmp-mib to Mempools
* Populate DB for ucd
Prep for yaml
* initial yaml attempt
* more complex conversions
fixes to YamlDiscovery, make leading $ optional and allow mib::oid format
* walk full tables and skip values
normalize percentages above 100
* handle precent only ones (specify total as 100)
* Move default polling out of YamlMempoolsDiscovery
* fixes
* Update test data hrstorage should be correct.
* perc_warn for hrstorage
* Host Resources, record buffer, cached, and shared
* Host Resources is always better, don't do both HR and UCD
* fix unix, include warning levels
* variable size
* consolidate skip_values
* define mempools schema
* number instead of integer
* more schema refactor
* one more skip_values reference
* throw error for invalid oid translation
aos6
* a* and Cisco
* updated test data
* update almost all hrstorage data files
* b*
* c* with test data
use standard cache for hrStorage
* use cache for storage module too
* hand bsnmp properly
* bdcom
* exclude total oid from yaml so it is not polled
May add a way to ignore this behavior and poll it, but I don't know if that is needed.
* automatically handle percent only values
* ciscowlc
* only poll used or free if we have used, free, and total.
* fix skipping
* the dlinkoning
fix find value when value "name" is numeric
* support numeric oids
* dnos/ftos attempt
* I guess we can't filter on total > 0
* edgecos
* e*
* f WIP
* f*
* gwd (aka g*)
* h* + procurve
* i*
* j*
* m*
* support 0% used memory (however unlikely)
* n*
* CISCO-PROCESS-MIB memory, share cache with processors module
* ignore mempools with invalid total
* p*
* quanta
* r*
fix raisecom mibs terribly broken
* s-z
* style fixes
* Move VRP back to PHP and make it actually work
* fix zynos
* update schema
* Update Cisco processor data for description bug fixes
* fix comware processors
* comware mempools with memory size
default precision to 1
* sophos-xg updated data
* hrstorage use ram size for buffers, cache, and shared
* Show memory available instead of free in device overview
* UCD, use same rrd format, store available instead of free in the db.
* Calculate availability for HOST-RESOURCES-MIB
* Convert UCD to standard polling
* rename old rrd files
* initial graph work
* graph WIP
* Graph looking decent
* Graph looking decent for hr
* remove old ucd_graph code
* handle availability mempool
more graph cleanup
* color adjustments
* remove accidental free calculation
* Update test data and fix corner cases
* fis pfsense
* update schema
* add default value for mempool_class
* fix whitespace
* update schema
* update schema correctly
* one more time
* fortigate_1500d-sensors missing oids
* Update docs.
* fix indent
* add implements MempoolsDiscovery explicitly to OS
* remove ucd_memory graph references
remove unused device_memory graph
* remove unused functions
* set devices with mempools to rediscover to prevent/minimize gaps
* use a subquery
* add overview graph
* port health mempools table
* Update device mempool
* only show overview if multiple
* Don't override user set warn percentages in discovery
* fix missed usage
* fix style
* Safety check to not rename rrd files incorrectly if migration has not been run.
* Fix overview percent bar and represent available and used on the bar
* missed an item to convert to mempool_class
* percent on the wrong side
2020-11-23 15:35:35 -06:00
|
|
|
/** @var string $processor_descr */
|
2018-02-05 07:39:13 -06:00
|
|
|
if (array_key_exists($processor_id, $data)) {
|
|
|
|
$usage = round($data[$processor_id], 2);
|
Modernize mempools (#12282)
* mempools to modern module
quick hacky hrstorage port
* port ucd-snmp-mib to Mempools
* Populate DB for ucd
Prep for yaml
* initial yaml attempt
* more complex conversions
fixes to YamlDiscovery, make leading $ optional and allow mib::oid format
* walk full tables and skip values
normalize percentages above 100
* handle precent only ones (specify total as 100)
* Move default polling out of YamlMempoolsDiscovery
* fixes
* Update test data hrstorage should be correct.
* perc_warn for hrstorage
* Host Resources, record buffer, cached, and shared
* Host Resources is always better, don't do both HR and UCD
* fix unix, include warning levels
* variable size
* consolidate skip_values
* define mempools schema
* number instead of integer
* more schema refactor
* one more skip_values reference
* throw error for invalid oid translation
aos6
* a* and Cisco
* updated test data
* update almost all hrstorage data files
* b*
* c* with test data
use standard cache for hrStorage
* use cache for storage module too
* hand bsnmp properly
* bdcom
* exclude total oid from yaml so it is not polled
May add a way to ignore this behavior and poll it, but I don't know if that is needed.
* automatically handle percent only values
* ciscowlc
* only poll used or free if we have used, free, and total.
* fix skipping
* the dlinkoning
fix find value when value "name" is numeric
* support numeric oids
* dnos/ftos attempt
* I guess we can't filter on total > 0
* edgecos
* e*
* f WIP
* f*
* gwd (aka g*)
* h* + procurve
* i*
* j*
* m*
* support 0% used memory (however unlikely)
* n*
* CISCO-PROCESS-MIB memory, share cache with processors module
* ignore mempools with invalid total
* p*
* quanta
* r*
fix raisecom mibs terribly broken
* s-z
* style fixes
* Move VRP back to PHP and make it actually work
* fix zynos
* update schema
* Update Cisco processor data for description bug fixes
* fix comware processors
* comware mempools with memory size
default precision to 1
* sophos-xg updated data
* hrstorage use ram size for buffers, cache, and shared
* Show memory available instead of free in device overview
* UCD, use same rrd format, store available instead of free in the db.
* Calculate availability for HOST-RESOURCES-MIB
* Convert UCD to standard polling
* rename old rrd files
* initial graph work
* graph WIP
* Graph looking decent
* Graph looking decent for hr
* remove old ucd_graph code
* handle availability mempool
more graph cleanup
* color adjustments
* remove accidental free calculation
* Update test data and fix corner cases
* fis pfsense
* update schema
* add default value for mempool_class
* fix whitespace
* update schema
* update schema correctly
* one more time
* fortigate_1500d-sensors missing oids
* Update docs.
* fix indent
* add implements MempoolsDiscovery explicitly to OS
* remove ucd_memory graph references
remove unused device_memory graph
* remove unused functions
* set devices with mempools to rediscover to prevent/minimize gaps
* use a subquery
* add overview graph
* port health mempools table
* Update device mempool
* only show overview if multiple
* Don't override user set warn percentages in discovery
* fix missed usage
* fix style
* Safety check to not rename rrd files incorrectly if migration has not been run.
* Fix overview percent bar and represent available and used on the bar
* missed an item to convert to mempool_class
* percent on the wrong side
2020-11-23 15:35:35 -06:00
|
|
|
echo "$processor_descr: $usage%\n";
|
2018-02-05 07:39:13 -06:00
|
|
|
|
2020-09-21 14:54:51 +02:00
|
|
|
$rrd_name = ['processor', $processor_type, $processor_index];
|
2018-02-05 07:39:13 -06:00
|
|
|
$fields = compact('usage');
|
|
|
|
$tags = compact('processor_type', 'processor_index', 'rrd_name', 'rrd_def');
|
2020-09-18 08:12:07 -05:00
|
|
|
data_update($os->getDeviceArray(), 'processors', $tags, $fields);
|
2018-02-05 07:39:13 -06:00
|
|
|
|
|
|
|
if ($usage != $processor_usage) {
|
2020-09-21 14:54:51 +02:00
|
|
|
dbUpdate(['processor_usage' => $usage], 'processors', '`processor_id` = ?', [$processor_id]);
|
2018-02-05 07:39:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static function pollProcessors(OS $os, $processors)
|
|
|
|
{
|
|
|
|
if (empty($processors)) {
|
2020-09-21 14:54:51 +02:00
|
|
|
return [];
|
2018-02-05 07:39:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
$oids = array_column($processors, 'processor_oid');
|
|
|
|
|
|
|
|
// don't fetch too many at a time TODO build into snmp_get_multi_oid?
|
2020-09-21 14:54:51 +02:00
|
|
|
$snmp_data = [];
|
2020-09-18 08:12:07 -05:00
|
|
|
foreach (array_chunk($oids, get_device_oid_limit($os->getDeviceArray())) as $oid_chunk) {
|
|
|
|
$multi_data = snmp_get_multi_oid($os->getDeviceArray(), $oid_chunk);
|
2018-02-05 07:39:13 -06:00
|
|
|
$snmp_data = array_merge($snmp_data, $multi_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
d_echo($snmp_data);
|
|
|
|
|
2020-09-21 14:54:51 +02:00
|
|
|
$results = [];
|
2018-02-05 07:39:13 -06:00
|
|
|
foreach ($processors as $processor) {
|
|
|
|
if (isset($snmp_data[$processor['processor_oid']])) {
|
|
|
|
$value = static::processData(
|
|
|
|
$snmp_data[$processor['processor_oid']],
|
|
|
|
$processor['processor_precision']
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$value = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$results[$processor['processor_id']] = $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static function processData($data, $precision)
|
|
|
|
{
|
|
|
|
preg_match('/([0-9]{1,5}(\.[0-9]+)?)/', $data, $matches);
|
|
|
|
$value = $matches[1];
|
|
|
|
|
|
|
|
if ($precision < 0) {
|
|
|
|
// idle value, subtract from 100
|
|
|
|
$value = 100 - ($value / ($precision * -1));
|
|
|
|
} elseif ($precision > 1) {
|
|
|
|
$value = $value / $precision;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function processYaml(OS $os)
|
|
|
|
{
|
2020-09-18 08:12:07 -05:00
|
|
|
$device = $os->getDeviceArray();
|
2018-02-05 07:39:13 -06:00
|
|
|
if (empty($device['dynamic_discovery']['modules']['processors'])) {
|
|
|
|
d_echo("No YAML Discovery data.\n");
|
2020-09-21 14:54:51 +02:00
|
|
|
|
|
|
|
return [];
|
2018-02-05 07:39:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return YamlDiscovery::discover($os, get_class(), $device['dynamic_discovery']['modules']['processors']);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is this sensor valid?
|
|
|
|
* If not, it should not be added to or in the database
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function isValid()
|
|
|
|
{
|
|
|
|
return $this->valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get an array of this sensor with fields that line up with the database.
|
|
|
|
*
|
|
|
|
* @param array $exclude exclude columns
|
|
|
|
* @return array
|
|
|
|
*/
|
2020-09-21 14:54:51 +02:00
|
|
|
public function toArray($exclude = [])
|
2018-02-05 07:39:13 -06:00
|
|
|
{
|
2020-09-21 14:54:51 +02:00
|
|
|
$array = [
|
2018-02-05 07:39:13 -06:00
|
|
|
'processor_id' => $this->processor_id,
|
2020-09-21 14:54:51 +02:00
|
|
|
'entPhysicalIndex' => (int) $this->entPhysicalIndex,
|
|
|
|
'hrDeviceIndex' => (int) $this->hrDeviceIndex,
|
2018-02-05 07:39:13 -06:00
|
|
|
'device_id' => $this->device_id,
|
|
|
|
'processor_oid' => $this->processor_oid,
|
|
|
|
'processor_index' => $this->processor_index,
|
|
|
|
'processor_type' => $this->processor_type,
|
|
|
|
'processor_usage' => $this->processor_usage,
|
|
|
|
'processor_descr' => $this->processor_descr,
|
2020-09-21 14:54:51 +02:00
|
|
|
'processor_precision' => (int) $this->processor_precision,
|
|
|
|
'processor_perc_warn' => (int) $this->processor_perc_warn,
|
|
|
|
];
|
2018-02-05 07:39:13 -06:00
|
|
|
|
|
|
|
return array_diff_key($array, array_flip($exclude));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function onCreate($processor)
|
|
|
|
{
|
|
|
|
$message = "Processor Discovered: {$processor->processor_type} {$processor->processor_index} {$processor->processor_descr}";
|
|
|
|
log_event($message, $processor->device_id, static::$table, 3, $processor->processor_id);
|
|
|
|
|
|
|
|
parent::onCreate($processor);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function onDelete($processor)
|
|
|
|
{
|
|
|
|
$message = "Processor Removed: {$processor->processor_type} {$processor->processor_index} {$processor->processor_descr}";
|
|
|
|
log_event($message, $processor->device_id, static::$table, 3, $processor->processor_id);
|
|
|
|
|
|
|
|
parent::onDelete($processor); // TODO: Change the autogenerated stub
|
|
|
|
}
|
|
|
|
}
|