Completed
Pull Request — master (#2936)
by
unknown
04:53
created

html/includes/collectd/functions.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * Copyright (C) 2009  Bruno Prémont <bonbons AT linux-vserver.org>
5
 *
6
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; only version 2 of the License is applicable.
9
 *
10
 * This program is distributed in the hope that it will be useful, but WITHOUT
11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13
 * details.
14
 *
15
 * You should have received a copy of the GNU General Public License along with
16
 * this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18
 */
19
20
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])?)*$/');
21
define('REGEXP_PLUGIN', '/^[a-zA-Z0-9_.-]+$/');
22
23
/*
24
 * Read input variable from GET, POST or COOKIE taking
25
 * care of magic quotes
26
 * @name Name of value to return
27
 * @array User-input array ($_GET, $_POST or $_COOKIE)
28
 * @default Default value
29
 * @return $default if name in unknown in $array, otherwise
30
 *         input value with magic quotes stripped off
31
 */
32
function read_var($name, &$array, $default=null) {
33
    if (isset($array[$name])) {
34
        if (is_array($array[$name])) {
35
            if (get_magic_quotes_gpc()) {
36
                $ret = array();
37
                while (list($k, $v) = each($array[$name])) {
38
                    $ret[stripslashes($k)] = stripslashes($v);
39
                }
40
41
                return $ret;
42
            }
43
            else {
44
                return $array[$name];
45
            }
46
        }
47
        else if (is_string($array[$name]) && get_magic_quotes_gpc()) {
48
            return stripslashes($array[$name]);
49
        }
50
        else {
51
            return $array[$name];
52
        }
53
    }
54
    else {
55
        return $default;
56
    }
57
58
}//end read_var()
59
60
61
/*
62
 * Alphabetically compare host names, comparing label
63
 * from tld to node name
64
 */
65
function collectd_compare_host($a, $b) {
66
    $ea = explode('.', $a);
67
    $eb = explode('.', $b);
68
    $i  = (count($ea) - 1);
69
    $j  = (count($eb) - 1);
70
    while ($i >= 0 && $j >= 0) {
71
        if (($r = strcmp($ea[$i--], $eb[$j--])) != 0) {
72
            return $r;
73
        }
74
    }
75
76
    return 0;
77
78
}//end collectd_compare_host()
79
80
81
/**
82
 * Fetch list of hosts found in collectd's datadirs.
83
 * @return Sorted list of hosts (sorted by label from rigth to left)
84
 */
85
function collectd_list_hosts() {
86
    global $config;
87
88
    $hosts = array();
89
    foreach($config['datadirs'] as $datadir) {
90
        if ($d = @opendir($datadir)) {
91
            while (($dent = readdir($d)) !== false) {
92
                if ($dent != '.' && $dent != '..' && is_dir($datadir.'/'.$dent) && preg_match(REGEXP_HOST, $dent)) {
93
                    $hosts[] = $dent;
94
                }
95
            }
96
            closedir($d);
97
        }
98
        else {
99
            error_log('Failed to open datadir: '.$datadir);
100
        }
101
    }
102
    $hosts = array_unique($hosts);
103
    usort($hosts, 'collectd_compare_host');
104
    return $hosts;
105
}
106
107
108
/**
109
 * Fetch list of plugins found in collectd's datadirs for given host.
110
 * @arg_host Name of host for which to return plugins
111
 * @return Sorted list of plugins (sorted alphabetically)
112
 */
113
function collectd_list_plugins($arg_host) {
114
    global $config;
115
116
    $plugins = array();
117
    foreach ($config['datadirs'] as $datadir) {
118
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir.'/'.$arg_host))) {
119
            while (($dent = readdir($d)) !== false) {
120
                if ($dent != '.' && $dent != '..' && is_dir($datadir.'/'.$arg_host.'/'.$dent)) {
121 View Code Duplication
                    if ($i = strpos($dent, '-')) {
122
                        $plugins[] = substr($dent, 0, $i);
123
                    }
124
                    else {
125
                        $plugins[] = $dent;
126
                    }
127
                }
128
            }
129
130
            closedir($d);
131
        }
132
    }
133
134
    $plugins = array_unique($plugins);
135
    sort($plugins);
136
    return $plugins;
137
138
}//end collectd_list_plugins()
139
140
141
/**
142
 * Fetch list of plugin instances found in collectd's datadirs for given host+plugin
143
 * @arg_host Name of host
144
 * @arg_plugin Name of plugin
145
 * @return Sorted list of plugin instances (sorted alphabetically)
146
 */
147
function collectd_list_pinsts($arg_host, $arg_plugin) {
148
    global $config;
149
150
    $pinsts = array();
151
    foreach ($config['datadirs'] as $datadir) {
152
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = opendir($datadir.'/'.$arg_host))) {
153
            while (($dent = readdir($d)) !== false) {
154
                if ($dent != '.' && $dent != '..' && is_dir($datadir.'/'.$arg_host.'/'.$dent)) {
155 View Code Duplication
                    if ($i = strpos($dent, '-')) {
156
                        $plugin = substr($dent, 0, $i);
157
                        $pinst  = substr($dent, ($i + 1));
158
                    }
159
                    else {
160
                        $plugin = $dent;
161
                        $pinst  = '';
162
                    }
163
164
                    if ($plugin == $arg_plugin) {
165
                        $pinsts[] = $pinst;
166
                    }
167
                }
168
            }
169
170
            closedir($d);
171
        }
172
    }//end foreach
173
174
    $pinsts = array_unique($pinsts);
175
    sort($pinsts);
176
    return $pinsts;
177
178
}//end collectd_list_pinsts()
179
180
181
/**
182
 * Fetch list of types found in collectd's datadirs for given host+plugin+instance
183
 * @arg_host Name of host
184
 * @arg_plugin Name of plugin
185
 * @arg_pinst Plugin instance
186
 * @return Sorted list of types (sorted alphabetically)
187
 */
188
function collectd_list_types($arg_host, $arg_plugin, $arg_pinst) {
189
    global $config;
190
191
    $types     = array();
192
    $my_plugin = $arg_plugin.(strlen($arg_pinst) ? '-'.$arg_pinst : '');
193
    if (!preg_match(REGEXP_PLUGIN, $my_plugin)) {
194
        return $types;
195
    }
196
197
    foreach ($config['datadirs'] as $datadir) {
198
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir.'/'.$arg_host.'/'.$my_plugin))) {
199
            while (($dent = readdir($d)) !== false) {
200
                if ($dent != '.' && $dent != '..' && is_file($datadir.'/'.$arg_host.'/'.$my_plugin.'/'.$dent) && substr($dent, (strlen($dent) - 4)) == '.rrd') {
201
                    $dent = substr($dent, 0, (strlen($dent) - 4));
202 View Code Duplication
                    if ($i = strpos($dent, '-')) {
203
                        $types[] = substr($dent, 0, $i);
204
                    }
205
                    else {
206
                        $types[] = $dent;
207
                    }
208
                }
209
            }
210
211
            closedir($d);
212
        }
213
    }
214
215
    $types = array_unique($types);
216
    sort($types);
217
    return $types;
218
219
}//end collectd_list_types()
220
221
222
/**
223
 * Fetch list of type instances found in collectd's datadirs for given host+plugin+instance+type
224
 * @arg_host Name of host
225
 * @arg_plugin Name of plugin
226
 * @arg_pinst Plugin instance
227
 * @arg_type Type
228
 * @return Sorted list of type instances (sorted alphabetically)
229
 */
230
function collectd_list_tinsts($arg_host, $arg_plugin, $arg_pinst, $arg_type) {
231
    global $config;
232
233
    $tinsts    = array();
234
    $my_plugin = $arg_plugin.(strlen($arg_pinst) ? '-'.$arg_pinst : '');
235
    if (!preg_match(REGEXP_PLUGIN, $my_plugin)) {
236
        return $types;
237
    }
238
239
    foreach ($config['datadirs'] as $datadir) {
240
        if (preg_match(REGEXP_HOST, $arg_host) && ($d = @opendir($datadir.'/'.$arg_host.'/'.$my_plugin))) {
241
            while (($dent = readdir($d)) !== false) {
242
                if ($dent != '.' && $dent != '..' && is_file($datadir.'/'.$arg_host.'/'.$my_plugin.'/'.$dent) && substr($dent, (strlen($dent) - 4)) == '.rrd') {
243
                    $dent = substr($dent, 0, (strlen($dent) - 4));
244 View Code Duplication
                    if ($i = strpos($dent, '-')) {
245
                        $type  = substr($dent, 0, $i);
246
                        $tinst = substr($dent, ($i + 1));
247
                    }
248
                    else {
249
                        $type  = $dent;
250
                        $tinst = '';
251
                    }
252
253
                    if ($type == $arg_type) {
254
                        $tinsts[] = $tinst;
255
                    }
256
                }
257
            }
258
259
            closedir($d);
260
        }
261
    }//end foreach
262
263
    $tinsts = array_unique($tinsts);
264
    sort($tinsts);
265
    return $tinsts;
266
267
}//end collectd_list_tinsts()
268
269
270
/**
271
 * Parse symlinks in order to get an identifier that collectd understands
272
 * (e.g. virtualisation is collected on host for individual VMs and can be
273
 *  symlinked to the VM's hostname, support FLUSH for these by flushing
274
 *  on the host-identifier instead of VM-identifier)
275
 * @host Host name
276
 * @plugin Plugin name
277
 * @pinst Plugin instance
278
 * @type Type name
279
 * @tinst Type instance
280
 * @return Identifier that collectd's FLUSH command understands
281
 */
282
function collectd_identifier($host, $plugin, $pinst, $type, $tinst) {
283
    global $config;
284
    $rrd_realpath    = null;
285
    $orig_identifier = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, strlen($pinst) ? '-' : '', $pinst, $type, strlen($tinst) ? '-' : '', $tinst);
286
    $identifier      = null;
287
    foreach ($config['datadirs'] as $datadir) {
288
        if (is_file($datadir.'/'.$orig_identifier.'.rrd')) {
289
            $rrd_realpath = realpath($datadir.'/'.$orig_identifier.'.rrd');
290
            break;
291
        }
292
    }
293
294
    if ($rrd_realpath) {
295
        $identifier   = basename($rrd_realpath);
296
        $identifier   = substr($identifier, 0, (strlen($identifier) - 4));
297
        $rrd_realpath = dirname($rrd_realpath);
298
        $identifier   = basename($rrd_realpath).'/'.$identifier;
299
        $rrd_realpath = dirname($rrd_realpath);
300
        $identifier   = basename($rrd_realpath).'/'.$identifier;
301
    }
302
303
    if (is_null($identifier)) {
304
        return $orig_identifier;
305
    }
306
    else {
307
        return $identifier;
308
    }
309
310
}//end collectd_identifier()
311
312
313
/**
314
 * Tell collectd that it should FLUSH all data it has regarding the
315
 * graph we are about to generate.
316
 * @host Host name
317
 * @plugin Plugin name
318
 * @pinst Plugin instance
319
 * @type Type name
320
 * @tinst Type instance
321
 */
322
function collectd_flush($identifier) {
323
    global $config;
324
325
    if (!$config['collectd_sock']) {
326
        return false;
327
    }
328
329
    if (is_null($identifier) || (is_array($identifier) && count($identifier) == 0) || !(is_string($identifier) || is_array($identifier))) {
330
        return false;
331
    }
332
333
    $u_errno  = 0;
334
    $u_errmsg = '';
335
    if ($socket = @fsockopen($config['collectd_sock'], 0, $u_errno, $u_errmsg)) {
336
        $cmd = 'FLUSH plugin=rrdtool';
337
        if (is_array($identifier)) {
338
            foreach ($identifier as $val) {
339
                $cmd .= sprintf(' identifier="%s"', $val);
340
            }
341
        }
342
        else {
343
            $cmd .= sprintf(' identifier="%s"', $identifier);
344
        }
345
346
        $cmd .= "\n";
347
348
        $r = fwrite($socket, $cmd, strlen($cmd));
349
        if ($r === false || $r != strlen($cmd)) {
350
            error_log(sprintf('graph.php: Failed to write whole command to unix-socket: %d out of %d written', $r === false ? (-1) : $r, strlen($cmd)));
351
        }
352
353
        $resp = fgets($socket);
354
        if ($resp === false) {
355
            error_log(sprintf('graph.php: Failed to read response from collectd for command: %s', trim($cmd)));
356
        }
357
358
        $n = (int) $resp;
359
        while ($n-- > 0) {
360
            fgets($socket);
361
        }
362
363
        fclose($socket);
364
    } //end if
365
    else {
366
        error_log(sprintf('graph.php: Failed to open unix-socket to collectd: %d: %s', $u_errno, $u_errmsg));
367
    }
368
369
}//end collectd_flush()
370
371
372
class CollectdColor {
373
374
    private $r = 0;
375
376
    private $g = 0;
377
378
    private $b = 0;
379
380
381
    function __construct($value=null) {
382
        if (is_null($value)) {
383
        }
384
        else if (is_array($value)) {
385 View Code Duplication
            if (isset($value['r'])) {
386
                $this->r = $value['r'] > 0 ? ($value['r'] > 1 ? 1 : $value['r']) : 0;
387
            }
388
389 View Code Duplication
            if (isset($value['g'])) {
390
                $this->g = $value['g'] > 0 ? ($value['g'] > 1 ? 1 : $value['g']) : 0;
391
            }
392
393 View Code Duplication
            if (isset($value['b'])) {
394
                $this->b = $value['b'] > 0 ? ($value['b'] > 1 ? 1 : $value['b']) : 0;
395
            }
396
        }
397
        else if (is_string($value)) {
398
            $matches = array();
399
            if ($value == 'random') {
400
                $this->randomize();
401
            }
402
            else if (preg_match('/([0-9A-Fa-f][0-9A-Fa-f])([0-9A-Fa-f][0-9A-Fa-f])([0-9A-Fa-f][0-9A-Fa-f])/', $value, $matches)) {
403
                $this->r = (('0x'.$matches[1]) / 255.0);
404
                $this->g = (('0x'.$matches[2]) / 255.0);
405
                $this->b = (('0x'.$matches[3]) / 255.0);
406
            }
407
        }
408
        else if (is_a($value, 'CollectdColor')) {
409
            $this->r = $value->r;
410
            $this->g = $value->g;
411
            $this->b = $value->b;
412
        }//end if
413
414
    }//end __construct()
415
416
417
    function randomize() {
418
        $this->r = (rand(0, 255) / 255.0);
419
        $this->g = (rand(0, 255) / 255.0);
420
        $this->b = 0.0;
0 ignored issues
show
Documentation Bug introduced by
The property $b was declared of type integer, but 0.0 is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
421
        $min     = 0.0;
422
        $max     = 1.0;
423
424
        if (($this->r + $this->g) < 1.0) {
425
            $min = (1.0 - ($this->r + $this->g));
426
        }
427
        else {
428
            $max = (2.0 - ($this->r + $this->g));
429
        }
430
431
        $this->b = ($min + ((rand(0, 255) / 255.0) * ($max - $min)));
432
433
    }//end randomize()
434
435
436
    function fade($bkgnd=null, $alpha=0.25) {
437
        if (is_null($bkgnd) || !is_a($bkgnd, 'CollectdColor')) {
438
            $bg_r = 1.0;
439
            $bg_g = 1.0;
440
            $bg_b = 1.0;
441
        }
442
        else {
443
            $bg_r = $bkgnd->r;
444
            $bg_g = $bkgnd->g;
445
            $bg_b = $bkgnd->b;
446
        }
447
448
        $this->r = ($alpha * $this->r + ((1.0 - $alpha) * $bg_r));
449
        $this->g = ($alpha * $this->g + ((1.0 - $alpha) * $bg_g));
450
        $this->b = ($alpha * $this->b + ((1.0 - $alpha) * $bg_b));
451
452
    }//end fade()
453
454
455
    function as_array() {
456
        return array(
457
            'r' => $this->r,
458
            'g' => $this->g,
459
            'b' => $this->b,
460
        );
461
462
    }//end as_array()
463
464
465
    function as_string() {
466
        $r = (int) ($this->r * 255);
467
        $g = (int) ($this->g * 255);
468
        $b = (int) ($this->b * 255);
469
        return sprintf('%02x%02x%02x', $r > 255 ? 255 : $r, $g > 255 ? 255 : $g, $b > 255 ? 255 : $b);
470
471
    }//end as_string()
472
473
474
}//end class
475
476
477
/**
478
 * Helper function to strip quotes from RRD output
479
 * @str RRD-Info generated string
480
 * @return String with one surrounding pair of quotes stripped
481
 */
482
function rrd_strip_quotes($str) {
483
    if ($str[0] == '"' && $str[(strlen($str) - 1)] == '"') {
484
        return substr($str, 1, (strlen($str) - 2));
485
    }
486
    else {
487
        return $str;
488
    }
489
490
}//end rrd_strip_quotes()
491
492
493
/**
494
 * Determine useful information about RRD file
495
 * @file Name of RRD file to analyse
496
 * @return Array describing the RRD file
497
 */
498
function rrd_info($file) {
499
    $info = array('filename' => $file);
500
501
    $rrd = popen(RRDTOOL.' info '.escapeshellarg($file), 'r');
502
    if ($rrd) {
503
        while (($s = fgets($rrd)) !== false) {
504
            $p = strpos($s, '=');
505
            if ($p === false) {
506
                continue;
507
            }
508
509
            $key   = trim(substr($s, 0, $p));
510
            $value = trim(substr($s, ($p + 1)));
511
            if (strncmp($key, 'ds[', 3) == 0) {
512
                // DS definition
513
                $p  = strpos($key, ']');
514
                $ds = substr($key, 3, ($p - 3));
515
                if (!isset($info['DS'])) {
516
                    $info['DS'] = array();
517
                }
518
519
                $ds_key = substr($key, ($p + 2));
520
521 View Code Duplication
                if (strpos($ds_key, '[') === false) {
522
                    if (!isset($info['DS']["$ds"])) {
523
                        $info['DS']["$ds"] = array();
524
                    }
525
526
                    $info['DS']["$ds"]["$ds_key"] = rrd_strip_quotes($value);
527
                }
528
            }
529
            else if (strncmp($key, 'rra[', 4) == 0) {
530
                // RRD definition
531
                $p   = strpos($key, ']');
532
                $rra = substr($key, 4, ($p - 4));
533
                if (!isset($info['RRA'])) {
534
                    $info['RRA'] = array();
535
                }
536
537
                $rra_key = substr($key, ($p + 2));
538
539 View Code Duplication
                if (strpos($rra_key, '[') === false) {
540
                    if (!isset($info['RRA']["$rra"])) {
541
                        $info['RRA']["$rra"] = array();
542
                    }
543
544
                    $info['RRA']["$rra"]["$rra_key"] = rrd_strip_quotes($value);
545
                }
546
            }
547
            else if (strpos($key, '[') === false) {
548
                $info[$key] = rrd_strip_quotes($value);
549
            }//end if
550
        }//end while
551
552
        pclose($rrd);
553
    }//end if
554
555
    return $info;
556
557
}//end rrd_info()
558
559
560
function rrd_get_color($code, $line=true) {
561
    global $config;
562
    $name = ($line ? 'f_' : 'h_').$code;
563
    if (!isset($config['rrd_colors'][$name])) {
564
        $c_f = new CollectdColor('random');
565
        $c_h = new CollectdColor($c_f);
566
        $c_h->fade();
567
        $config['rrd_colors']['f_'.$code] = $c_f->as_string();
568
        $config['rrd_colors']['h_'.$code] = $c_h->as_string();
569
    }
570
571
    return $config['rrd_colors'][$name];
572
573
}//end rrd_get_color()
574
575
576
/**
577
 * Draw RRD file based on it's structure
578
 *
579
 * @host
580
 * @plugin
581
 * @pinst
582
 * @type
583
 * @tinst
584
 * @opts
585
 * @return Commandline to call RRDGraph in order to generate the final graph
586
 */
587
function collectd_draw_rrd($host, $plugin, $pinst=null, $type, $tinst=null, $opts=array()) {
588
    global $config;
589
    $timespan_def = null;
590 View Code Duplication
    if (!isset($opts['timespan'])) {
591
        $timespan_def = reset($config['timespan']);
592
    }
593
    else {
594
        foreach ($config['timespan'] as &$ts) {
595
            if ($ts['name'] == $opts['timespan']) {
596
                $timespan_def = $ts;
597
            }
598
        }
599
    }
600
601
    if (!isset($opts['rrd_opts'])) {
602
        $opts['rrd_opts'] = array();
603
    }
604
605
    if (isset($opts['logarithmic']) && $opts['logarithmic']) {
606
        array_unshift($opts['rrd_opts'], '-o');
607
    }
608
609
    $rrdinfo = null;
610
    $rrdfile = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, is_null($pinst) ? '' : '-', $pinst, $type, is_null($tinst) ? '' : '-', $tinst);
611
    foreach ($config['datadirs'] as $datadir) {
612
        if (is_file($datadir.'/'.$rrdfile.'.rrd')) {
613
            $rrdinfo = rrd_info($datadir.'/'.$rrdfile.'.rrd');
614
            if (isset($rrdinfo['RRA']) && is_array($rrdinfo['RRA'])) {
615
                break;
616
            }
617
            else {
618
                $rrdinfo = null;
619
            }
620
        }
621
    }
622
623
    if (is_null($rrdinfo)) {
624
        return false;
625
    }
626
627
    $graph   = array();
628
    $has_avg = false;
629
    $has_max = false;
630
    $has_min = false;
631
    reset($rrdinfo['RRA']);
632
    $l_max = 0;
633
    while (list($k, $v) = each($rrdinfo['RRA'])) {
634
        if ($v['cf'] == 'MAX') {
635
            $has_max = true;
636
        }
637
        else if ($v['cf'] == 'AVERAGE') {
638
            $has_avg = true;
639
        }
640
        else if ($v['cf'] == 'MIN') {
641
            $has_min = true;
642
        }
643
    }
644
645
    // Build legend. This may not work for all RRDs, i don't know :)
646
    if ($has_avg) {
647
        $graph[] = 'COMMENT:           Last';
648
    }
649
650
    if ($has_min) {
651
        $graph[] = 'COMMENT:   Min';
652
    }
653
654
    if ($has_max) {
655
        $graph[] = 'COMMENT:   Max';
656
    }
657
658
    if ($has_avg) {
659
        $graph[] = "COMMENT:   Avg\\n";
660
    }
661
662
    reset($rrdinfo['DS']);
663
    while (list($k, $v) = each($rrdinfo['DS'])) {
664
        if (strlen($k) > $l_max) {
665
            $l_max = strlen($k);
666
        }
667
668
        if ($has_min) {
669
            $graph[] = sprintf('DEF:%s_min=%s:%s:MIN', $k, $rrdinfo['filename'], $k);
670
        }
671
672
        if ($has_avg) {
673
            $graph[] = sprintf('DEF:%s_avg=%s:%s:AVERAGE', $k, $rrdinfo['filename'], $k);
674
        }
675
676
        if ($has_max) {
677
            $graph[] = sprintf('DEF:%s_max=%s:%s:MAX', $k, $rrdinfo['filename'], $k);
678
        }
679
    }
680
681
    if ($has_min && $has_max || $has_min && $has_avg || $has_avg && $has_max) {
682
        $n = 1;
683
        reset($rrdinfo['DS']);
684
        while (list($k, $v) = each($rrdinfo['DS'])) {
685
            $graph[] = sprintf('LINE:%s_%s', $k, $has_min ? 'min' : 'avg');
686
            $graph[] = sprintf('CDEF:%s_var=%s_%s,%s_%s,-', $k, $k, $has_max ? 'max' : 'avg', $k, $has_min ? 'min' : 'avg');
687
            $graph[] = sprintf('AREA:%s_var#%s::STACK', $k, rrd_get_color($n++, false));
688
        }
689
    }
690
691
    reset($rrdinfo['DS']);
692
    $n = 1;
693
    while (list($k, $v) = each($rrdinfo['DS'])) {
694
        $graph[] = sprintf('LINE1:%s_avg#%s:%s ', $k, rrd_get_color($n++, true), $k.substr('                  ', 0, ($l_max - strlen($k))));
695
        if (isset($opts['tinylegend']) && $opts['tinylegend']) {
696
            continue;
697
        }
698
699
        if ($has_avg) {
700
            $graph[] = sprintf('GPRINT:%s_avg:AVERAGE:%%5.1lf%%s', $k, $has_max || $has_min || $has_avg ? ',' : '\\l');
701
        }
702
703
        if ($has_min) {
704
            $graph[] = sprintf('GPRINT:%s_min:MIN:%%5.1lf%%s', $k, $has_max || $has_avg ? ',' : '\\l');
705
        }
706
707
        if ($has_max) {
708
            $graph[] = sprintf('GPRINT:%s_max:MAX:%%5.1lf%%s', $k, $has_avg ? ',' : '\\l');
709
        }
710
711
        if ($has_avg) {
712
            $graph[] = sprintf('GPRINT:%s_avg:LAST:%%5.1lf%%s\\l', $k);
713
        }
714
    }//end while
715
716
    // $rrd_cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'], '-t', $rrdfile);
717
    $rrd_cmd = array(
718
        RRDTOOL,
719
        'graph',
720
        '-',
721
        '-E',
722
        '-a',
723
        'PNG',
724
        '-w',
725
        $config['rrd_width'],
726
        '-h',
727
        $config['rrd_height'],
728
    );
729 View Code Duplication
    if ($config['rrd_width'] <= '300') {
730
        $small_opts = array(
731
            '--font',
732
            'LEGEND:7:mono',
733
            '--font',
734
            'AXIS:6:mono',
735
            '--font-render-mode',
736
            'normal',
737
        );
738
        $rrd_cmd    = array_merge($rrd_cmd, $small_opts);
739
    }
740
741
    $rrd_cmd = array_merge($rrd_cmd, $config['rrd_opts_array'], $opts['rrd_opts'], $graph);
742
743
    $cmd               = RRDTOOL;
744
    $count_rrd_cmd = count($rrd_cmd);
745
    for ($i = 1; $i < $count_rrd_cmd; $i++) {
746
        $cmd .= ' '.escapeshellarg($rrd_cmd[$i]);
747
    }
748
749
    return $cmd;
750
751
}//end collectd_draw_rrd()
752
753
754
/**
755
 * Draw RRD file based on it's structure
756
 *
757
 * @timespan
758
 * @host
759
 * @plugin
760
 * @pinst
761
 * @type
762
 * @tinst
763
 * @opts
764
 * @return   Commandline to call RRDGraph in order to generate the final graph
765
 */
766
function collectd_draw_generic($timespan, $host, $plugin, $pinst=null, $type, $tinst=null) {
767
    global $config, $GraphDefs;
768
    $timespan_def = null;
769
    foreach ($config['timespan'] as &$ts) {
770
        if ($ts['name'] == $timespan) {
771
            $timespan_def = $ts;
772
        }
773
    }
774
775
    if (is_null($timespan_def)) {
776
        $timespan_def = reset($config['timespan']);
777
    }
778
779
    if (!isset($GraphDefs[$type])) {
780
        return false;
781
    }
782
783
    $rrd_file = sprintf('%s/%s%s%s/%s%s%s', $host, $plugin, is_null($pinst) ? '' : '-', $pinst, $type, is_null($tinst) ? '' : '-', $tinst);
784
    // $rrd_cmd  = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'], '-t', $rrd_file);
785
    $rrd_cmd = array(
786
        RRDTOOL,
787
        'graph',
788
        '-',
789
        '-E',
790
        '-a',
791
        'PNG',
792
        '-w',
793
        $config['rrd_width'],
794
        '-h',
795
        $config['rrd_height'],
796
    );
797
798 View Code Duplication
    if ($config['rrd_width'] <= '300') {
799
        $small_opts = array(
800
            '--font',
801
            'LEGEND:7:mono',
802
            '--font',
803
            'AXIS:6:mono',
804
            '--font-render-mode',
805
            'normal',
806
        );
807
        $rrd_cmd    = array_merge($rrd_cmd, $small_opts);
808
    }
809
810
    $rrd_cmd  = array_merge($rrd_cmd, $config['rrd_opts_array']);
811
    $rrd_args = $GraphDefs[$type];
812
813
    foreach ($config['datadirs'] as $datadir) {
814
        $file = $datadir.'/'.$rrd_file.'.rrd';
815
        if (!is_file($file)) {
816
            continue;
817
        }
818
819
        $file     = str_replace(':', '\\:', $file);
820
        $rrd_args = str_replace('{file}', $file, $rrd_args);
821
822
        $rrdgraph           = array_merge($rrd_cmd, $rrd_args);
823
        $cmd                = RRDTOOL;
824
        $count_rrdgraph = count($rrdgraph);
825
        for ($i = 1; $i < $count_rrdgraph; $i++) {
826
            $cmd .= ' '.escapeshellarg($rrdgraph[$i]);
827
        }
828
829
        return $cmd;
830
    }
831
832
    return false;
833
834
}//end collectd_draw_generic()
835
836
837
/**
838
 * Draw stack-graph for set of RRD files
839
 * @opts Graph options like colors
840
 * @sources List of array(name, file, ds)
841
 * @return Commandline to call RRDGraph in order to generate the final graph
842
 */
843
function collectd_draw_meta_stack(&$opts, &$sources) {
844
    global $config;
845
    $timespan_def = null;
846 View Code Duplication
    if (!isset($opts['timespan'])) {
847
        $timespan_def = reset($config['timespan']);
848
    }
849
    else {
850
        foreach ($config['timespan'] as &$ts) {
851
            if ($ts['name'] == $opts['timespan']) {
852
                $timespan_def = $ts;
853
            }
854
        }
855
    }
856
857
    if (!isset($opts['title'])) {
858
        $opts['title'] = 'Unknown title';
859
    }
860
861
    if (!isset($opts['rrd_opts'])) {
862
        $opts['rrd_opts'] = array();
863
    }
864
865
    if (!isset($opts['colors'])) {
866
        $opts['colors'] = array();
867
    }
868
869
    if (isset($opts['logarithmic']) && $opts['logarithmic']) {
870
        array_unshift($opts['rrd_opts'], '-o');
871
    }
872
873
    // $cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'],
874
    // '-t', $opts['title']);
875
    $cmd = array(
876
        RRDTOOL,
877
        'graph',
878
        '-',
879
        '-E',
880
        '-a',
881
        'PNG',
882
        '-w',
883
        $config['rrd_width'],
884
        '-h',
885
        $config['rrd_height'],
886
    );
887
888 View Code Duplication
    if ($config['rrd_width'] <= '300') {
889
        $small_opts = array(
890
            '--font',
891
            'LEGEND:7:mono',
892
            '--font',
893
            'AXIS:6:mono',
894
            '--font-render-mode',
895
            'normal',
896
        );
897
        $cmd        = array_merge($cmd, $small_opts);
898
    }
899
900
    $cmd           = array_merge($cmd, $config['rrd_opts_array'], $opts['rrd_opts']);
901
    $max_inst_name = 0;
902
903
    foreach ($sources as &$inst_data) {
904
        $inst_name = $inst_data['name'];
905
        $file      = $inst_data['file'];
906
        $ds        = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
907
908
        if (strlen($inst_name) > $max_inst_name) {
909
            $max_inst_name = strlen($inst_name);
910
        }
911
912
        if (!is_file($file)) {
913
            continue;
914
        }
915
916
        $cmd[] = 'DEF:'.$inst_name.'_min='.$file.':'.$ds.':MIN';
917
        $cmd[] = 'DEF:'.$inst_name.'_avg='.$file.':'.$ds.':AVERAGE';
918
        $cmd[] = 'DEF:'.$inst_name.'_max='.$file.':'.$ds.':MAX';
919
        $cmd[] = 'CDEF:'.$inst_name.'_nnl='.$inst_name.'_avg,UN,0,'.$inst_name.'_avg,IF';
920
    }
921
922
    $inst_data = end($sources);
923
    $inst_name = $inst_data['name'];
924
    $cmd[]     = 'CDEF:'.$inst_name.'_stk='.$inst_name.'_nnl';
925
926
    $inst_data1 = end($sources);
927
    while (($inst_data0 = prev($sources)) !== false) {
928
        $inst_name0 = $inst_data0['name'];
929
        $inst_name1 = $inst_data1['name'];
930
931
        $cmd[]      = 'CDEF:'.$inst_name0.'_stk='.$inst_name0.'_nnl,'.$inst_name1.'_stk,+';
932
        $inst_data1 = $inst_data0;
933
    }
934
935
    foreach ($sources as &$inst_data) {
936
        $inst_name = $inst_data['name'];
937
        // $legend = sprintf('%s', $inst_name);
938
        $legend = $inst_name;
939
        while (strlen($legend) < $max_inst_name) {
940
            $legend .= ' ';
941
        }
942
943
        $number_format = isset($opts['number_format']) ? $opts['number_format'] : '%6.1lf';
944
945 View Code Duplication
        if (isset($opts['colors'][$inst_name])) {
946
            $line_color = new CollectdColor($opts['colors'][$inst_name]);
947
        }
948
        else {
949
            $line_color = new CollectdColor('random');
950
        }
951
952
        $area_color = new CollectdColor($line_color);
953
        $area_color->fade();
954
955
        $cmd[] = 'AREA:'.$inst_name.'_stk#'.$area_color->as_string();
956
        $cmd[] = 'LINE1:'.$inst_name.'_stk#'.$line_color->as_string().':'.$legend;
957 View Code Duplication
        if (!(isset($opts['tinylegend']) && $opts['tinylegend'])) {
958
            $cmd[]             = 'GPRINT:'.$inst_name.'_avg:LAST:'.$number_format.'';
959
            $cmd[] = 'GPRINT:'.$inst_name.'_avg:AVERAGE:'.$number_format.'';
960
            $cmd[]             = 'GPRINT:'.$inst_name.'_min:MIN:'.$number_format.'';
961
            $cmd[]             = 'GPRINT:'.$inst_name.'_max:MAX:'.$number_format.'\\l';
962
        }
963
    }//end foreach
964
965
    $rrdcmd        = RRDTOOL;
966
    $count_cmd = count($cmd);
967 View Code Duplication
    for ($i = 1; $i < $count_cmd; $i++) {
968
        $rrdcmd .= ' '.escapeshellarg($cmd[$i]);
969
    }
970
971
    return $rrdcmd;
972
973
}//end collectd_draw_meta_stack()
974
975
976
/**
977
 * Draw stack-graph for set of RRD files
978
 * @opts Graph options like colors
979
 * @sources List of array(name, file, ds)
980
 * @return Commandline to call RRDGraph in order to generate the final graph
981
 */
982
function collectd_draw_meta_line(&$opts, &$sources) {
983
    global $config;
984
    $timespan_def = null;
985 View Code Duplication
    if (!isset($opts['timespan'])) {
986
        $timespan_def = reset($config['timespan']);
987
    }
988
    else {
989
        foreach ($config['timespan'] as &$ts) {
990
            if ($ts['name'] == $opts['timespan']) {
991
                $timespan_def = $ts;
992
            }
993
        }
994
    }
995
996
    if (!isset($opts['title'])) {
997
        $opts['title'] = 'Unknown title';
998
    }
999
1000
    if (!isset($opts['rrd_opts'])) {
1001
        $opts['rrd_opts'] = array();
1002
    }
1003
1004
    if (!isset($opts['colors'])) {
1005
        $opts['colors'] = array();
1006
    }
1007
1008
    if (isset($opts['logarithmic']) && $opts['logarithmic']) {
1009
        array_unshift($opts['rrd_opts'], '-o');
1010
    }
1011
1012
    // $cmd = array(RRDTOOL, 'graph', '-', '-E', '-a', 'PNG', '-w', $config['rrd_width'], '-h', $config['rrd_height'], '-t', $opts['title']);
1013
    // $cmd = array_merge($cmd, $config['rrd_opts_array'], $opts['rrd_opts']);
1014
    $cmd = array(
1015
        RRDTOOL,
1016
        'graph',
1017
        '-',
1018
        '-E',
1019
        '-a',
1020
        'PNG',
1021
        '-w',
1022
        $config['rrd_width'],
1023
        '-h',
1024
        $config['rrd_height'],
1025
    );
1026
1027 View Code Duplication
    if ($config['rrd_width'] <= '300') {
1028
        $small_opts = array(
1029
            '--font',
1030
            'LEGEND:7:mono',
1031
            '--font',
1032
            'AXIS:6:mono',
1033
            '--font-render-mode',
1034
            'normal',
1035
        );
1036
        $cmd        = array_merge($cmd, $small_opts);
1037
    }
1038
1039
    $max_inst_name = 0;
1040
1041
    foreach ($sources as &$inst_data) {
1042
        $inst_name = $inst_data['name'];
1043
        $file      = $inst_data['file'];
1044
        $ds        = isset($inst_data['ds']) ? $inst_data['ds'] : 'value';
1045
1046
        if (strlen($inst_name) > $max_inst_name) {
1047
            $max_inst_name = strlen($inst_name);
1048
        }
1049
1050
        if (!is_file($file)) {
1051
            continue;
1052
        }
1053
1054
        $cmd[] = 'DEF:'.$inst_name.'_min='.$file.':'.$ds.':MIN';
1055
        $cmd[] = 'DEF:'.$inst_name.'_avg='.$file.':'.$ds.':AVERAGE';
1056
        $cmd[] = 'DEF:'.$inst_name.'_max='.$file.':'.$ds.':MAX';
1057
    }
1058
1059
    foreach ($sources as &$inst_data) {
1060
        $inst_name = $inst_data['name'];
1061
        $legend    = sprintf('%s', $inst_name);
1062
        while (strlen($legend) < $max_inst_name) {
1063
            $legend .= ' ';
1064
        }
1065
1066
        $number_format = isset($opts['number_format']) ? $opts['number_format'] : '%6.1lf';
1067
1068 View Code Duplication
        if (isset($opts['colors'][$inst_name])) {
1069
            $line_color = new CollectdColor($opts['colors'][$inst_name]);
1070
        }
1071
        else {
1072
            $line_color = new CollectdColor('random');
1073
        }
1074
1075
        $cmd[] = 'LINE1:'.$inst_name.'_avg#'.$line_color->as_string().':'.$legend;
1076 View Code Duplication
        if (!(isset($opts['tinylegend']) && $opts['tinylegend'])) {
1077
            $cmd[] = 'GPRINT:'.$inst_name.'_min:MIN:'.$number_format.'';
1078
            $cmd[] = 'GPRINT:'.$inst_name.'_avg:AVERAGE:'.$number_format.'';
1079
            $cmd[] = 'GPRINT:'.$inst_name.'_max:MAX:'.$number_format.'';
1080
            $cmd[] = 'GPRINT:'.$inst_name.'_avg:LAST:'.$number_format.'\\l';
1081
        }
1082
    }//end foreach
1083
1084
    $rrdcmd        = RRDTOOL;
1085
    $count_cmd = count($cmd);
1086 View Code Duplication
    for ($i = 1; $i < $count_cmd; $i++) {
1087
        $rrdcmd .= ' '.escapeshellarg($cmd[$i]);
1088
    }
1089
1090
    return $rrdcmd;
1091
1092
}//end collectd_draw_meta_line()
1093