makegraphs umgebaut, sodass nurnoch rrd daten geschrieben werden die graphen
[people/pmueller/ipfire-2.x.git] / src / scripts / makegraphs
1 #!/usr/bin/perl
2
3 ############################################################################
4 #                                                                          #
5 # This file is part of the IPCop Firewall.                                 #
6 #                                                                          #
7 # IPCop 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 2 of the License, or        #
10 # (at your option) any later version.                                      #
11 #                                                                          #
12 # IPCop 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 IPCop; if not, write to the Free Software                     #
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA #
20 #                                                                          #
21 # Copyright (C) 2004-01-19 Mark Wormgoor <mark@wormgoor.com>.              #
22 #                                                                          #
23 ############################################################################
24
25 use strict;
26 #use warnings;
27
28 use RRDs;
29 require "/var/ipfire/general-functions.pl";
30 require "${General::swroot}/lang.pl";
31
32 my (%settings, @ipacsum, $iface, $ERROR);
33 &General::readhash("${General::swroot}/ethernet/settings", \%settings);
34 my %mbmon_settings = ();
35 &General::readhash("${General::swroot}/mbmon/settings", \%mbmon_settings);
36
37 # Added for conversion of utf-8 characters
38 use Encode 'from_to';
39 my %tr=();
40
41 # Force language back to English (ugly hack!)
42 # Modified to only force if we are unable to convert charset 
43 # from utf-8
44 if ((${Lang::language} eq 'el') || 
45     (${Lang::language} eq 'fa') ||
46     (${Lang::language} eq 'ru') ||
47     (${Lang::language} eq 'th') || 
48     (${Lang::language} eq 'vi') ||
49     (${Lang::language} eq 'zh') ||
50     (${Lang::language} eq 'zt')) {
51         eval `/bin/cat "${General::swroot}/langs/en.pl"`;
52 } else {
53         %tr=%Lang::tr;          # use translated version for other languages
54 }
55
56 # Settings
57 my $rrdlog = "/var/log/rrd";
58 my $graphs = "/srv/web/ipfire/html/graphs";
59 $ENV{PATH}="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
60 my $hdd_device = "/dev/harddisk";
61 my $temp = '';
62 my %mbmon_values = ();
63 my $key;
64 my $value;
65 my @args = ();
66 my $count = 0;
67 my $ERROR;
68 my $dbg = 0;
69 my $path_smartctl = "/usr/sbin/smartctl";
70 my $path_hddtemp = "/usr/sbin/hddtemp";
71
72 my %color = ();
73 my %mainsettings = ();
74 &General::readhash("${General::swroot}/main/settings", \%mainsettings);
75 &General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
76
77 open(MBMON_OUT, ">/var/log/mbmon-values");
78 open(FD, "/usr/bin/mbmon -rc1|" ) || die "ERROR: Cannot run mbmon\n" ;
79
80 while( $_ = <FD> ) 
81 {
82   next unless( /^([A-Za-z][^:\s]+)\s*:\s*([+\-]{0,1}[\d\.]+)/ ) ;
83   $key = $1 ;
84   $value = $2 ;
85   $key =~ y/A-Z/a-z/ ;
86   $mbmon_values{$key} = $value;
87   print(MBMON_OUT "$key=$value\n");
88 }
89 close(FD);
90 close(MBMON_OUT);
91
92 sub gettraffic {
93         my $interface = $_[0];
94
95         my $bytesin=0;
96         my $bytesout=0;
97
98         foreach (@ipacsum)
99         {
100                 # Incoming...
101                 $bytesin += $1 if (/^[\* ]\s+incoming\s+${interface}.+\:\s+(\d+)/);
102
103                 # Forwarded Incoming...
104                 $bytesin += $1 if (/^[\* ]\s+forwarded\s+incoming\s+${interface}.+\:\s+(\d+)/);
105
106                 # Outgoing...
107                 $bytesout += $1 if (/^[* ]\s+outgoing\s+${interface}.+\:\s+(\d+)/);
108
109                 # Forwarded Outgoing...
110                 $bytesout += $1 if (/^[* ]\s+forwarded\s+outgoing\s+${interface}.+\:\s+(\d+)/);
111         }
112         return "$bytesin:$bytesout";
113 }
114
115 sub updatecpudata {
116         if ( ! -e "$rrdlog/cpu.rrd") {
117                 RRDs::create ("$rrdlog/cpu.rrd", "--step=300",
118                         "DS:user:GAUGE:600:0:100",
119                         "DS:system:GAUGE:600:0:100",
120                         "DS:idle:GAUGE:600:0:100",
121                         "DS:iowait:GAUGE:600:0:100",
122                         "RRA:AVERAGE:0.5:1:576",
123                         "RRA:AVERAGE:0.5:6:672",
124                         "RRA:AVERAGE:0.5:24:732",
125                         "RRA:AVERAGE:0.5:144:1460");
126                 $ERROR = RRDs::error;
127                 print "Error in RRD::create for cpu: $ERROR\n" if $ERROR;
128         }
129
130         my ($cpu, $user, $nice, $system, $idle, $trash, $iowait);
131
132         my $Zeilen = `/usr/bin/iostat -c | tail -2 | head -1`;
133         ($trash, $user, $nice, $system, $iowait, $trash, $idle) = split(/\s+/,$Zeilen);
134         $user += $nice;
135
136         RRDs::update ("$rrdlog/cpu.rrd",
137                 "-t", "user:system:idle:iowait", 
138                 "N:$user:$system:$idle:$iowait");
139         $ERROR = RRDs::error;
140         print "Error in RRD::update for cpu: $ERROR\n" if $ERROR;
141
142 }
143
144 sub updateloaddata {
145         if ( ! -e "$rrdlog/load.rrd") {
146                 RRDs::create ("$rrdlog/load.rrd", "--step=60",
147                         "DS:load1:GAUGE:120:0:U",
148                         "DS:load5:GAUGE:120:0:U",
149                         "DS:load15:GAUGE:120:0:U",
150                         "RRA:AVERAGE:0.5:1:2160",
151                         "RRA:AVERAGE:0.5:5:2016",
152                         "RRA:AVERAGE:0.5:15:2880",
153                         "RRA:AVERAGE:0.5:60:8760");
154
155                 $ERROR = RRDs::error;
156                 print "Error in RRD::create for cpu: $ERROR\n" if $ERROR;
157         }
158 }
159
160 sub updatememdata {
161         my ($memused, $memfree, $memshared, $membuffers, $memcache, $swapused, $swapfree, $swaptotal);
162         if ( ! -e "$rrdlog/mem.rrd") {
163                 RRDs::create ("$rrdlog/mem.rrd", "--step=300",
164                         "DS:memused:ABSOLUTE:600:0:5000000000",
165                         "DS:memfree:ABSOLUTE:600:0:5000000000",
166                         "DS:memshared:ABSOLUTE:600:0:5000000000",
167                         "DS:membuffers:ABSOLUTE:600:0:5000000000",
168                         "DS:memcache:ABSOLUTE:600:0:5000000000",
169                         "DS:swapused:ABSOLUTE:600:0:5000000000",
170                         "DS:swapfree:ABSOLUTE:600:0:5000000000",
171                         "RRA:AVERAGE:0.5:1:576",
172                         "RRA:AVERAGE:0.5:6:672",
173                         "RRA:AVERAGE:0.5:24:732",
174                         "RRA:AVERAGE:0.5:144:1460");
175                 $ERROR = RRDs::error;
176                 print "Error in RRD::create for mem: $ERROR\n" if $ERROR;
177         }
178
179         open MEM, "/proc/meminfo";
180         while(<MEM>) {
181                 chomp;
182                 if ($_ =~ /^MemTotal:/) {
183                         my @temp = split (/\s+/, $_);
184                         $memused    = $temp[1];
185                 } elsif ($_ =~ /^MemFree:/) {
186                         my @temp = split (/\s+/, $_);
187                         $memfree    = $temp[1];
188                 } elsif ($_ =~ /^Cached:/) {
189                         my @temp = split (/\s+/, $_);
190                         $memcache   = $temp[1];
191                 } elsif ($_ =~ /^Buffers:/) {
192                         my @temp = split (/\s+/, $_);
193                         $membuffers = $temp[1];
194                 } elsif ($_ =~ /^SwapTotal:/) {
195                         my @temp = split (/\s+/, $_);
196                         $swaptotal   = $temp[1];
197                 } elsif ($_ =~ /^SwapFree:/) {
198                         my @temp = split (/\s+/, $_);
199                         $swapfree   = $temp[1];
200                 }
201         }
202         close MEM;
203
204         system("/bin/df > /tmp/diskfree");
205         open DF, "/tmp/diskfree";
206         while(<DF>) {
207                 chomp;
208                 if ($_ =~ /^shm/) {
209                         my @temp = split (/\s+/, $_);
210                         $memshared  = $temp[2];
211                 }
212         }
213         close DF;
214         system("/bin/rm -f /tmp/diskfree");
215         
216         $swapused = $swaptotal-$swapfree;
217         RRDs::update ("$rrdlog/mem.rrd",
218                 "-t", "memused:memfree:memshared:membuffers:memcache:swapused:swapfree",
219                 "N:$memused:$memfree:$memshared:$membuffers:$memcache:$swapused:$swapfree");
220         $ERROR = RRDs::error;
221         print "Error in RRD::update for mem: $ERROR\n" if $ERROR;
222 }
223
224 sub updatediskdata {
225         my $disk = $_[0];
226         my ($readsect, $writesect, $trash);
227         if ( ! -e "$rrdlog/disk-$disk.rrd") {
228                 RRDs::create ("$rrdlog/disk-$disk.rrd", "--step=300",
229                         "DS:readsect:COUNTER:600:0:5000000000",
230                         "DS:writesect:COUNTER:600:0:5000000000",
231                         "RRA:AVERAGE:0.5:1:576",
232                         "RRA:AVERAGE:0.5:6:672",
233                         "RRA:AVERAGE:0.5:24:732",
234                         "RRA:AVERAGE:0.5:144:1460");
235                 $ERROR = RRDs::error;
236                 print "Error in RRD::create for disk $disk: $ERROR\n" if $ERROR;
237         }        
238         
239         my $Zeilen = `/usr/bin/iostat $disk | tail -2 | head -1`;
240         ($trash, $trash, $trash, $trash, $readsect, $writesect) = split(/\s+/,$Zeilen);
241         
242         print "\nread:".$readsect."write:".$writesect."\n";
243
244         if ($readsect && $writesect) {
245                 RRDs::update ("$rrdlog/disk-$disk.rrd",
246                         "-t", "readsect:writesect",
247                         "N:$readsect:$writesect");
248                 $ERROR = RRDs::error;
249                 print "Error in RRD::update for disk $disk: $ERROR\n" if $ERROR;
250         } else {
251                 print "Error in RRD::update for disk: $disk no data available\n";
252         }
253 }
254
255 sub updateifdata {
256         my $interface = $_[0];
257
258         if ( ! -e "$rrdlog/$interface.rrd") {
259                 RRDs::create ("$rrdlog/$interface.rrd", "--step=300",
260                         "DS:incoming:ABSOLUTE:600:0:12500000",
261                         "DS:outgoing:ABSOLUTE:600:0:12500000",
262                         "RRA:AVERAGE:0.5:1:576",
263                         "RRA:AVERAGE:0.5:6:672",
264                         "RRA:AVERAGE:0.5:24:732",
265                         "RRA:AVERAGE:0.5:144:1460");
266                 $ERROR = RRDs::error;
267                 print "Error in RRD::create for $interface: $ERROR\n" if $ERROR;
268         }
269
270         my $traffic = gettraffic ($interface);
271         RRDs::update ("$rrdlog/$interface.rrd",
272                 "-t", "incoming:outgoing", 
273                 "N:$traffic");
274         $ERROR = RRDs::error;
275         print "Error in RRD::update for $interface: $ERROR\n" if $ERROR;
276 }
277
278 sub updatefwhitsdata {
279         my $portamount=0;
280         my $alertaktuell=0;
281         my $aktuell=0;
282         my $portaktuell=0;
283         my $skip=0;
284
285         if (! -e "$rrdlog/firewallhits.rrd")
286         {
287                 RRDs::create ("$rrdlog/firewallhits.rrd", "--step=300",
288                         "DS:amount:GAUGE:600:0:U",
289                         "DS:portamount:GAUGE:600:0:U",
290                         "RRA:AVERAGE:0.5:1:576",
291                         "RRA:AVERAGE:0.5:6:672",
292                         "RRA:AVERAGE:0.5:24:732",
293                         "RRA:AVERAGE:0.5:144:1460");
294                 $ERROR = RRDs::error;
295                 print "Error in RRD::create for cpu: $ERROR\n" if $ERROR;
296         }
297
298         system("logtailfwhits /var/log/messages /var/log/fwhits.messages.offset >/tmp/messages.fwhits");
299         if (!(open (FILE,'/tmp/messages.fwhits'))) {
300            $skip=1;
301         }
302         $aktuell = 0;
303         if (!$skip) {
304                 while (<FILE>) {
305                         if (/kernel:.*(IN=.*)$/) {
306                                 $aktuell++;
307                         }
308                 }
309                 close (FILE);
310         }
311
312         system("logtailfwhits /var/log/snort/alert /var/log/snort/fwhits.alert.offset >/tmp/snort.fwhits");
313         if (!(open (FILE,'/tmp/snort.fwhits'))) {
314            $skip=1;
315         }
316         $alertaktuell = 0;
317         if (!$skip) {
318                 while (<FILE>) {
319                         if (/scan.*$/) {
320                                 $alertaktuell++;
321                         }
322                 }
323                 close (FILE);
324         }
325
326         if (!(open (FILE,'/tmp/messages.fwhits'))) {
327            $skip=1;
328         }
329         $portaktuell = 0;
330         if (!$skip) {
331                 while (<FILE>) {
332                         if (/kernel:.*(Scan.*)$/) {
333                                 $portaktuell++;
334                         }
335                 }
336                 close (FILE);
337         }
338
339         system("rm /tmp/messages.fwhits");
340         system("rm /tmp/snort.fwhits");
341
342         $portamount = $portaktuell + $alertaktuell;
343         chomp($portamount);
344         RRDs::update ("$rrdlog/firewallhits.rrd",
345                 "N:$aktuell:$portamount");
346         $ERROR = RRDs::error;
347         print "Error in RRD::update for Firewallhits: $ERROR\n" if $ERROR;
348 }
349
350 # Creates and updates a link quality database
351 # -------------------------------------------
352 sub updatelq {
353         if ( ! -e "$rrdlog/lq.rrd") {
354                 RRDs::create ("$rrdlog/lq.rrd", "--step=300",
355                         "DS:loss:GAUGE:600:0:100",
356                         "DS:roundtrip:GAUGE:600:0:10000",
357                         "RRA:AVERAGE:0.5:1:576",
358                         "RRA:AVERAGE:0.5:6:672",
359                         "RRA:AVERAGE:0.5:24:732",
360                         "RRA:AVERAGE:0.5:144:1460");
361                 $ERROR = RRDs::error;
362                 print "Error in RRD::create for link: $ERROR\n" if $ERROR;
363         }
364         my $packetloss=0;
365         my $roundtrip=0;
366         my $test=0;
367 #       LQ_GATEWAY is the ip of your isp's public ip facing you
368         my $LQ_GATEWAY=`netstat -rn | grep ^0.0.0.0 | awk '{print \$2}'`;
369         my $NUMPINGS=10;
370         my $pingoutput = `ping -c $NUMPINGS -q $LQ_GATEWAY`;
371         chomp;
372         my @temp = split (/\/|\%|\s/, $pingoutput);
373         $packetloss   = $temp[17];
374         $roundtrip    = $temp[28];
375         RRDs::update ("$rrdlog/lq.rrd", "N:$packetloss:$roundtrip");
376         $ERROR = RRDs::error;
377         print "Error in RRD::update for line quality: $ERROR\n" if $ERROR;
378
379
380 sub updatehdddata 
381 {
382   my $disk = $_[0];
383   if ( ! -e "$rrdlog/hddtemp-$disk.rrd") 
384   {
385     # database did not exist -> create
386     RRDs::create ("$rrdlog/hddtemp-$disk.rrd", "--step=300",
387       "DS:temperature:GAUGE:600:0:100",
388       "RRA:AVERAGE:0.5:1:576",
389       "RRA:AVERAGE:0.5:6:672",
390       "RRA:AVERAGE:0.5:24:732",
391       "RRA:AVERAGE:0.5:144:1460");
392     $ERROR = RRDs::error;
393     print "Error in RRD::create for hdd-$disk: $ERROR\n" if $ERROR;
394   }
395
396   $temp = 0;
397   my $hdd_output = '';
398   my $smart_output = '';
399
400   if ( -e "$path_smartctl" )
401   {
402     system("$path_smartctl -iHA /dev/$disk > /var/log/smartctl_out_hddtemp-$disk");
403   }
404
405   if ( -e "$path_hddtemp" )
406   {
407     $hdd_output = `$path_hddtemp -qn /dev/$disk`;
408
409     # I know 4 response possible responses:
410     #
411     # /dev/harddisk: harddisk type: S.M.A.R.T. not available
412     # /dev/harddisk: harddisk type: no sensor
413     # /dev/harddisk: harddisk type: 37?C or ?F
414     # 37
415
416     if ( index($hdd_output, "S.M.A.R.T.") != -1 )
417     {
418       $temp = 0;
419     }
420     elsif ( index($hdd_output, "no sensor") != -1 )
421     {
422       $temp = 1;
423     }
424     elsif ( index($hdd_output, "$disk") != -1 )
425     {
426       $hdd_output =~ /.*:.*:\s*(\d+).*\s/;
427       $temp = $1;
428     }
429     else
430     {
431       $hdd_output =~ /(\d+)\s/;
432       $temp = $1;
433     }
434   }
435   elsif ( -e "/var/log/smartctl_out_hddtemp-$disk" )
436   {
437     $hdd_output = `cat /var/log/smartctl_out_hddtemp-$disk | grep Temperature_`;
438     my @t = split(/\s+/,$hdd_output);
439     $temp = $t[9];
440   }
441   else
442   {
443     $temp = 0;
444   }
445
446 #  print "hdd  $hdd_output \n";
447 #  print "temp $temp \n";
448
449   RRDs::update ("$rrdlog/hddtemp-$disk.rrd", "-t", "temperature", "N:$temp");
450
451   $ERROR = RRDs::error;
452   print "Error in RRD::update for hdd-$disk: $ERROR\n" if $ERROR;
453 }
454
455 sub updatembmondata 
456 {
457   if ( ! -e "$rrdlog/mbmon.rrd" )
458   {
459     # database did not exist -> create
460
461     @args = ("$rrdlog/mbmon.rrd");
462
463     push(@args, "--step=300");
464     foreach $key ( sort(keys %mbmon_values) ) 
465     {
466       push(@args, "DS:$key:GAUGE:600:U:U");
467     }
468     push(@args, "RRA:AVERAGE:0.5:1:576");
469     push(@args, "RRA:AVERAGE:0.5:6:672");
470     push(@args, "RRA:AVERAGE:0.5:24:732");
471     push(@args, "RRA:AVERAGE:0.5:144:1460");
472
473     print("create ". join( ", ", @args)) if ( $dbg );
474    
475     RRDs::create (@args);
476     $ERROR = RRDs::error;
477     print("Error in RRD::create for mbmon: $ERROR\n") if $ERROR;
478   }
479
480   my @ds;
481   my @val;
482   my $template;
483
484   foreach $key ( sort(keys %mbmon_values) )
485   {
486     push(@ds, $key);
487     push(@val, $mbmon_values{$key});
488   }
489
490   $template = join(':', @ds);
491   $value    = "N:".join(':', @val);
492
493   print("update template = '$template'\n") if ( $dbg );
494   print("update value    = '$value'\n") if ( $dbg );
495
496   RRDs::update("$rrdlog/mbmon.rrd", "-t", $template, $value);
497   $ERROR = RRDs::error;
498   print("Error in RRD::update for mbmon: $ERROR\n") if $ERROR;
499 }
500
501 ## Update ipac logs
502 system ('/usr/sbin/fetchipac');
503 sleep 8;
504
505 ###
506 ### Squid Graphs
507 ###
508 if ( -e "/var/log/squid/access.log") {
509         system ("/usr/bin/squid-graph -o=/srv/web/ipfire/html/sgraph --tcp-only < /var/log/squid/access.log >/dev/null 2>&1");
510 }
511
512 ###
513 ### utf8 conversion
514 ###
515 if ((${Lang::language} eq 'cs') || 
516     (${Lang::language} eq 'hu') || 
517     (${Lang::language} eq 'pl') || 
518     (${Lang::language} eq 'sk')) {
519         # Czech, Hungarian, Polish and Slovak character set
520         foreach my $key(keys %Lang::tr) {
521                 from_to($tr{$key}, "utf-8", "iso-8859-2");
522         }
523 } elsif (${Lang::language} eq 'tr') {
524         # Turkish
525         foreach my $key(keys %Lang::tr) {
526                 from_to($tr{$key}, "utf-8", "iso-8859-9");
527         }
528 } else {
529         foreach my $key(keys %Lang::tr) {
530                 from_to($tr{$key}, "utf-8", "iso-8859-1"); 
531         }
532 }
533
534 ###
535 ### System graphs
536 ###
537 updatecpudata();
538 updateloaddata();
539 updatememdata();
540
541 my @disks = `kudzu -qps -c HD | grep device: | cut -d" " -f2 | sort | uniq`;
542 print "\nFound following amount of disks:".@disks."\n";
543 foreach (@disks){
544 my $disk = $_;
545 chomp $disk;
546 print "Working on disk ".$disk.".\n";
547 updatediskdata($disk);
548 }
549
550 ###
551 ### Firewallhits
552 ###
553 updatefwhitsdata();
554
555 ###
556 ### Link Quality
557 ###
558 updatelq();
559
560 ###
561 ### HDDTEMP-Graphs for /dev/harddisk
562 ###
563
564 my @disks = `kudzu -qps -c HD | grep device: | cut -d" " -f2 | sort | uniq`;
565 print "\nFound following amount of disks for hddtemp:".@disks."\n";
566 foreach (@disks){
567 my $disk = $_;
568 chomp $disk;
569 updatehdddata ($disk);
570 }
571
572 ###
573 ### Network Graphs
574 ###
575 @ipacsum = `/usr/sbin/ipacsum --exact -s 5m 2>/dev/null`;
576 if (@ipacsum) {
577         updateifdata  ("GREEN");
578         updateifdata  ("RED");
579         if ($settings{'CONFIG_TYPE'} =~ /^(2|4)$/ ) {
580                 updateifdata  ("ORANGE");
581         }
582         if ($settings{'CONFIG_TYPE'} =~ /^(3|4)$/ ) {
583                 updateifdata  ("BLUE");
584         }
585 }