#!/usr/bin/perl -w #-d
#
# sar/iostat graphing tool based on rrdtool
# (c) 2004 B. Cornec HP <bruno.cornec@hp.com>
# Licensed under the GPL or Artistic License
#
# Original Charter: Monitor CPU/Load/Net_eth0|2 (io/s)/Disk (io/s) 
# 1 mesure par 20 seconde
# So the script has been developped first with that context in mind
# trying to be generic enough to be expandable later on
# More work needs to be done, some code factorized, ...
#
use strict;		# Always :-)
use RRDs;		# for data management and graphing
use Data::Dumper;	# for debug
use HTML::AsSubs;	# for HTML generation
use Storable;		# for data exchange
use Date::Manip;	# for timestamp
use Config::Auto;	# for config file
use sario2rrd qw(from_epoch);
			# local common functions


# Avoid localisation problems in sar
$ENV{LANG}="C";

#
# Begin of configuration options
#
my $dir = "sar2rrd"; 	# Place under the html dir of user apache
			# Under that directory you should have one
			# directory per machine and in it all the
			# files resulting form the sar and iostat
			# commands (saxx and ioxx). Look at the 
			# cron file and related script

my ($l,$p,$uid,$gid,$q,$c,$gc,$apache,$empty) = getpwnam("apache") or die "apache not in passwd file";
my $base = "$apache/html/$dir";
my $config = Config::Auto::parse("$base/$dir.conf");
my @machines = @{$config->{machines}};

my $debug = 0;
foreach my $a (@ARGV) {
	$debug++ if ($a =~ /-v/);
	$| = 1;		# Flush STDOUT
}
my $m;
my %t;
my %attrio = %{ retrieve("$base/$config->{svgio}") };
my %attrsar = %{ retrieve("$base/$config->{svgsar}") };

my $h = "$base/index.html";
open (MAIN, "> $h") || die "Unable to create $h : $!";
my @hm = (h1("sar2rrd - sar/iostats monitoring via rrdtool"),
	p("List of systems to monitor:"));
my @index;
my @tmp1;
my @tmp2;

print Dumper($config) if ($debug > 1);

foreach $m (@machines) {
	@tmp1 = ();
	@tmp2 = ();
	#
	# The graphs/HTML generation
	#
	push @index,li(a({href=>"$m/index.html"}, "$m"));
	my $hm = "$base/$m/index.html";
	open (MACHINE, "> $hm") || die "Unable to create $hm : $!";
	my @hhm = (h1("sar2rrd - Monitoring $m"));
	my $img="$base/$m/img";
	print "Graphing rrd base for $m under $img\n" if ($debug > 0);
	printf "Between %s/%s and %s/%s for sar\n",from_epoch($attrsar{$m}{mintmst}),$attrsar{$m}{mintmst},ParseDate("epoch $attrsar{$m}{maxtmst}"),$attrsar{$m}{maxtmst} if ($debug > 0);
	printf "Between %s (%s) and %s (%s) for iostat\n",ParseDate("epoch $attrio{$m}{mintmst}"),$attrio{$m}{mintmst},ParseDate("epoch $attrio{$m}{maxtmst}"),$attrio{$m}{maxtmst} if ($debug > 0);
	print "Generating " if ($debug > 0);
	mkdir "$img",0755 if (not (-d "$img"));
	unlink <$img/*.png>;
	print "mem.png " if ($debug > 0);
	RRDs::graph("$img/mem.png","-s $attrsar{$m}{mintmst}","-e $attrsar{$m}{maxtmst}","-L KB","-v KiloBytes","-aPNG","-t Memory Report","DEF:s1=$base/$m/$config->{rrdsar}:memoryfree:AVERAGE","AREA:s1#00ee22:Free Memory");
	my $rrderror = RRDs::error;
    	die "Problem while generating graph: $rrderror\n" if ($rrderror);
	print "load.png " if ($debug > 0);
	RRDs::graph("$img/load.png","-s",$attrsar{$m}{mintmst},"-e",$attrsar{$m}{maxtmst},"-S",$config->{step},"-aPNG","-t","Load Report","DEF:s1=$base/$m/$config->{rrdsar}:load1:AVERAGE","DEF:s2=$base/$m/$config->{rrdsar}:load5:AVERAGE","DEF:s3=$base/$m/$config->{rrdsar}:runq:AVERAGE","LINE2:s1#00b6e4:Load 1m","LINE2:s2#00ee22:Load 5m","LINE2:s3#ff0000:Run Queue");
	$rrderror = RRDs::error;
    	die "Problem while generating graph: $rrderror\n" if ($rrderror);
	push @tmp1,td(img({src=>"$config->{http}/$dir/$m/img/mem.png"}));
	push @tmp1,td(img({src=>"$config->{http}/$dir/$m/img/load.png"}));
	push @tmp1,HTML::AsSubs::tr(@tmp1);

	my $col = 0;
	foreach my $i (@{$attrsar{$m}{measures}},@{$attrio{$m}{measures}}) {
		if ($i =~ /^eth/) {
			$i =~ s/-[inout]+//;
			next if (-f "$img/$i.png");
			print "$i.png " if ($debug > 0);
			RRDs::graph("$img/$i.png","-s",$attrsar{$m}{mintmst},"-e",$attrsar{$m}{maxtmst},"-S",$config->{step},"-aPNG","-t","Network Report","DEF:s1=$base/$m/$config->{rrdsar}:$i-in:AVERAGE","DEF:s2=$base/$m/$config->{rrdsar}:$i-out:AVERAGE","LINE2:s1#ff0000:$i (in)","LINE2:s2#00ee22:$i (out)");
			push @tmp2,td(img({src=>"$config->{http}/$dir/$m/img/$i.png"}));
			$col++;
			if ($col == 2) {
				push @tmp1,HTML::AsSubs::tr(@tmp2);
				@tmp2 = ();
				$col = 0;
			}
				
		}
		if (($i =~ /^sd/) || ($i =~ /^hd/) || ($i =~ /^cciss/)) {
			$i =~ s/-[inout]+//;
			next if (-f "$img/$i.png");
			print "$i.png " if ($debug > 0);
			RRDs::graph("$img/$i.png","-s",$attrio{$m}{mintmst},"-e",$attrio{$m}{maxtmst},"-S",$config->{step},"-aPNG","-t","Disk Report","DEF:s1=$base/$m/$config->{rrdio}:$i-in:AVERAGE","DEF:s2=$base/$m/$config->{rrdio}:$i-out:AVERAGE","LINE2:s1#ff0000:$i (in)","LINE2:s2#00ee22:$i (out)");
			push @tmp2,td(img({src=>"$config->{http}/$dir/$m/img/$i.png"}));
			$col++;
			if ($col == 2) {
				push @tmp1,HTML::AsSubs::tr(@tmp2);
				@tmp2 = ();
				$col = 0;
			}
		}
		if (($i =~ /^cpu/) || ($i =~ /^all/)) {
			$i =~ s/-[a-z]+//;
			next if (-f "$img/$i.png");
			print "$i.png " if ($debug > 0);
			RRDs::graph("$img/$i.png","-s",$attrsar{$m}{mintmst},"-e",$attrsar{$m}{maxtmst},"-S",$config->{step},"-aPNG","-t","CPU Report","DEF:s1=$base/$m/$config->{rrdsar}:$i-idle:AVERAGE","DEF:s2=$base/$m/$config->{rrdsar}:$i-nice:AVERAGE","DEF:s3=$base/$m/$config->{rrdsar}:$i-system:AVERAGE","DEF:s4=$base/$m/$config->{rrdsar}:$i-user:AVERAGE","AREA:s1#00b6e4:$i (idle)","STACK:s2#00ee22:$i (nice)","STACK:s3#ff0000:$i (system)","STACK:s4#000000:$i (user)");
			push @tmp2,td(img({src=>"$config->{http}/$dir/$m/img/$i.png"}));
			$col++;
			if ($col == 2) {
				push @tmp1,HTML::AsSubs::tr(@tmp2);
				@tmp2 = ();
				$col = 0;
			}
		}
	}
	$rrderror = RRDs::error;
    	die "Problem while generating graph: $rrderror\n" if ($rrderror);
	print "\n" if ($debug > 0);
	push @hhm,table(@tmp1);
	my $hhm = body(@hhm);
	print MACHINE $hhm->as_HTML;
	close(MACHINE);
}
push @hm,ul(@index);
my $hm = body(@hm);
print MAIN $hm->as_HTML;
close MAIN;
print "Point your browser to $config->{http}/$dir/index.html\n" if ($debug > 0);
