#!/usr/bin/perl
#

use lib "/usr/share/spong/Spong";

use IO::File;
use Data::Dumper;
use File::Path;
use Sys::Hostname;
use Getopt::Long;
use Carp;

# Configuration variables

$config_file = "/etc/spong/spong.rrd";

require $config_file || die "Can't load $config_file: $!";

my(@files);

%opt;
@options = ("info","help","debug");
if (! GetOptions(\%opt, @options)) {warn "Incorrect usage, see $0 --help"; exit 1; }

if ($opt{"help"}) { &usage(); exit 0; }

$debug = ($opt{'debug'}) ? 1 : 0;

opendir DIR,$RRDDIR or die "Could not opendir $RRDDIR: $!";
@files = grep { ! /^\./ } readdir(DIR);
closedir DIR;
&debug("Done scanning $RRDDIR dir, found " . ($#files+1) . " hosts");

# Create the IMAGE_DIR dir is not present
if ( ! -d $IMAGE_DIR ) {
   &debug("\$IMAGE_DIR $IMAGE_DIR not found, creating it");
   mkpath $IMAGE_DIR,0,"0777";
}

foreach $host (@files) {
   &debug("Processing host $host");

   # If --info parameter entered, generate Host Info file for the host
   if ( $opt{'info'} ) { &doInfo($host) }

   my($namemap);

   # Create $host subdirectories if needed
   if (! -d "$RRDWWWDIR/$host" ) {
       &debug("spong-rrd dir $RRDWWWDIR/$host not found, creating it");
       mkpath "$RRDWWWDIR/$host",0,0755;
    }

   my( $indexfile ) = "$RRDWWWDIR/$host/index.html";
   my( $fh ) = new IO::File "$indexfile","w";
   if (! defined $fh) {
      &error("doDiskIndex: Error: could not create file $indexfile; $!");
      return;
   }

   $fh->print( &htmlHeader("System Charts of $host",
                           "Spong RRD - System Charts") );
   $fh->print("\n<H1>System Charts for $host.</h1>\n");
   $fh->print("<P>\n"); 

   # If data_rrd_disk plugin is running, run the DiskGen routines
   if ( -f "$RRDDIR/$host/.rrd-disk" ) { 
      &debug("data_rrd_disk DB's found, running DiskGen");
      $namemap = &doDiskSingle( $RRDDIR, $host );

      if (%$namemap) {
         &doDiskSummary( $RRDDIR, $host, $namemap);
      }

      $fh->print("<ul><li><h2>Disk Usage:</h2><ul>\n");
      $fh->print("<li><A HREF=\"$WWW_URL/$host/disk-summary" . $CGIEXT . 
                 "\">All partitions</a></li>\n" );
      foreach my $part (sort( keys(%$namemap) ) ) {
         $fh->print("<li><A HREF=\"$WWW_URL/$host/disk-$part" . $CGIEXT .
                    "\">" . $namemap->{$part} . "</a></li>\n" );
      }
      $fh->print("</ul></ul>\n");
   }

   # If data_rrd_la plugin is running, generate the CPU stats pages
   if ( -f "$RRDDIR/$host/.rrd-la" ) {
      &debug("data_rrd_la DB's found, running LoadAvgGen");

      $fh->print("<p><ul>\n");

      &doLoadAvg( $RRDDIR, $host );

      $fh->print("<li><a HREF=\"$WWW_URL/$host/loadavg" . $CGIEXT .
                 "\">Load Average</a></li>\n" );

      &doNumUsers( $RRDDIR, $host );

      $fh->print("<li><a HREF=\"$WWW_URL/$host/num-users" . $CGIEXT .
                 "\">Number of Users</a></li>\n" );

      &doNumJobs( $RRDDIR, $host );

      $fh->print("<li><a HREF=\"$WWW_URL/$host/num-jobs" . $CGIEXT .
                 "\">Number of Jobs</a></li>\n" );
      $fh->print("<\ul>\n");
   }

   $fh->print( &cgiFooter() );
   $fh->close();

}

# Build index page of hosts that have rrd data
&buildIndex();
exit; 

sub buildIndex {
   my($curtime) = scalar localtime();
   my($host) = &Sys::Hostname::hostname();
   my($user) = $ENV{'USER'};

   $fh = new IO::File "$RRDWWWDIR/index.html","w";

   print $fh "
<!-- spong-rrd host index file  
    Generated at $curtime on $host by $user --!>

<HTML>
<HEAD><TITLE>$title</TITLE></HEAD>
<BODY>
<center><H1>Spong-rrd Host Index</H1></center>
<hr>
<UL>
";
   foreach $host (@files) {
      print $fh "	<li><a href=$WWW_URL/$host/index.html>$host</a>\n";   
   }

   print $fh "
</ul>
</body>
</html>
";

   $fh->close();

}

sub doInfo {
   my( $host ) = @_;

   my($infodir) = "$SPONGDB/$host/info";
   if (! -d $infodir ) { mkpath "$infodir",0,"0755"; }

   my($fh) = new IO::File "$infodir/info.html","w";
   if (! defined $fh) {
       &error("doInfo: Error: Could not create file $infodir/info.html: $!");
       return;
   }

   $fh->print("<a href=\"$WWW_URL/$host/index.html\">System Charts</a>");

   $fh->close();

   &debug("info file i$infodir/info.html created for host $host");
}


sub doLoadAvg {
   my( $rrddir, $host ) = @_;

   my($rrdfile) = "$RRDDIR/$host/la.rrd";

   # If rrdfile not found, complain and move on
   if ( ! -f $rrdfile ) {
      &error("doDiskGen: Error: Can't find rrd file $rrdfile");
      next;
    }

   my($cgidir) = "$RRDWWWDIR/$host";
   my($cgifile) = "$cgidir/loadavg";
   $cgifile .= $CGIEXT if $CGIEXT;

   if (! -d $cgidir) { mkpath "$cgidir",0,0755; }

   my($fh) = new IO::File "$cgifile","w";
   if (! defined $fh) {
      &error("bldPartCGI: Error: Could not create file $cgifile: $!");
      return;
   }

   $fh->print( &cgiHeader("host $host, Load Average",
                         "Load Average for $host") );

   my $comment = "load avg";

   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &dsGraph('hourly',$host,$rrdfile,"loadavg","Load Average",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Daily</h3>" );
   $fh->print( &dsGraph('daily',$host,$rrdfile,"loadavg","Load Average",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Weekly</h3>" );
   $fh->print( &dsGraph('weekly',$host,$rrdfile,"loadavg","Load Average",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Monthly</h3>" );
   $fh->print( &dsGraph('monthly',$host,$rrdfile,"loadavg","Load Average",
               $comment  ) );
   $fh->print( "\n</p>\n" );

   $fh->print( &cgiFooter );
   $fh->close();

   # Set permissions so it's executable
   chmod 0755,$cgifile;

}

sub doNumUsers {
   my( $rrddir, $host ) = @_;

   my($rrdfile) = "$RRDDIR/$host/la.rrd";

   # If rrdfile not found, complain and move on
   if ( ! -f $rrdfile ) {
      &error("doDiskGen: Error: Can't find rrd file $rrdfile");
      next;
    }

   my($cgidir) = "$RRDWWWDIR/$host";
   my($cgifile) = "$cgidir/num-users";
   $cgifile .= $CGIEXT if $CGIEXT;

   if (! -d $cgidir) { mkpath "$cgidir",0,0755; }

   my($fh) = new IO::File "$cgifile","w";
   if (! defined $fh) {
      &error("bldPartCGI: Error: Could not create file $cgifile: $!");
      return;
   }

   $fh->print( &cgiHeader("host $host, Number of Users" ,
                         "Number of Users for $host") );

   my $comment = "# of users";

   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &dsGraph('hourly',$host,$rrdfile,"users","# of users",
                        $comment) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Daily</h3>" );
   $fh->print( &dsGraph('daily',$host,$rrdfile,"users","# of users",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Weekly</h3>" );
   $fh->print( &dsGraph('weekly',$host,$rrdfile,"users","# of users",
                        $comment) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Monthly</h3>" );
   $fh->print( &dsGraph('monthly',$host,$rrdfile,"users","# of users",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( &cgiFooter );
   $fh->close();

   # Set permissions so it's executable
   chmod 0755,$cgifile;

}

sub doNumJobs {
   my( $rrddir, $host ) = @_;

   my($rrdfile) = "$RRDDIR/$host/la.rrd";

   # If rrdfile not found, complain and move on
   if ( ! -f $rrdfile ) {
      &error("doDiskGen: Error: Can't find rrd file $rrdfile");
      next;
    }

   my($cgidir) = "$RRDWWWDIR/$host";
   my($cgifile) = "$cgidir/num-jobs";
   $cgifile .= $CGIEXT if $CGIEXT;

   if (! -d $cgidir) { mkpath "$cgidir",0,0755; }

   my($fh) = new IO::File "$cgifile","w";
   if (! defined $fh) {
      &error("bldPartCGI: Error: Could not create file $cgifile: $!");
      return;
   }

   my $comment = "# of jobs";

   $fh->print( &cgiHeader("host $host, Number of Jobs",
                         "Number of Jobs for $host") );

   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &dsGraph('hourly',$host,$rrdfile,"jobs","# of jobs",
               $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Daily</h3>" );
   $fh->print( &dsGraph('daily',$host,$rrdfile,"jobs","# of jobs",
               $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Weekly</h3>" );
   $fh->print( &dsGraph('weekly',$host,$rrdfile,"jobs","# of jobs",
               $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Monthly</h3>" );
   $fh->print( &dsGraph('monthly',$host,$rrdfile,"jobs","# of jobs",
               $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( &cgiFooter );
   $fh->close();

   # Set permissions so it's executable
   chmod 0755,$cgifile;

}



sub doDiskSummary {
   my( $rrddir, $host, $namemap ) = @_;

   # Build the DEFS and LINES definitions
   my( $partfile, $defs, $lines, $p ); 
   $defs = $lines = ""; $p=-1;
   foreach $part ( sort (keys %$namemap) ) {
        my($rrdfile) = "$rrddir/$host/disk-$part.rrd";
        $p++;
        $defs .= "\nDEF:$p=$rrdfile:pct:AVERAGE";
        $lines .= "\nLINE2:$p#" . $COLORS[$p] . ':"' . $namemap->{$part} . '"';
   }

   my($cgifile) = "$RRDWWWDIR/$host/disk-summary";
   $cgifile .= $CGIEXT if $CGIEXT;

   my($fh) = new IO::File "$cgifile","w";
   if (! defined $fh) {
      &error("doDiskSummary: Error: could not create file $cgifile; $!");
      return;
   }

   $fh->print( cgiHeader("host $host, All Partitions",
                          "File Usage Summary for $host") );
   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &diskGraphAll('hourly',$host,$partfile,$part,$rrdfile,$defs,$lines) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Daily</h3>" );
   $fh->print( &diskGraphAll('daily',$host,$partfile,$part,$rrdfile,$defs,$lines) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Weekly</h3>" );
   $fh->print( &diskGraphAll('weekly',$host,$partfile,$part,$rrdfile,$defs,$lines) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Monthly</h3>" );
   $fh->print( &diskGraphAll('monthly',$host,$partfile,$part,$rrdfile,$defs,$lines) );
   $fh->print( "\n</p>\n" );

   $fh->print( &cgiFooter );
   $fh->close();

   # Set permissions so it's executable
   chmod 0755,$cgifile;
}


sub doDiskSingle {
   my( $rrddir, $host ) = @_;

   # Read in the disk-name-map files
   my($mapfile)= "$rrddir/$host/disk-name-map";
   my($nm) = new IO::File "$mapfile", "r";
   if (! defined $nm) { 
      &error("Error:doDiskGen: Could not open name map file $file: $!");
      return;
   }

   # Read in the disk name map and process each one
   my( %namemap );
   while (<$nm>) {
      chomp; my($k,$v) = split ':';
      $namemap{$k} = $v;

      my($rrdfile) = "$RRDDIR/$host/disk-$k.rrd";

      # If rrdfile not found, complain and move on
      if ( ! -f $rrdfile ) {
         &error("doDiskGen: Error: Can't find rrd file $rrdfile");
         next;
       }

       # Build the CGI page for the host/partition
       &bldPartCGI($host,$k,$v,$rrdfile);

   }

   return \%namemap; # Return the name map to papa 
}

sub bldPartCGI {
   my( $host, $partfile, $part, $rrdfile ) = @_;

   my($cgidir) = "$RRDWWWDIR/$host";
   my($cgifile) = "$cgidir/disk-$partfile";
   $cgifile .= $CGIEXT if $CGIEXT;

   if (! -d $cgidir) { mkpath "$cgidir",0,0755; }

   my($fh) = new IO::File "$cgifile","w";
   if (! defined $fh) {
      &error("bldPartCGI: Error: Could not create file $cgifile: $!");
      return;
   }

   $fh->print( &cgiHeader("host $host, partition $part",
                         "File Usage for $host $part") );

   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &diskGraphOne('hourly',$host,$partfile,$part,$rrdfile) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Daily</h3>" );
   $fh->print( &diskGraphOne('daily',$host,$partfile,$part,$rrdfile) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Weekly</h3>" );
   $fh->print( &diskGraphOne('weekly',$host,$partfile,$part,$rrdfile) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Monthly</h3>" );
   $fh->print( &diskGraphOne('monthly',$host,$partfile,$part,$rrdfile) );
   $fh->print( "\n</p>\n" );

   $fh->print( &cgiFooter );
   $fh->close();

   # Set permissions so it's executable
   chmod 0755,$cgifile;
}

sub diskGraphAll {
   my($type,$host,$partfile,$part,$rrdfile,$defs,$lines) = @_;

   my($timestr) = "";
   if ($type eq 'hourly') { $timestr = "e-48h"; }
   elsif ($type eq 'daily') { $timestr = "e-12d"; }
   elsif ($type eq 'weekly') { $timestr = "e-48d"; }
   elsif ($type eq 'monthly') { $timestr = "e-576d"; }

   my($graph) = qq|
<RRD::GRAPH $IMAGE_DIR/$host-$partfile-$type.gif --title "$host All Partitions"
      --imginfo '<IMG SRC="$WWW_IMAGE_URL/%s" WIDTH="%lu" HEIGHT="%lu">'
      -l 0 -u 100 -w 500 -h 200 -v "% Full" -s $timestr
      $defs
      $lines
>
|;

   return $graph;
}

sub diskGraphOne {
   my($type,$host,$partfile,$part,$rrdfile) = @_;

   my($timestr) = "";
   if ($type eq 'hourly') { $timestr = "e-48h"; }
   elsif ($type eq 'daily') { $timestr = "e-12d"; }
   elsif ($type eq 'weekly') { $timestr = "e-48d"; }
   elsif ($type eq 'monthly') { $timestr = "e-576d"; }

   my($graph) = qq|
<RRD::GRAPH $IMAGE_DIR/$host-$partfile-$type.gif --title "$host $part"
      --imginfo '<IMG SRC="$WWW_IMAGE_URL/%s" WIDTH="%lu" HEIGHT="%lu">'
      -l 0 -u 100 -w 500 -h 200 -v "% Full" -s $timestr
      DEF:part=$rrdfile:pct:AVERAGE
      LINE2:part#00a000:"$part"
>
|;

   return $graph;
}

sub dsGraph {
   my($type,$host,$rrdfile,$ds,$comment,$y_comment) = @_;

   my($timestr) = "";
   if ($type eq 'hourly') { $timestr = "e-48h"; }
   elsif ($type eq 'daily') { $timestr = "e-12d"; }
   elsif ($type eq 'weekly') { $timestr = "e-48d"; }
   elsif ($type eq 'monthly') { $timestr = "e-576d"; }

   my($graph) = qq|
<RRD::GRAPH $IMAGE_DIR/$host-$ds-$type.gif --title "$host $part"
      --imginfo '<IMG SRC="$WWW_IMAGE_URL/%s" WIDTH="%lu" HEIGHT="%lu">'
      -w 500 -h 200 -v "$y_comment" -s $timestr
      DEF:$ds=$rrdfile:$ds:AVERAGE
      LINE2:$ds#$COLORS[0]:"$comment"
>
|;

   return $graph;
}

sub htmlHeader {
   my($for,$title) = @_;
   my($curtime) = scalar localtime();
   my($host) = &Sys::Hostname::hostname();
   my($user) = $ENV{'USER'};


   my($header) = "
<!-- spong-rrd cgi program file for $for
    Generated at $curtime on $host by $user --!>

<HTML>
<HEAD><TITLE>$title</TITLE></HEAD>
<BODY>
";

   return $header;
}

sub cgiHeader {
   my($for,$title) = @_;
   my($curtime) = scalar localtime();
   my($host) = &Sys::Hostname::hostname();
   my($user) = $ENV{'USER'};


   my($header) = "#!$RRDCGI
<!-- spong-rrd cgi program file for $for
    Generated at $curtime on $host by $user --!>

<HTML>
<HEAD><TITLE>$title</TITLE></HEAD>
<BODY>
<H1>$title</H1>
<P>
";

   return $header;
}

sub cgiFooter {
   my($footer) = "
</BODY>
</HTML>
";
   return $footer;
}

# Error reporting routine
sub error {
   my($msg) = @_;

   warn scalar localtime(), " Error: $msg \n";

}

sub debug  {
   print scalar localtime(), " ", @_[0], "\n" if $main::debug; 
}
