Issues (2963)

includes/html/collectd/functions.php (10 issues)

1
<?php
2
/*
3
 * Copyright (C) 2009  Bruno Prémont <bonbons AT linux-vserver.org>
4
 *
5
 * This program is free software; you can redistribute it and/or modify it under
6
 * the terms of the GNU General Public License as published by the Free Software
7
 * Foundation; only version 2 of the License is applicable.
8
 *
9
 * This program is distributed in the hope that it will be useful, but WITHOUT
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12
 * details.
13
 *
14
 * You should have received a copy of the GNU General Public License along with
15
 * this program; if not, write to the Free Software Foundation, Inc.,
16
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17
 */
18
19
require 'includes/html/collectd/CollectdColor.php';
20
21
use LibreNMS\CollectdColor;
22
use LibreNMS\Config;
23
24
define('REGEXP_HOST', '/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/');
25
define('REGEXP_PLUGIN', '/^[a-zA-Z0-9_.-]+$/');
26
27
/*
28
 * Read input variable from GET, POST or COOKIE taking
29
 * care of magic quotes
30
 *
31
 * @param string $name Name of value to return
32
 * @param array $array User-input array ($_GET, $_POST or $_COOKIE)
33
 * @param string $default Default value
34
 * @return string $default if name in unknown in $array, otherwise
35
 *         input value with magic quotes stripped off
36
 */
37
function read_var($name, &$array, $default = null)
38
{
39
    if (isset($array[$name])) {
40
        if (is_array($array[$name])) {
41
            if (get_magic_quotes_gpc()) {
42
                $ret = [];
43
                foreach ($array[$name] as $k => $v) {
44
                    $ret[stripslashes($k)] = stripslashes($v);
45
                }
46
47
                return $ret;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $ret returns the type array which is incompatible with the documented return type string.
Loading history...
48
            } else {
49
                return $array[$name];
50
            }
51
        } elseif (is_string($array[$name]) && get_magic_quotes_gpc()) {
52
            return stripslashes($array[$name]);
53
        } else {
54
            return $array[$name];
55
        }
56
    } else {
57
        return $default;
58
    }
59
}//end read_var()
60
61
/*
62
 * Alphabetically compare host names, comparing label
63
 * from tld to node name
64
 */
65
function collectd_compare_host($a, $b)
66
{
67
    $ea = explode('.', $a);
68
    $eb = explode('.', $b);
69
    $i = (count($ea) - 1);
70
    $j = (count($eb) - 1);
71
    while ($i >= 0 && $j >= 0) {
72
        if (($r = strcmp($ea[$i--], $eb[$j--])) != 0) {
73
            return $r;
74
        }
75
    }
76
77
    return 0;
78
}//end collectd_compare_host()
79
80
/**
81
 * Fetch list of hosts found in collectd's datadirs.
82
 *
83
 * @return array Sorted list of hosts (sorted by label from rigth to left)
84
 */
85
function collectd_list_hosts()
86
{
87
    $hosts = [];
88
    foreach (Config::get('datadirs') as $datadir) {
89
        if ($d = @opendir($datadir)) {
90
            while (($dent = readdir($d)) !== false) {
91
                if ($dent != '.' && $dent != '..' && is_dir($datadir . '/' . $dent) && preg_match(REGEXP_HOST, $dent)) {
92
                    $hosts[] = $dent;
93
                }
94
            }
95
            closedir($d);
96
        } else {
97
            error_log('Failed to open datadir: ' . $datadir);
98
        }
99
    }
100
    $hosts = array_unique($hosts);
101
    usort($hosts, 'collectd_compare_host');
102
103
    return $hosts;
104
}
105
106
/**
107
 * Fetch list of plugins found in collectd's datadirs for given host.
108
 *
109
 * @param  string  $arg_host  Name of host for which to return plugins
110
 * @return array Sorted list of plugins (sorted alphabetically)
111
 */
112
function collectd_list_plugins($arg_host)
113
{
114
    $plugins = [];
115
    foreach (Config::get('datadirs') as $datadir) {
116
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir . '/' . $arg_host))) {
117
            while (($dent = readdir($d)) !== false) {
118
                if ($dent != '.' && $dent != '..' && is_dir($datadir . '/' . $arg_host . '/' . $dent)) {
119
                    if ($i = strpos($dent, '-')) {
120
                        $plugins[] = substr($dent, 0, $i);
121
                    } else {
122
                        $plugins[] = $dent;
123
                    }
124
                }
125
            }
126
127
            closedir($d);
128
        }
129
    }
130
131
    $plugins = array_unique($plugins);
132
    sort($plugins);
133
134
    return $plugins;
135
}//end collectd_list_plugins()
136
137
/**
138
 * Fetch list of plugin instances found in collectd's datadirs for given host+plugin
139
 *
140
 * @param  string  $arg_host  Name of host
141
 * @param  string  $arg_plugin  Name of plugin
142
 * @return array Sorted list of plugin instances (sorted alphabetically)
143
 */
144
function collectd_list_pinsts($arg_host, $arg_plugin)
145
{
146
    $pinsts = [];
147
    foreach (Config::get('datadirs') as $datadir) {
148
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = opendir($datadir . '/' . $arg_host))) {
149
            while (($dent = readdir($d)) !== false) {
150
                if ($dent != '.' && $dent != '..' && is_dir($datadir . '/' . $arg_host . '/' . $dent)) {
151
                    if ($i = strpos($dent, '-')) {
152
                        $plugin = substr($dent, 0, $i);
153
                        $pinst = substr($dent, ($i + 1));
154
                    } else {
155
                        $plugin = $dent;
156
                        $pinst = '';
157
                    }
158
159
                    if ($plugin == $arg_plugin) {
160
                        $pinsts[] = $pinst;
161
                    }
162
                }
163
            }
164
165
            closedir($d);
166
        }
167
    }//end foreach
168
169
    $pinsts = array_unique($pinsts);
170
    sort($pinsts);
171
172
    return $pinsts;
173
}//end collectd_list_pinsts()
174
175
/**
176
 * Fetch list of types found in collectd's datadirs for given host+plugin+instance
177
 *
178
 * @arg_host Name of host
179
 * @arg_plugin Name of plugin
180
 * @arg_pinst Plugin instance
181
 *
182
 * @return array Sorted list of types (sorted alphabetically)
183
 */
184
function collectd_list_types($arg_host, $arg_plugin, $arg_pinst)
185
{
186
    $types = [];
187
    $my_plugin = $arg_plugin . (strlen($arg_pinst) ? '-' . $arg_pinst : '');
188
    if (! preg_match(REGEXP_PLUGIN, $my_plugin)) {
189
        return $types;
190
    }
191
192
    foreach (Config::get('datadirs') as $datadir) {
193
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir . '/' . $arg_host . '/' . $my_plugin))) {
194
            while (($dent = readdir($d)) !== false) {
195
                if ($dent != '.' && $dent != '..' && is_file($datadir . '/' . $arg_host . '/' . $my_plugin . '/' . $dent) && substr($dent, (strlen($dent) - 4)) == '.rrd') {
196
                    $dent = substr($dent, 0, (strlen($dent) - 4));
197
                    if ($i = strpos($dent, '-')) {
198
                        $types[] = substr($dent, 0, $i);
199
                    } else {
200
                        $types[] = $dent;
201
                    }
202
                }
203
            }
204
205
            closedir($d);
206
        }
207
    }
208
209
    $types = array_unique($types);
210
    sort($types);
211
212
    return $types;
213
}//end collectd_list_types()
214
215
/**
216
 * Fetch list of type instances found in collectd's datadirs for given host+plugin+instance+type
217
 *
218
 * @arg_host Name of host
219
 * @arg_plugin Name of plugin
220
 * @arg_pinst Plugin instance
221
 * @arg_type Type
222
 *
223
 * @return array Sorted list of type instances (sorted alphabetically)
224
 */
225
function collectd_list_tinsts($arg_host, $arg_plugin, $arg_pinst, $arg_type)
226
{
227
    $tinsts = [];
228
    $my_plugin = $arg_plugin . (strlen($arg_pinst) ? '-' . $arg_pinst : '');
229
    if (! preg_match(REGEXP_PLUGIN, $my_plugin)) {
230
        return $tinsts;
231
    }
232
233
    foreach (Config::get('datadirs') as $datadir) {
234
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir . '/' . $arg_host . '/' . $my_plugin))) {
235
            while (($dent = readdir($d)) !== false) {
236
                if ($dent != '.' && $dent != '..' && is_file($datadir . '/' . $arg_host . '/' . $my_plugin . '/' . $dent) && substr($dent, (strlen($dent) - 4)) == '.rrd') {
237
                    $dent = substr($dent, 0, (strlen($dent) - 4));
238
                    if ($i = strpos($dent, '-')) {
239
                        $type = substr($dent, 0, $i);
240
                        $tinst = substr($dent, ($i + 1));
241
                    } else {
242
                        $type = $dent;
243
                        $tinst = '';
244
                    }
245
246
                    if ($type == $arg_type) {
247
                        $tinsts[] = $tinst;
248
                    }
249
                }
250
            }
251
252
            closedir($d);
253
        }
254
    }//end foreach
255
256
    $tinsts = array_unique($tinsts);
257
    sort($tinsts);
258
259
    return $tinsts;
260
}//end collectd_list_tinsts()
261
262
/**
263
 * Parse symlinks in order to get an identifier that collectd understands
264
 * (e.g. virtualisation is collected on host for individual VMs and can be
265
 *  symlinked to the VM's hostname, support FLUSH for these by flushing
266
 *  on the host-identifier instead of VM-identifier)
267
 *
268
 * @param  string  $host  Hostname
269
 * @param  string  $plugin  Plugin name
270
 * @param  string  $type
271
 * @param  string  $pinst  Plugin instance
272
 * @param  string  $tinst  Type instance
273
 * @return string Identifier that collectd's FLUSH command understands
274
 */
275
function collectd_identifier($host, $plugin, $type, $pinst, $tinst)
276
{
277
    $rrd_realpath = null;
278
    $orig_identifier = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, strlen($pinst) ? '-' : '', $pinst, $type, strlen($tinst) ? '-' : '', $tinst);
279
    $identifier = null;
280
    foreach (Config::get('datadirs') as $datadir) {
281
        if (is_file($datadir . '/' . $orig_identifier . '.rrd')) {
282
            $rrd_realpath = realpath($datadir . '/' . $orig_identifier . '.rrd');
283
            break;
284
        }
285
    }
286
287
    if ($rrd_realpath) {
288
        $identifier = basename($rrd_realpath);
289
        $identifier = substr($identifier, 0, (strlen($identifier) - 4));
290
        $rrd_realpath = dirname($rrd_realpath);
291
        $identifier = basename($rrd_realpath) . '/' . $identifier;
292
        $rrd_realpath = dirname($rrd_realpath);
293
        $identifier = basename($rrd_realpath) . '/' . $identifier;
294
    }
295
296
    if (is_null($identifier)) {
297
        return $orig_identifier;
298
    } else {
299
        return $identifier;
300
    }
301
}//end collectd_identifier()
302
303
/**
304
 * Tell collectd that it should FLUSH all data it has regarding the
305
 * graph we are about to generate.
306
 *
307
 * @param  string  $identifier
308
 * @return bool
309
 */
310
function collectd_flush($identifier)
311
{
312
    if (! Config::get('collectd_sock')) {
313
        return false;
314
    }
315
316
    if (is_null($identifier) || (is_array($identifier) && count($identifier) == 0) || ! (is_string($identifier) || is_array($identifier))) {
0 ignored issues
show
The condition is_string($identifier) is always true.
Loading history...
The condition is_array($identifier) is always false.
Loading history...
317
        return false;
318
    }
319
320
    $u_errno = 0;
321
    $u_errmsg = '';
322
    if ($socket = @fsockopen(Config::get('collectd_sock'), 0, $u_errno, $u_errmsg)) {
323
        $cmd = 'FLUSH plugin=rrdtool';
324
        if (is_array($identifier)) {
0 ignored issues
show
The condition is_array($identifier) is always false.
Loading history...
325
            foreach ($identifier as $val) {
326
                $cmd .= sprintf(' identifier="%s"', $val);
327
            }
328
        } else {
329
            $cmd .= sprintf(' identifier="%s"', $identifier);
330
        }
331
332
        $cmd .= "\n";
333
334
        $r = fwrite($socket, $cmd, strlen($cmd));
335
        if ($r === false || $r != strlen($cmd)) {
336
            error_log(sprintf('graph.php: Failed to write whole command to unix-socket: %d out of %d written', $r === false ? (-1) : $r, strlen($cmd)));
337
        }
338
339
        $resp = fgets($socket);
340
        if ($resp === false) {
341
            error_log(sprintf('graph.php: Failed to read response from collectd for command: %s', trim($cmd)));
342
        }
343
344
        $n = (int) $resp;
345
        while ($n-- > 0) {
346
            fgets($socket);
347
        }
348
349
        fclose($socket);
350
    } else {
351
        error_log(sprintf('graph.php: Failed to open unix-socket to collectd: %d: %s', $u_errno, $u_errmsg));
352
    }
353
354
    return true;
355
}//end collectd_flush()
356
357
/**
358
 * Helper function to strip quotes from RRD output
359
 *
360
 * @param  string  $str  RRD-Info generated string
361
 * @return string String with one surrounding pair of quotes stripped
362
 */
363
function rrd_strip_quotes($str)
364
{
365
    if ($str[0] == '"' && $str[(strlen($str) - 1)] == '"') {
366
        return substr($str, 1, (strlen($str) - 2));
367
    } else {
368
        return $str;
369
    }
370
}//end rrd_strip_quotes()
371
372
/**
373
 * Determine useful information about RRD file
374
 *
375
 * @param  string  $file  Name of RRD file to analyse
376
 * @return array Array describing the RRD file
377
 */
378
function _rrd_info($file)
379
{
380
    $info = ['filename' => $file];
381
382
    $rrd = popen(RRDTOOL . ' info ' . escapeshellarg($file), 'r');
383
    if ($rrd) {
0 ignored issues
show
$rrd is of type resource, thus it always evaluated to false.
Loading history...
384
        while (($s = fgets($rrd)) !== false) {
385
            $p = strpos($s, '=');
386
            if ($p === false) {
387
                continue;
388
            }
389
390
            $key = trim(substr($s, 0, $p));
391
            $value = trim(substr($s, ($p + 1)));
392
            if (strncmp($key, 'ds[', 3) == 0) {
393
                // DS definition
394
                $p = strpos($key, ']');
395
                $ds = substr($key, 3, ($p - 3));
396
                if (! isset($info['DS'])) {
397
                    $info['DS'] = [];
398
                }
399
400
                $ds_key = substr($key, ($p + 2));
401
402
                if (strpos($ds_key, '[') === false) {
403
                    if (! isset($info['DS']["$ds"])) {
404
                        $info['DS']["$ds"] = [];
405
                    }
406
407
                    $info['DS']["$ds"]["$ds_key"] = rrd_strip_quotes($value);
408
                }
409
            } elseif (strncmp($key, 'rra[', 4) == 0) {
410
                // RRD definition
411
                $p = strpos($key, ']');
412
                $rra = substr($key, 4, ($p - 4));
413
                if (! isset($info['RRA'])) {
414
                    $info['RRA'] = [];
415
                }
416
417
                $rra_key = substr($key, ($p + 2));
418
419
                if (strpos($rra_key, '[') === false) {
420
                    if (! isset($info['RRA']["$rra"])) {
421
                        $info['RRA']["$rra"] = [];
422
                    }
423
424
                    $info['RRA']["$rra"]["$rra_key"] = rrd_strip_quotes($value);
425
                }
426
            } elseif (strpos($key, '[') === false) {
427
                $info[$key] = rrd_strip_quotes($value);
428
            }//end if
429
        }//end while
430
431
        pclose($rrd);
432
    }//end if
433
434
    return $info;
435
}//end _rrd_info()
436
437
function rrd_get_color($code, $line = true)
438
{
439
    $name = ($line ? 'f_' : 'h_') . $code;
440
    if (! Config::has("rrd_colors.$name")) {
441
        $c_f = new CollectdColor('random');
442
        $c_h = new CollectdColor($c_f);
443
        $c_h->fade();
444
        Config::set("rrd_colors.f_$code", $c_f->toString());
445
        Config::set("rrd_colors.h_$code", $c_h->toString());
446
    }
447
448
    return Config::get("rrd_colors.$name");
449
}//end rrd_get_color()
450
451
/**
452
 * Draw RRD file based on it's structure
453
 *
454
 * @param $host
455
 * @param $plugin
456
 * @param $type
457
 * @param  null  $pinst
458
 * @param  null  $tinst
459
 * @param  array  $opts
460
 * @return string|false Commandline to call RRDGraph in order to generate the final graph* @internal param $
461
 */
462
function collectd_draw_rrd($host, $plugin, $type, $pinst = null, $tinst = null, $opts = [])
463
{
464
    $timespan_def = null;
465
    $timespans = Config::get('timespan');
466
    if (! isset($opts['timespan'])) {
467
        $timespan_def = reset($timespans);
468
    } else {
469
        foreach ($timespans as &$ts) {
470
            if ($ts['name'] == $opts['timespan']) {
471
                $timespan_def = $ts;
472
            }
473
        }
474
    }
475
476
    if (! isset($opts['rrd_opts'])) {
477
        $opts['rrd_opts'] = [];
478
    }
479
480
    if (isset($opts['logarithmic']) && $opts['logarithmic']) {
481
        array_unshift($opts['rrd_opts'], '-o');
482
    }
483
484
    $rrdinfo = null;
485
    $rrdfile = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, is_null($pinst) ? '' : '-', $pinst, $type, is_null($tinst) ? '' : '-', $tinst);
0 ignored issues
show
The condition is_null($tinst) is always true.
Loading history...
The condition is_null($pinst) is always true.
Loading history...
486
    foreach (Config::get('datadirs') as $datadir) {
487
        if (is_file($datadir . '/' . $rrdfile . '.rrd')) {
488
            $rrdinfo = _rrd_info($datadir . '/' . $rrdfile . '.rrd');
489
            if (isset($rrdinfo['RRA']) && is_array($rrdinfo['RRA'])) {
490
                break;
491
            } else {
492
                $rrdinfo = null;
493
            }
494
        }
495
    }
496
497
    if (is_null($rrdinfo)) {
498
        return false;
499
    }
500
501
    $graph = [];
502
    $has_avg = false;
503
    $has_max = false;
504
    $has_min = false;
505
    reset($rrdinfo['RRA']);
506
    $l_max = 0;
507
    foreach ($rrdinfo['RRA'] as $k => $v) {
508
        if ($v['cf'] == 'MAX') {
509
            $has_max = true;
510
        } elseif ($v['cf'] == 'AVERAGE') {
511
            $has_avg = true;
512
        } elseif ($v['cf'] == 'MIN') {
513
            $has_min = true;
514
        }
515
    }
516
517
    // Build legend. This may not work for all RRDs, i don't know :)
518
    if ($has_avg) {
519
        $graph[] = 'COMMENT:           Last';
520
    }
521
522
    if ($has_min) {
523
        $graph[] = 'COMMENT:   Min';
524
    }
525
526
    if ($has_max) {
527
        $graph[] = 'COMMENT:   Max';
528
    }
529
530
    if ($has_avg) {
531
        $graph[] = 'COMMENT:   Avg\\n';
532
    }
533
534
    reset($rrdinfo['DS']);
0 ignored issues
show
$rrdinfo['DS'] of type string is incompatible with the type array|object expected by parameter $array of reset(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

534
    reset(/** @scrutinizer ignore-type */ $rrdinfo['DS']);
Loading history...
535
    foreach ($rrdinfo['DS'] as $k => $v) {
536
        if (strlen($k) > $l_max) {
537
            $l_max = strlen($k);
538
        }
539
540
        if ($has_min) {
541
            $graph[] = sprintf('DEF:%s_min=%s:%s:MIN', $k, $rrdinfo['filename'], $k);
542
        }
543
544
        if ($has_avg) {
545
            $graph[] = sprintf('DEF:%s_avg=%s:%s:AVERAGE', $k, $rrdinfo['filename'], $k);
546
        }
547
548
        if ($has_max) {
549
            $graph[] = sprintf('DEF:%s_max=%s:%s:MAX', $k, $rrdinfo['filename'], $k);
550
        }
551
    }
552
553
    if ($has_min && $has_max || $has_min && $has_avg || $has_avg && $has_max) {
554
        $n = 1;
555
        reset($rrdinfo['DS']);
556
        foreach ($rrdinfo['DS'] as $k => $v) {
557
            $graph[] = sprintf('LINE:%s_%s', $k, $has_min ? 'min' : 'avg');
558
            $graph[] = sprintf('CDEF:%s_var=%s_%s,%s_%s,-', $k, $k, $has_max ? 'max' : 'avg', $k, $has_min ? 'min' : 'avg');
559
            $graph[] = sprintf('AREA:%s_var#%s::STACK', $k, rrd_get_color($n++, false));
560
        }
561
    }
562
563
    reset($rrdinfo['DS']);
564
    $n = 1;
565
    foreach ($rrdinfo['DS'] as $k => $v) {
566
        $graph[] = sprintf('LINE1:%s_avg#%s:%s ', $k, rrd_get_color($n++, true), $k . substr('                  ', 0, ($l_max - strlen($k))));
567
        if (isset($opts['tinylegend']) && $opts['tinylegend']) {
568
            continue;
569
        }
570
571
        if ($has_avg) {
572
            $graph[] = sprintf('GPRINT:%s_avg:AVERAGE:%%5.1lf%%s', $k, $has_max || $has_min || $has_avg ? ',' : '\\l');
573
        }
574
575
        if ($has_min) {
576
            $graph[] = sprintf('GPRINT:%s_min:MIN:%%5.1lf%%s', $k, $has_max || $has_avg ? ',' : '\\l');
577
        }
578
579
        if ($has_max) {
580
            $graph[] = sprintf('GPRINT:%s_max:MAX:%%5.1lf%%s', $k, $has_avg ? ',' : '\\l');
581
        }
582
583
        if ($has_avg) {
584
            $graph[] = sprintf('GPRINT:%s_avg:LAST:%%5.1lf%%s\\l', $k);
585
        }
586
    }//end while
587
588
    // $rrd_cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', Config::get('rrd_width'), '-h', Config::get('rrd_height'), '-t', $rrdfile);
589
    $rrd_cmd = [
590
        RRDTOOL,
591
        'graph',
592
        '-',
593
        '-E',
594
        '-a',
595
        'PNG',
596
        '-w',
597
        Config::get('rrd_width'),
598
        '-h',
599
        Config::get('rrd_height'),
600
    ];
601
    if (Config::get('rrd_width') <= '300') {
602
        $small_opts = [
603
            '--font',
604
            'LEGEND:7:mono',
605
            '--font',
606
            'AXIS:6:mono',
607
            '--font-render-mode',
608
            'normal',
609
        ];
610
        $rrd_cmd = array_merge($rrd_cmd, $small_opts);
611
    }
612
613
    $rrd_cmd = array_merge($rrd_cmd, Config::get('rrd_opts_array'), $opts['rrd_opts'], $graph);
614
615
    $cmd = RRDTOOL;
616
    $count_rrd_cmd = count($rrd_cmd);
617
    for ($i = 1; $i < $count_rrd_cmd; $i++) {
618
        $cmd .= ' ' . escapeshellarg($rrd_cmd[$i]);
619
    }
620
621
    return $cmd;
622
}//end collectd_draw_rrd()
623
624
/**
625
 * Draw RRD file based on it's structure
626
 *
627
 * @param $timespan
628
 * @param $host
629
 * @param $plugin
630
 * @param $type
631
 * @param  null  $pinst
632
 * @param  null  $tinst
633
 * @return false|string Commandline to call RRDGraph in order to generate the final graph* @internal param $
634
 */
635
function collectd_draw_generic($timespan, $host, $plugin, $type, $pinst = null, $tinst = null)
636
{
637
    global $GraphDefs;
638
    $timespan_def = null;
639
    $timespans = Config::get('timespan');
640
    foreach ($timespans as &$ts) {
641
        if ($ts['name'] == $timespan) {
642
            $timespan_def = $ts;
643
        }
644
    }
645
646
    if (is_null($timespan_def)) {
647
        $timespan_def = reset($timespans);
648
    }
649
650
    if (! isset($GraphDefs[$type])) {
651
        return false;
652
    }
653
654
    $rrd_file = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, is_null($pinst) ? '' : '-', $pinst, $type, is_null($tinst) ? '' : '-', $tinst);
0 ignored issues
show
The condition is_null($pinst) is always true.
Loading history...
The condition is_null($tinst) is always true.
Loading history...
655
    // $rrd_cmd  = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', Config::get('rrd_width'), '-h', Config::get('rrd_height'), '-t', $rrd_file);
656
    $rrd_cmd = [
657
        RRDTOOL,
658
        'graph',
659
        '-',
660
        '-E',
661
        '-a',
662
        'PNG',
663
        '-w',
664
        Config::get('rrd_width'),
665
        '-h',
666
        Config::get('rrd_height'),
667
    ];
668
669
    if (Config::get('rrd_width') <= '300') {
670
        $small_opts = [
671
            '--font',
672
            'LEGEND:7:mono',
673
            '--font',
674
            'AXIS:6:mono',
675
            '--font-render-mode',
676
            'normal',
677
        ];
678
        $rrd_cmd = array_merge($rrd_cmd, $small_opts);
679
    }
680
681
    $rrd_cmd = array_merge($rrd_cmd, Config::get('rrd_opts_array'));
682
    $rrd_args = $GraphDefs[$type];
683
684
    foreach (Config::get('datadirs') as $datadir) {
685
        $file = $datadir . '/' . $rrd_file . '.rrd';
686
        if (! is_file($file)) {
687
            continue;
688
        }
689
690
        $file = str_replace(':', '\\:', $file);
691
        $rrd_args = str_replace('{file}', $file, $rrd_args);
692
693
        $rrdgraph = array_merge($rrd_cmd, $rrd_args);
694
        $cmd = RRDTOOL;
695
        $count_rrdgraph = count($rrdgraph);
696
        for ($i = 1; $i < $count_rrdgraph; $i++) {
697
            $cmd .= ' ' . escapeshellarg($rrdgraph[$i]);
698
        }
699
700
        return $cmd;
701
    }
702
703
    return false;
704
}//end collectd_draw_generic()
705
706
/**
707
 * Draw stack-graph for set of RRD files
708
 *
709
 * @param  array  $opts  Graph options like colors
710
 * @param  array  $sources  List of array(name, file, ds)
711
 * @return string Commandline to call RRDGraph in order to generate the final graph
712
 */
713
function collectd_draw_meta_stack(&$opts, &$sources)
714
{
715
    $timespan_def = null;
716
    $timespans = Config::get('timespan');
717
    if (! isset($opts['timespan'])) {
718
        $timespan_def = reset($timespans);
719
    } else {
720
        foreach ($timespans as &$ts) {
721
            if ($ts['name'] == $opts['timespan']) {
722
                $timespan_def = $ts;
723
            }
724
        }
725
    }
726
727
    if (! isset($opts['title'])) {
728
        $opts['title'] = 'Unknown title';
729
    }
730
731
    if (! isset($opts['rrd_opts'])) {
732
        $opts['rrd_opts'] = [];
733
    }
734
735
    if (! isset($opts['colors'])) {
736
        $opts['colors'] = [];
737
    }
738
739
    if (isset($opts['logarithmic']) && $opts['logarithmic']) {
740
        array_unshift($opts['rrd_opts'], '-o');
741
    }
742
743
    // $cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', Config::get('rrd_width'), '-h', Config::get('rrd_height'),
744
    // '-t', $opts['title']);
745
    $cmd = [
746
        RRDTOOL,
747
        'graph',
748
        '-',
749
        '-E',
750
        '-a',
751
        'PNG',
752
        '-w',
753
        Config::get('rrd_width'),
754
        '-h',
755
        Config::get('rrd_height'),
756
    ];
757
758
    if (Config::get('rrd_width') <= '300') {
759
        $small_opts = [
760
            '--font',
761
            'LEGEND:7:mono',
762
            '--font',
763
            'AXIS:6:mono',
764
            '--font-render-mode',
765
            'normal',
766
        ];
767
        $cmd = array_merge($cmd, $small_opts);
768
    }
769
770
    $cmd = array_merge($cmd, Config::get('rrd_opts_array'), $opts['rrd_opts']);
771
    $max_inst_name = 0;
772
773
    foreach ($sources as &$inst_data) {
774
        $inst_name = $inst_data['name'];
775
        $file = $inst_data['file'];
776
        $ds = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
777
778
        if (strlen($inst_name) > $max_inst_name) {
779
            $max_inst_name = strlen($inst_name);
780
        }
781
782
        if (! is_file($file)) {
783
            continue;
784
        }
785
786
        $cmd[] = 'DEF:' . $inst_name . '_min=' . $file . ':' . $ds . ':MIN';
787
        $cmd[] = 'DEF:' . $inst_name . '_avg=' . $file . ':' . $ds . ':AVERAGE';
788
        $cmd[] = 'DEF:' . $inst_name . '_max=' . $file . ':' . $ds . ':MAX';
789
        $cmd[] = 'CDEF:' . $inst_name . '_nnl=' . $inst_name . '_avg,UN,0,' . $inst_name . '_avg,IF';
790
    }
791
792
    $inst_data = end($sources);
793
    $inst_name = $inst_data['name'];
794
    $cmd[] = 'CDEF:' . $inst_name . '_stk=' . $inst_name . '_nnl';
795
796
    $inst_data1 = end($sources);
797
    while (($inst_data0 = prev($sources)) !== false) {
798
        $inst_name0 = $inst_data0['name'];
799
        $inst_name1 = $inst_data1['name'];
800
801
        $cmd[] = 'CDEF:' . $inst_name0 . '_stk=' . $inst_name0 . '_nnl,' . $inst_name1 . '_stk,+';
802
        $inst_data1 = $inst_data0;
803
    }
804
805
    foreach ($sources as &$inst_data) {
806
        $inst_name = $inst_data['name'];
807
        // $legend = sprintf('%s', $inst_name);
808
        $legend = $inst_name;
809
        while (strlen($legend) < $max_inst_name) {
810
            $legend .= ' ';
811
        }
812
813
        $number_format = isset($opts['number_format']) ? $opts['number_format'] : '%6.1lf';
814
815
        if (isset($opts['colors'][$inst_name])) {
816
            $line_color = new CollectdColor($opts['colors'][$inst_name]);
817
        } else {
818
            $line_color = new CollectdColor('random');
819
        }
820
821
        $area_color = new CollectdColor($line_color);
822
        $area_color->fade();
823
824
        $cmd[] = 'AREA:' . $inst_name . '_stk#' . $area_color->toString();
825
        $cmd[] = 'LINE1:' . $inst_name . '_stk#' . $line_color->toString() . ':' . $legend;
826
        if (! (isset($opts['tinylegend']) && $opts['tinylegend'])) {
827
            $cmd[] = 'GPRINT:' . $inst_name . '_avg:LAST:' . $number_format . '';
828
            $cmd[] = 'GPRINT:' . $inst_name . '_avg:AVERAGE:' . $number_format . '';
829
            $cmd[] = 'GPRINT:' . $inst_name . '_min:MIN:' . $number_format . '';
830
            $cmd[] = 'GPRINT:' . $inst_name . '_max:MAX:' . $number_format . '\\l';
831
        }
832
    }//end foreach
833
834
    $rrdcmd = RRDTOOL;
835
    $count_cmd = count($cmd);
836
    for ($i = 1; $i < $count_cmd; $i++) {
837
        $rrdcmd .= ' ' . escapeshellarg($cmd[$i]);
838
    }
839
840
    return $rrdcmd;
841
}//end collectd_draw_meta_stack()
842
843
/**
844
 * Draw stack-graph for set of RRD files
845
 *
846
 * @param  array  $opts  Graph options like colors
847
 * @param  array  $sources  List of array(name, file, ds)
848
 * @return string Commandline to call RRDGraph in order to generate the final graph
849
 */
850
function collectd_draw_meta_line(&$opts, &$sources)
851
{
852
    $timespan_def = null;
853
    $timespans = Config::get('timespan');
854
    if (! isset($opts['timespan'])) {
855
        $timespan_def = reset($timespans);
856
    } else {
857
        foreach ($timespans as &$ts) {
858
            if ($ts['name'] == $opts['timespan']) {
859
                $timespan_def = $ts;
860
            }
861
        }
862
    }
863
864
    if (! isset($opts['title'])) {
865
        $opts['title'] = 'Unknown title';
866
    }
867
868
    if (! isset($opts['rrd_opts'])) {
869
        $opts['rrd_opts'] = [];
870
    }
871
872
    if (! isset($opts['colors'])) {
873
        $opts['colors'] = [];
874
    }
875
876
    if (isset($opts['logarithmic']) && $opts['logarithmic']) {
877
        array_unshift($opts['rrd_opts'], '-o');
878
    }
879
880
    // $cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', Config::get('rrd_width'), '-h', Config::get('rrd_height'), '-t', $opts['title']);
881
    // $cmd = array_merge($cmd, Config::get('rrd_opts_array'), $opts['rrd_opts']);
882
    $cmd = [
883
        RRDTOOL,
884
        'graph',
885
        '-',
886
        '-E',
887
        '-a',
888
        'PNG',
889
        '-w',
890
        Config::get('rrd_width'),
891
        '-h',
892
        Config::get('rrd_height'),
893
    ];
894
895
    if (Config::get('rrd_width') <= '300') {
896
        $small_opts = [
897
            '--font',
898
            'LEGEND:7:mono',
899
            '--font',
900
            'AXIS:6:mono',
901
            '--font-render-mode',
902
            'normal',
903
        ];
904
        $cmd = array_merge($cmd, $small_opts);
905
    }
906
907
    $max_inst_name = 0;
908
909
    foreach ($sources as &$inst_data) {
910
        $inst_name = $inst_data['name'];
911
        $file = $inst_data['file'];
912
        $ds = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
913
914
        if (strlen($inst_name) > $max_inst_name) {
915
            $max_inst_name = strlen($inst_name);
916
        }
917
918
        if (! is_file($file)) {
919
            continue;
920
        }
921
922
        $cmd[] = 'DEF:' . $inst_name . '_min=' . $file . ':' . $ds . ':MIN';
923
        $cmd[] = 'DEF:' . $inst_name . '_avg=' . $file . ':' . $ds . ':AVERAGE';
924
        $cmd[] = 'DEF:' . $inst_name . '_max=' . $file . ':' . $ds . ':MAX';
925
    }
926
927
    foreach ($sources as &$inst_data) {
928
        $inst_name = $inst_data['name'];
929
        $legend = sprintf('%s', $inst_name);
930
        while (strlen($legend) < $max_inst_name) {
931
            $legend .= ' ';
932
        }
933
934
        $number_format = isset($opts['number_format']) ? $opts['number_format'] : '%6.1lf';
935
936
        if (isset($opts['colors'][$inst_name])) {
937
            $line_color = new CollectdColor($opts['colors'][$inst_name]);
938
        } else {
939
            $line_color = new CollectdColor('random');
940
        }
941
942
        $cmd[] = 'LINE1:' . $inst_name . '_avg#' . $line_color->toString() . ':' . $legend;
943
        if (! (isset($opts['tinylegend']) && $opts['tinylegend'])) {
944
            $cmd[] = 'GPRINT:' . $inst_name . '_min:MIN:' . $number_format . '';
945
            $cmd[] = 'GPRINT:' . $inst_name . '_avg:AVERAGE:' . $number_format . '';
946
            $cmd[] = 'GPRINT:' . $inst_name . '_max:MAX:' . $number_format . '';
947
            $cmd[] = 'GPRINT:' . $inst_name . '_avg:LAST:' . $number_format . '\\l';
948
        }
949
    }//end foreach
950
951
    $rrdcmd = RRDTOOL;
952
    $count_cmd = count($cmd);
953
    for ($i = 1; $i < $count_cmd; $i++) {
954
        $rrdcmd .= ' ' . escapeshellarg($cmd[$i]);
955
    }
956
957
    return $rrdcmd;
958
}//end collectd_draw_meta_line()
959