Issues (2963)

LibreNMS/Device/Processor.php (1 issue)

1
<?php
2
/**
3
 * Processor.php
4
 *
5
 * Processor Module
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 *
20
 * @link       https://www.librenms.org
21
 *
22
 * @copyright  2017 Tony Murray
23
 * @author     Tony Murray <[email protected]>
24
 */
25
26
namespace LibreNMS\Device;
27
28
use Illuminate\Support\Str;
29
use LibreNMS\Interfaces\Discovery\DiscoveryItem;
30
use LibreNMS\Interfaces\Discovery\DiscoveryModule;
31
use LibreNMS\Interfaces\Discovery\ProcessorDiscovery;
32
use LibreNMS\Interfaces\Polling\PollerModule;
33
use LibreNMS\Interfaces\Polling\ProcessorPolling;
34
use LibreNMS\Model;
35
use LibreNMS\OS;
36
use LibreNMS\RRD\RrdDefinition;
37
38
class Processor extends Model implements DiscoveryModule, PollerModule, DiscoveryItem
39
{
40
    protected static $table = 'processors';
41
    protected static $primaryKey = 'processor_id';
42
43
    private $valid = true;
44
45
    public $processor_id;
46
    public $device_id;
47
    public $processor_type;
48
    public $processor_usage;
49
    public $processor_oid;
50
    public $processor_index;
51
    public $processor_descr;
52
    public $processor_precision;
53
    public $entPhysicalIndex;
54
    public $hrDeviceIndex;
55
    public $processor_perc_warn = 75;
56
57
    /**
58
     * Processor constructor.
59
     *
60
     * @param  string  $type
61
     * @param  int  $device_id
62
     * @param  string  $oid
63
     * @param  int|string  $index
64
     * @param  string  $description
65
     * @param  int  $precision  The returned value will be divided by this number (should be factor of 10) If negative this oid returns idle cpu
66
     * @param  int  $current_usage
67
     * @param  int  $warn_percent
68
     * @param  int  $entPhysicalIndex
69
     * @param  int  $hrDeviceIndex
70
     * @return static
71
     */
72
    public static function discover(
73
        $type,
74
        $device_id,
75
        $oid,
76
        $index,
77
        $description = 'Processor',
78
        $precision = 1,
79
        $current_usage = null,
80
        $warn_percent = 75,
81
        $entPhysicalIndex = null,
82
        $hrDeviceIndex = null
83
    ) {
84
        $proc = new static();
85
        $proc->processor_type = $type;
86
        $proc->device_id = $device_id;
87
        $proc->processor_index = (string) $index;
88
        $proc->processor_descr = $description;
89
        $proc->processor_precision = $precision;
90
        $proc->processor_usage = $current_usage;
91
        $proc->entPhysicalIndex = $entPhysicalIndex;
92
        $proc->hrDeviceIndex = $hrDeviceIndex;
93
94
        // handle string indexes
95
        if (Str::contains($oid, '"')) {
96
            $oid = preg_replace_callback('/"([^"]+)"/', function ($matches) {
97
                return string_to_oid($matches[1]);
98
            }, $oid);
99
        }
100
        $proc->processor_oid = '.' . ltrim($oid, '.');
101
102
        if (! is_null($warn_percent)) {
0 ignored issues
show
The condition is_null($warn_percent) is always false.
Loading history...
103
            $proc->processor_perc_warn = $warn_percent;
104
        }
105
106
        // validity not checked yet
107
        if (is_null($proc->processor_usage)) {
108
            $data = snmp_get(device_by_id_cache($proc->device_id), $proc->processor_oid, '-Ovq');
109
            $proc->valid = ($data !== false);
110
            if (! $proc->valid) {
111
                return $proc;
112
            }
113
            $proc->processor_usage = static::processData($data, $proc->processor_precision);
114
        }
115
116
        d_echo('Discovered ' . get_called_class() . ' ' . print_r($proc->toArray(), true));
117
118
        return $proc;
119
    }
120
121
    public static function fromYaml(OS $os, $index, array $data)
122
    {
123
        $precision = $data['precision'] ?: 1;
124
125
        return static::discover(
126
            $data['type'] ?: $os->getName(),
127
            $os->getDeviceId(),
128
            $data['num_oid'],
129
            isset($data['index']) ? $data['index'] : $index,
130
            $data['descr'] ?: 'Processor',
131
            $precision,
132
            static::processData($data['value'], $precision),
133
            $data['warn_percent'],
134
            $data['entPhysicalIndex'],
135
            $data['hrDeviceIndex']
136
        );
137
    }
138
139
    public static function runDiscovery(OS $os)
140
    {
141
        // check yaml first
142
        $processors = self::processYaml($os);
143
144
        // if no processors found, check OS discovery (which will fall back to HR and UCD if not implemented
145
        if (empty($processors) && $os instanceof ProcessorDiscovery) {
146
            $processors = $os->discoverProcessors();
147
        }
148
149
        foreach ($processors as $processor) {
150
            $processor->processor_descr = substr($processor->processor_descr, 0, 64);
151
            $processors[] = $processor;
152
        }
153
154
        if (isset($processors) && is_array($processors)) {
155
            self::sync(
156
                $os->getDeviceId(),
157
                $processors,
158
                ['device_id', 'processor_index', 'processor_type'],
159
                ['processor_usage', 'processor_perc_warn']
160
            );
161
        }
162
163
        dbDeleteOrphans(static::$table, ['devices.device_id']);
164
165
        echo PHP_EOL;
166
    }
167
168
    public static function poll(OS $os)
169
    {
170
        $processors = dbFetchRows('SELECT * FROM processors WHERE device_id=?', [$os->getDeviceId()]);
171
172
        if ($os instanceof ProcessorPolling) {
173
            $data = $os->pollProcessors($processors);
174
        } else {
175
            $data = static::pollProcessors($os, $processors);
176
        }
177
178
        $rrd_def = RrdDefinition::make()->addDataset('usage', 'GAUGE', -273, 1000);
179
180
        foreach ($processors as $index => $processor) {
181
            extract($processor); // extract db fields to variables
182
            /** @var int $processor_id */
183
            /** @var string $processor_type */
184
            /** @var int $processor_index */
185
            /** @var int $processor_usage */
186
            /** @var string $processor_descr */
187
            if (array_key_exists($processor_id, $data)) {
188
                $usage = round($data[$processor_id], 2);
189
                echo "$processor_descr: $usage%\n";
190
191
                $rrd_name = ['processor', $processor_type, $processor_index];
192
                $fields = compact('usage');
193
                $tags = compact('processor_type', 'processor_index', 'rrd_name', 'rrd_def');
194
                data_update($os->getDeviceArray(), 'processors', $tags, $fields);
195
196
                if ($usage != $processor_usage) {
197
                    dbUpdate(['processor_usage' => $usage], 'processors', '`processor_id` = ?', [$processor_id]);
198
                }
199
            }
200
        }
201
    }
202
203
    private static function pollProcessors(OS $os, $processors)
204
    {
205
        if (empty($processors)) {
206
            return [];
207
        }
208
209
        $oids = array_column($processors, 'processor_oid');
210
211
        // don't fetch too many at a time TODO build into snmp_get_multi_oid?
212
        $snmp_data = [];
213
        foreach (array_chunk($oids, get_device_oid_limit($os->getDeviceArray())) as $oid_chunk) {
214
            $multi_data = snmp_get_multi_oid($os->getDeviceArray(), $oid_chunk);
215
            $snmp_data = array_merge($snmp_data, $multi_data);
216
        }
217
218
        d_echo($snmp_data);
219
220
        $results = [];
221
        foreach ($processors as $processor) {
222
            if (isset($snmp_data[$processor['processor_oid']])) {
223
                $value = static::processData(
224
                    $snmp_data[$processor['processor_oid']],
225
                    $processor['processor_precision']
226
                );
227
            } else {
228
                $value = 0;
229
            }
230
231
            $results[$processor['processor_id']] = $value;
232
        }
233
234
        return $results;
235
    }
236
237
    private static function processData($data, $precision)
238
    {
239
        preg_match('/([0-9]{1,5}(\.[0-9]+)?)/', $data, $matches);
240
        $value = $matches[1];
241
242
        if ($precision < 0) {
243
            // idle value, subtract from 100
244
            $value = 100 - ($value / ($precision * -1));
245
        } elseif ($precision > 1) {
246
            $value = $value / $precision;
247
        }
248
249
        return $value;
250
    }
251
252
    public static function processYaml(OS $os)
253
    {
254
        $device = $os->getDeviceArray();
255
        if (empty($device['dynamic_discovery']['modules']['processors'])) {
256
            d_echo("No YAML Discovery data.\n");
257
258
            return [];
259
        }
260
261
        return YamlDiscovery::discover($os, get_class(), $device['dynamic_discovery']['modules']['processors']);
262
    }
263
264
    /**
265
     * Is this sensor valid?
266
     * If not, it should not be added to or in the database
267
     *
268
     * @return bool
269
     */
270
    public function isValid()
271
    {
272
        return $this->valid;
273
    }
274
275
    /**
276
     * Get an array of this sensor with fields that line up with the database.
277
     *
278
     * @param  array  $exclude  exclude columns
279
     * @return array
280
     */
281
    public function toArray($exclude = [])
282
    {
283
        $array = [
284
            'processor_id' => $this->processor_id,
285
            'entPhysicalIndex' => (int) $this->entPhysicalIndex,
286
            'hrDeviceIndex' => (int) $this->hrDeviceIndex,
287
            'device_id' => $this->device_id,
288
            'processor_oid' => $this->processor_oid,
289
            'processor_index' => $this->processor_index,
290
            'processor_type' => $this->processor_type,
291
            'processor_usage' => $this->processor_usage,
292
            'processor_descr' => $this->processor_descr,
293
            'processor_precision' => (int) $this->processor_precision,
294
            'processor_perc_warn' => (int) $this->processor_perc_warn,
295
        ];
296
297
        return array_diff_key($array, array_flip($exclude));
298
    }
299
300
    /**
301
     * @param  Processor  $processor
302
     */
303
    public static function onCreate($processor)
304
    {
305
        $message = "Processor Discovered: {$processor->processor_type} {$processor->processor_index} {$processor->processor_descr}";
306
        log_event($message, $processor->device_id, static::$table, 3, $processor->processor_id);
307
308
        parent::onCreate($processor);
309
    }
310
311
    /**
312
     * @param  Processor  $processor
313
     */
314
    public static function onDelete($processor)
315
    {
316
        $message = "Processor Removed: {$processor->processor_type} {$processor->processor_index} {$processor->processor_descr}";
317
        log_event($message, $processor->device_id, static::$table, 3, $processor->processor_id);
318
319
        parent::onDelete($processor); // TODO: Change the autogenerated stub
320
    }
321
}
322