#!/usr/bin/perl
#

use lib "/home/spong/lib";

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

# Configuration variables

$SPONGDB = "/home/spong/var/database";

$RRDCGI  = "/usr/local/rrdtool/bin/rrdcgi";  # Location of RRD CGI program

$RRDDIR = "/home/spong/var/rrd";        # RRD Databases location
$RRDWWWDIR = "/home/spong/var/spong-rrd";  # Location to put generated
                                                # CGI programs

$WWW_URL = "/spong-rrd";                     # URL path to spong-rrd web pages
$WWW_IMAGE_URL = "/spong-rrd/images";        # URL path to image directory
$IMAGE_DIR = "/home/spong/tmp/spong-rrd";               # Directory file for generated
                                             # graph images

$CGIEXT = ".cgi";

@COLORS = ( "00cc00", "0000ff", "00ffff", "ff00ff", "ffff00", "cc0000",
            "0080c0", "8080c0", "ff0080", "800080", "0000a0",
            "408080", "808000", "000000", "00ff00", "0080ff", "ff8000",
            "800000", "fb31fb" );
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"); 
   $fh->print("<ul>\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("<li>Disk Usage<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>\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("<li>CPU/Job Information\n");
      $fh->print("<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");
   }

   # If data_rrd_mysql plugin is running, generate the MySQL stats pages
   if ( -f "$RRDDIR/$host/.rrd-mysql" ) {
      &debug("data_rrd_mysql DB's found, running MySQLGen");

      $fh->print("<li>MySQL Information\n");
      $fh->print("<ul>\n");

      &doMySQLThreads( $RRDDIR, $host );

      $fh->print("<li><a HREF=\"$WWW_URL/$host/mysql-threads" . $CGIEXT .
                 "\">Threads</a></li>\n" );

      &doMySQLTables( $RRDDIR, $host );

      $fh->print("<li><a HREF=\"$WWW_URL/$host/mysql-tables" . $CGIEXT .
                 "\">Tables</a></li>\n" );

      &doMySQLAvg( $RRDDIR, $host );

      $fh->print("<li><a HREF=\"$WWW_URL/$host/mysql-avg" . $CGIEXT .
                 "\">Queries per Second</a></li>\n" );
      $fh->print("</ul>\n");
   }

   # If data_rrd_ping plugin is running, generate the ping stats pages
   if ( -f "$RRDDIR/$host/.rrd-ping" ) {
      &debug("data_rrd_mysql DB's found, running PingGen");

      $fh->print("<li>Ping Information\n");
      $fh->print("<ul>\n");

      &doPingTimes( $RRDDIR, $host );

      $fh->print("<li><a HREF=\"$WWW_URL/$host/ping-times" . $CGIEXT .
                 "\">Response Time</a></li>\n" );
      $fh->print("</ul>\n");
   }

   # If data_rrd_realserver plugin is running, run the RealServerGen routines
   if ( -f "$RRDDIR/$host/.rrd-realserver" ) { 
      &debug("data_rrd_realserver DB's found, running RealServerGen");
      $namemap = &doRealServerSingle( $RRDDIR, $host );

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

      $fh->print("<li>RealServer Usage<ul>\n");
      $fh->print("<li><A HREF=\"$WWW_URL/$host/realserver-summary" . $CGIEXT . 
                 "\">All streams</a></li>\n" );
      foreach my $stream (sort( keys(%$namemap) ) ) {
         $fh->print("<li><A HREF=\"$WWW_URL/$host/realserver-$stream" . $CGIEXT .
                    "\">" . $namemap->{$stream} . "</a></li>\n" );
      }
      $fh->print("</ul>\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 (sort @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 doMySQLThreads {
   my( $rrddir, $host ) = @_;

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

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

   my($cgidir) = "$RRDWWWDIR/$host";
   my($cgifile) = "$cgidir/mysql-threads";
   $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, MySQL Threads",
                         "MySQL Threads for $host") );

   my $comment = "threads";

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

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

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

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

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

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

}

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

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

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

   my($cgidir) = "$RRDWWWDIR/$host";
   my($cgifile) = "$cgidir/mysql-tables";
   $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, MySQL Tables",
                         "MySQL Tables for $host") );

   my $comment = "tables";

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

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

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

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

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

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

}

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

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

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

   my($cgidir) = "$RRDWWWDIR/$host";
   my($cgifile) = "$cgidir/mysql-avg";
   $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, MySQL Queries per Second",
                         "MySQL Queries per Second for $host") );

   $fh->print("If you have MySQL v3.22 or below, these'll be zero.\n");

   my $comment = "queries/s";

   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &dsGraph('hourly',$host,$rrdfile,"avg","MySQL Queries per Second",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Daily</h3>" );
   $fh->print( &dsGraph('daily',$host,$rrdfile,"avg","MySQL Queries per Second",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Weekly</h3>" );
   $fh->print( &dsGraph('weekly',$host,$rrdfile,"avg","MySQL Queries per Second",
                        $comment ) );
   $fh->print( "\n</p>\n" );

   $fh->print( "<P>\n<H3>Monthly</h3>" );
   $fh->print( &dsGraph('monthly',$host,$rrdfile,"avg","MySQL Queries per Second",
               $comment  ) );
   $fh->print( "\n</p>\n" );

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

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

}



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

   # Build the DEFS and LINES definitions
   my( $partfile, $defs, $lines, $p ); 
   $defs = $lines = ""; $p=-1;
   my($rrdfile) = "$rrddir/$host/ping-times.rrd";
   foreach $part ( @{ [ 'max', 'avg', 'min' ] } ) {
        $p++;
        $defs .= "\nDEF:$p=$rrdfile:$part:AVERAGE";

        if ($part eq 'max') {
            $lines .= "\nAREA:$p#" . $COLORS[$p] . ":$part";
        } else {
            $lines .= "\nLINE2:$p#" . $COLORS[$p] . ":$part";
        }
   }

   my($cgifile) = "$RRDWWWDIR/$host/ping-times";
   $cgifile .= $CGIEXT if $CGIEXT;

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

   $fh->print( cgiHeader("host $host, Ping Times",
                          "Ping Times to $host") );
   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &pingTimes('hourly',$host,$part,$rrdfile,$defs,$lines) );
   $fh->print( "\n</p>\n" );

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

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

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

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

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



sub pingTimes {
   my($type,$host,$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-ping-times-$type.gif --title "$host Ping Times"
      --imginfo '<IMG SRC="$WWW_IMAGE_URL/%s" WIDTH="%lu" HEIGHT="%lu">'
      -w 500 -h 200 -v "ping times (s)" -s $timestr
      $defs
      $lines
>
|;

   return $graph;
}




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 doRealServerSummary {
   my( $rrddir, $host, $namemap ) = @_;

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

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

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

   $fh->print( cgiHeader("host $host, All Streams",
                          "RealServer Players Summary for $host") );
   $fh->print( "<P>\n<H3>Hourly</h3>" );
   $fh->print( &realServerGraphAll('hourly',$host,$rrdfile,$defs,$lines) );
   $fh->print( "\n</p>\n" );

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

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

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

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

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

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

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

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

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

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

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

   }

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

sub bldStreamCGI {
   my( $host, $streamfile, $stream, $rrdfile ) = @_;

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

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

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

   $fh->print( &cgiHeader("host $host, stream $streamName",
                         "RealServer Usage for $host $part") );

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

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

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

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

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

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

sub realServerGraphAll {
   my($type,$host,$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-realserver-$type.gif --title "$host All Streams"
      --imginfo '<IMG SRC="$WWW_IMAGE_URL/%s" WIDTH="%lu" HEIGHT="%lu">'
      -l 0 -w 500 -h 200 -v "players" -s $timestr
      $defs
      $lines
>
|;

   return $graph;
}

sub realServerGraphOne {
   my($type,$host,$streamfile,$stream,$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-$streamfile-$type.gif --title "$host $stream"
      --imginfo '<IMG SRC="$WWW_IMAGE_URL/%s" WIDTH="%lu" HEIGHT="%lu">'
      -w 500 -h 200 -v "% Full" -s $timestr
      DEF:part=$rrdfile:players: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>
<META HTTP-EQUIV=\"Expires\" CONTENT=0>
</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; 
}
