
#!/usr/bin/perl -w

package RRDPerf;
use strict;
use RRDs;
use Color::Rgb;

BEGIN{
	use Exporter ();
	@RRDPerf::ISA       = qw(Exporter);
	@RRDPerf::EXPORT    = qw();
	@RRDPerf::EXPORT_OK = qw(update_rrd graph_rrd);
}

my $rrds = '/usr/local/nagios_indep/var/rrds';
my $imgs = '/usr/local/nagios/share/images/rrdimg';
my $debug = 0;

my $rgb = new Color::Rgb(rgb_txt => '/usr/X11R6/lib/X11/rgb.txt');
my @colors = (
	$rgb->hex('red','#'),
	$rgb->hex('blue','#'),
	$rgb->hex('green','#'),
	$rgb->hex('orange','#'),
	$rgb->hex('dark red','#'),
	$rgb->hex('dark green','#'),
	$rgb->hex('dark blue','#')
);
undef $rgb;

=head1 NAME

RRDPerf.pm - does the work for L<PerfDataConsumers.pm>.

=head1 AUTHOR

(c) 2003 Hannes Schulz <mail@hannes-schulz.de>

=head1 VERSION

Version 1.0

=head1 SYNOPSIS

 use RRDPerf qw/update_rrd graph_rrd/;
 
 # create database if not existing and put in data (two "colums": loss and rta):
 update_rrd("PING","sapwdfr0",30*60,scalar time, "loss", $loss, "RTA", $rta);
 
 # create a picture for a host/service:
 graph_rrd("PING","sapwdfr0","Ping-stats","loss", "RTA");
 
=head1 DEBUGGING

Set C<$debug> to true in the script. If your crontab has a line

  MAILTO=you@sap.com

you should get the results by mail every hour.

=head1 DESCRIPTION

This is doing all the work for L<PerfDataConsumers.pm>. Look there for the gory
details. You should not need to change anything in here... except... well:

This assumes a whole lot of "default" values, like the amount of time the data
will be kept, what color which graph should have...

You I<may> want to change this, try the documentation for RRDTool at

 http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/manual/

The parameters described there are the same as those used in RRDs-module.

=head2 METHODS

=over 4

=item update_rrd

This just puts in the values given into a database named by putting together
the 

  general database path/hostname/servicedescription.rrd

If this file does not exist, it is created by C<create_rrd()>.

Parameters:

 $sdesc  # Service description
 $hn     # Host Name
 $step   # how often 
 $timet  # when messure was taken
 %vals   # like (mem => 10, cpu => 99)

=cut

sub update_rrd($$$$@){
	my $sdesc = shift();    # Service description
	my $hn    = shift();    # Host Name
	my $step  = shift();    # how often 
	my $timet = shift();    # when messure was taken
	my %vals  = @_;         # like {mem => 10, cpu => 99}

	my $timeoffset = `cat /usr/local/nagios_indep/var/rrds/$hn/toffset.txt`;
	$timet += ($timeoffset * 3600);

	$sdesc =~ s/\W/-/g;     # for use as filename
	unless(-e "$rrds/$hn/$sdesc.rrd"){
		create_rrd($sdesc,$hn,$step,$timet,@_);
	}
	
	my @cmd = (
		"$rrds/$hn/$sdesc.rrd",
	);

	push @cmd, join(":", $timet, values %vals);

	RRDs::update(@cmd);
	my $ERR=RRDs::error;
	if($ERR){
		sleep 2;             # wait... and
		RRDs::update(@cmd);  # try again
		$ERR=RRDs::error;
	}
	warn  "ERROR while updating: $ERR\n".join(" ",@cmd) if($ERR and $debug);
}

=item create_rrd($$$@)

This creates a new RRD-File, using rough guesses about what you want.
See the RRDTool-Documentation and here: L<RRDs> for more infos.

It sleeps 1 second at the end, so that an update immediately afterwards is
possible.

Parameters:

  $sdesc # Service description
  $hn    # Host Name
  $step  # how often 
  $timet # when messure was taken
  %vals  # like {mem => 10, cpu => 99}

=cut

sub create_rrd($$$$@){
	my $sdesc = shift();    # Service description
	my $hn    = shift();    # Host Name
	my $step  = shift();    # how often 
	my $timet = shift();    # when messure was taken
	my %vals  = @_;         # like {mem => 10, cpu => 99}

	$sdesc =~ s/\W/-/g;     # for use as filename

	mkdir("$rrds/$hn");
	
	my @cmd = (
		"$rrds/$hn/$sdesc.rrd",
		"--start", $timet-$step,
		"--step",  $step
	);
	foreach(keys %vals){
		push(@cmd,"DS:$_:GAUGE:".($step*3).":-9999999999:9999999999");
		push(@cmd,"RRA:AVERAGE:0.5:1:2688"); # 1 Month if step=15min
		push(@cmd,"RRA:AVERAGE:0.5:4:4320"); # 6 Months if step=15min/4
	}
	print "creating $rrds/$hn/$sdesc.rrd..." if $debug;
	RRDs::create(@cmd);
	my $ERR=RRDs::error;
	die "ERROR while creating: $ERR\n" if $ERR;
	print "done.\n" if $debug;
	sleep 2;
}

=item graph_rrd

This creates a graph for a database (name put together as shown above).

Again, it uses rough guesses, use the RRDTool Documentation and here:
L<RRDs.pm> if you want to change anything that is B<not> self-explanatory.

Parameters:

  $sdesc  # Service Description
  $hn     # Host Name
  $title  # Title of the diagram 
  @DSs    # All DSses.

=cut

sub graph_rrd{
	graph_rrd_do_work("180",@_);
	graph_rrd_do_work("007",@_);
	graph_rrd_do_work("002",@_);
}
sub graph_rrd_do_work{
	my $days  = shift();     # number of days
	my $sdesc = shift();     # Service Description
	my $hn    = shift();     # Host Name
	my $title = shift();     # Title of the diagram 
	my @DSs   = @_;          # All DSses.

	$sdesc =~ s/\W/-/g;      # make filename-usable
	my $file = "$rrds/$hn/$sdesc.rrd";
	return unless(-e $file);

	my $end   = scalar time;
	my $start = scalar time - ($days*86400);

	my $grid;
	$grid =  "WEEK:1:MONTH:1:MONTH:1:345600:%b" if($days>10);
	$grid =  "DAY:1:WEEK:1:DAY:1:86400:%m-%d"    if($days<10);
	$grid =  "HOUR:2:DAY:1:HOUR:2:0:%H"   if($days<=3);

	my $timeoffset = `cat /usr/local/nagios_indep/var/rrds/$hn/toffset.txt`;
	$end   += ($timeoffset * 3600);
	$start += ($timeoffset * 3600);

	my @cmd =(
		"$imgs/$hn"."__$sdesc"."__$days.png",        # Dest
		"--x-grid", $grid,                           # Mayor grid 1 week,
		"--start", $start,                           # one week ### TODO
		"--end", $end,                               # now + offset
		"--imgformat", "PNG",
		"--title", "$hn: $title"                     # "Hostname: Title"
	);
	my $i = 0;
	my $d = "";
	foreach(@DSs){
		$d = $_;
		$d =~ y!_!/! if($sdesc eq "fs-disk-nrpep");
		push @cmd, "DEF:$_=$file:$_:AVERAGE";
		push @cmd, "LINE2:$_$colors[$i]:$d";
		$i++;
	}

	RRDs::graph(@cmd);
	
	my $ERR=RRDs::error;
	warn  "ERROR while graphing: $ERR\n".join(", ",@cmd) if($ERR);
}

=back

=cut

1;
