Some cosmetic edits
authorAndrew DeFaria <Andrew@DeFaria.com>
Wed, 18 Jul 2018 20:08:18 +0000 (13:08 -0700)
committerAndrew DeFaria <Andrew@DeFaria.com>
Wed, 18 Jul 2018 20:08:18 +0000 (13:08 -0700)
Adding new Machines.pm interface

13 files changed:
clearadm/lib/Clearadm.pm
clearadm/lib/ClearadmWeb.pm
clearadm/lib/Clearexec.pm
clearadm/lib/User.pm
data/machines
etc/machines.sql [new file with mode: 0644]
lib/Clearquest/DBService.pm
lib/Clearquest/REST.pm
lib/Clearquest/Server.pm
lib/Machines.pm [new file with mode: 0755]
lib/Machines/MySQL.pm [new file with mode: 0755]
rc/gitconfig
rc/system

index fb63079..719b772 100644 (file)
@@ -36,7 +36,7 @@ specifics about the method you are envoking.
 
  # Create new Clearadm object
  my $clearadm = new Clearadm;
+
  # Add a new system
  my %system = (
   name          => 'jupiter',
@@ -46,22 +46,22 @@ specifics about the method you are envoking.
   type          => 'Linux',
   description   => 'Home server',
  );
+
  my ($err, $msg) = $clearadm->AddSystem (%system);
+
  # Find systems matching 'jup'
  my @systems = $clearadm->FindSystem ('jup');
+
  # Get a system by name
  my %system = $clearadm->GetSystem ('jupiter');
+
  # Update system
  my %update = (
   'region' => 'East Coast',
  );
 
  my ($err, $msg) = $clearadm->UpdateSystem ('jupiter', %update);
+
  # Delete system (Warning: will delete all related records regarding this
  # system).
  my ($err, $msg) = $clearadm->DeleteSystem ('jupiter');
@@ -69,8 +69,8 @@ specifics about the method you are envoking.
 =head1 DESCRIPTION
 
 This package provides and object oriented interface to the Clearadm database.
-Methods are provided to manipulate records by adding, updating and deleting 
-them. In general you need to specify a hash which contains keys and values 
+Methods are provided to manipulate records by adding, updating and deleting
+them. In general you need to specify a hash which contains keys and values
 corresponding to the database field names and values.
 
 =head1 ROUTINES
@@ -105,19 +105,19 @@ our %CLEAROPTS = GetConfig ($conf);
 # Globals
 our $VERSION  = '$Revision: 1.54 $';
    ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
-  
-$CLEAROPTS{CLEARADM_USERNAME} = $ENV{CLEARADM_USERNAME} 
+
+$CLEAROPTS{CLEARADM_USERNAME} = $ENV{CLEARADM_USERNAME}
                               ? $ENV{CLEARADM_USERNAME}
                               : $CLEAROPTS{CLEARADM_USERNAME}
                               ? $CLEAROPTS{CLEARADM_USERNAME}
                               : 'clearwriter';
-$CLEAROPTS{CLEARADM_PASSWORD} = $ENV{CLEARADM_PASSWORD} 
+$CLEAROPTS{CLEARADM_PASSWORD} = $ENV{CLEARADM_PASSWORD}
                               ? $ENV{CLEARADM_PASSWORD}
                               : $CLEAROPTS{CLEARADM_PASSWORD}
                               ? $CLEAROPTS{CLEARADM_PASSWORD}
                               : 'clearwriter';
-$CLEAROPTS{CLEARADM_SERVER}   = $ENV{CLEARADM_SERVER} 
-                              ? $ENV{CLEARADM_SERVER} 
+$CLEAROPTS{CLEARADM_SERVER}   = $ENV{CLEARADM_SERVER}
+                              ? $ENV{CLEARADM_SERVER}
                               : $CLEAROPTS{CLEARADM_SERVER}
                               ? $CLEAROPTS{CLEARADM_SERVER}
                               : 'localhost';
@@ -132,12 +132,12 @@ sub _dberror ($$) {
 
   my $dberr    = $self->{db}->err;
   my $dberrmsg = $self->{db}->errstr;
-  
+
   $dberr    ||= 0;
   $dberrmsg ||= 'Success';
 
   my $message = '';
-  
+
   if ($dberr) {
     my $function = (caller (1)) [3];
 
@@ -145,82 +145,82 @@ sub _dberror ($$) {
              . "SQL Statement: $statement";
   } # if
 
-  return $dberr, $message;  
+  return $dberr, $message;
 } # _dberror
 
 sub _formatValues (@) {
   my ($self, @values) = @_;
-  
+
   my @returnValues;
-  
+
   # Quote data values
-  push @returnValues, $_ eq '' ? 'null' : $self->{db}->quote ($_)  
-    foreach (@values);
-  
+  push @returnValues, $_ eq '' ? 'null' : $self->{db}->quote ($_)
+    for (@values);
+
   return @returnValues;
 } # _formatValues
 
 sub _formatNameValues (%) {
   my ($self, %rec) = @_;
-  
+
   my @nameValueStrs;
-  
+
   push @nameValueStrs, "$_=" . $self->{db}->quote ($rec{$_})
-    foreach (keys %rec);
-    
+    for (keys %rec);
+
   return @nameValueStrs;
 } # _formatNameValues
 
 sub _addRecord ($%) {
   my ($self, $table, %rec) = @_;
-  
+
   my $statement  = "insert into $table (";
      $statement .= join ',', keys %rec;
      $statement .= ') values (';
      $statement .= join ',', $self->_formatValues (values %rec);
      $statement .= ')';
-  
+
   my ($err, $msg);
-  
+
   $self->{db}->do ($statement);
-  
+
   return $self->_dberror ("Unable to add record to $table", $statement);
 } # _addRecord
 
 sub _deleteRecord ($;$) {
   my ($self, $table, $condition) = @_;
-  
+
   my $count;
-  
+
   my $statement  = "select count(*) from $table ";
      $statement .= "where $condition"
       if $condition;
-  
+
   my $sth = $self->{db}->prepare ($statement)
     or return $self->_dberror ('Unable to prepare statement', $statement);
-    
+
   $sth->execute
     or return $self->_dberror ('Unable to execute statement', $statement);
-    
+
   my @row = $sth->fetchrow_array;
-  
+
   $sth->finish;
-  
+
   if ($row[0]) {
     $count = $row[0];
   } else {
     $count = 0;
   } # if
-  
+
   return ($count, 'Records deleted')
     if $count == 0;
-    
+
   $statement  = "delete from $table ";
   $statement .= "where $condition"
     if $condition;
-  
+
   $self->{db}->do ($statement);
-  
+
   if ($self->{db}->err) {
     return $self->_dberror ("Unable to delete record from $table", $statement);
   } else {
@@ -235,44 +235,44 @@ sub _updateRecord ($$%) {
      $statement .= join ',', $self->_formatNameValues (%rec);
      $statement .= " where $condition"
        if $condition;
-  
+
   $self->{db}->do ($statement);
-  
+
   return $self->_dberror ("Unable to update record in $table", $statement);
 } # _updateRecord
 
 sub _checkRequiredFields ($$) {
   my ($fields, $rec) = @_;
-  
-  foreach my $fieldname (@$fields) {
+
+  for my $fieldname (@$fields) {
     my $found = 0;
-    
-    foreach (keys %$rec) {
+
+    for (keys %$rec) {
       if ($fieldname eq $_) {
         $found = 1;
         last;
       } # if
-    } # foreach
-    
+    } # for
+
     return "$fieldname is required"
       unless $found;
-  } # foreach
-  
+  } # for
+
   return;
 } # _checkRequiredFields
 
 sub _getRecords ($$) {
   my ($self, $table, $condition) = @_;
-  
+
   my ($err, $msg);
-    
+
   my $statement = "select * from $table where $condition";
-  
+
   my $sth = $self->{db}->prepare ($statement);
-  
+
   unless ($sth) {
     ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement);
-    
+
     croak $msg;
   } # if
 
@@ -280,15 +280,15 @@ sub _getRecords ($$) {
   my $maxAttempts = 3;
   my $sleepTime   = 30;
   my $status;
-  
+
   # We've been having the server going away. Supposedly it should reconnect so
-  # here we simply retry up to $maxAttempts times to re-execute the statement. 
+  # here we simply retry up to $maxAttempts times to re-execute the statement.
   # (Are there other places where we need to do this?)
   $err = 2006;
-  
+
   while ($err == 2006 and $attempts++ < $maxAttempts) {
     $status = $sth->execute;
-    
+
     if ($status) {
       $err = 0;
       last;
@@ -296,16 +296,16 @@ sub _getRecords ($$) {
       ($err, $msg) = $self->_dberror ('Unable to execute statement',
                                       $statement);
     } # if
-    
+
     last if $err == 0;
-    
+
     croak $msg unless $err == 2006;
 
     my $timestamp = YMDHMS;
-      
+
     $self->Error ("$timestamp: Unable to talk to DB server.\n\n$msg\n\n"
                 . "Will try again in $sleepTime seconds", -1);
-                
+
     # Try to reconnect
     $self->_connect ($self->{dbserver});
 
@@ -314,21 +314,21 @@ sub _getRecords ($$) {
 
   $self->Error ("After $maxAttempts attempts I could not connect to the database", $err)
     if ($err == 2006 and $attempts > $maxAttempts);
-  
+
   my @records;
-  
+
   while (my $row = $sth->fetchrow_hashref) {
     push @records, $row;
   } # while
-  
+
   return @records;
 } # _getRecord
 
 sub _aliasSystem ($) {
   my ($self, $system) = @_;
-  
+
   my %system = $self->GetSystem ($system);
-  
+
   if ($system{name}) {
     return $system{name};
   } else {
@@ -338,54 +338,54 @@ sub _aliasSystem ($) {
 
 sub _getLastID () {
   my ($self) = @_;
-  
+
   my $statement = 'select last_insert_id()';
-  
+
   my $sth = $self->{db}->prepare ($statement);
-  
+
   my ($err, $msg);
-  
+
   unless ($sth) {
     ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my $status = $sth->execute;
-  
+
   unless ($status) {
     ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my @records;
 
   my @row = $sth->fetchrow_array;
-  
+
   return $row[0];
 } # _getLastID
 
 sub _connect (;$) {
   my ($self, $dbserver) = @_;
-  
+
   $dbserver ||= $CLEAROPTS{CLEARADM_SERVER};
-  
+
   my $dbname   = 'clearadm';
   my $dbdriver = 'mysql';
 
   $self->{db} = DBI->connect (
-    "DBI:$dbdriver:$dbname:$dbserver", 
+    "DBI:$dbdriver:$dbname:$dbserver",
     $CLEAROPTS{CLEARADM_USERNAME},
     $CLEAROPTS{CLEARADM_PASSWORD},
     {PrintError => 0},
   ) or croak (
-    "Couldn't connect to $dbname database " 
+    "Couldn't connect to $dbname database "
   . "as $CLEAROPTS{CLEARADM_USERNAME}\@$CLEAROPTS{CLEARADM_SERVER}"
   );
-  
+
   $self->{dbserver} = $dbserver;
-  
+
   return;
 } # _connect
 
@@ -401,9 +401,9 @@ sub new (;$) {
 
 sub SetNotify () {
   my ($self) = @_;
-  
+
   $self->{NOTIFY} = $CLEAROPTS{CLEARADM_NOTIFY};
-  
+
   return;
 } # SetNotify
 
@@ -411,9 +411,9 @@ sub Error ($;$) {
   my ($self, $msg, $errno) = @_;
 
   # If $errno is specified we need to stop. However we need to notify somebody
-  # that cleartasks is no longer running.  
+  # that cleartasks is no longer running.
   error $msg;
-  
+
   if ($errno) {
     if ($self->{NOTIFY}) {
       mail (
@@ -422,35 +422,35 @@ sub Error ($;$) {
         data    => "<p>An unexpected, internal error occurred in Clearadm:</p><p>$msg</p>",
         mode    => 'html',
       );
-    
+
       exit $errno  if $errno > 0;
     } # if
   } # if
-  
+
   return;
 } # Error
 
 sub AddSystem (%) {
   my ($self, %system) = @_;
-  
+
   my @requiredFields = (
     'name',
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%system;
-  
+
   return -1, "AddSystem: $result"
     if $result;
-  
+
   $system{loadavgHist} ||= $defaultLoadavgHist;
-  
+
   return $self->_addRecord ('system', %system);
 } # AddSystem
 
 sub DeleteSystem ($) {
   my ($self, $name) = @_;
 
-  return $self->_deleteRecord ('system', "name='$name'");  
+  return $self->_deleteRecord ('system', "name='$name'");
 } # DeleteSystem
 
 sub UpdateSystem ($%) {
@@ -461,15 +461,15 @@ sub UpdateSystem ($%) {
 
 sub GetSystem ($) {
   my ($self, $system) = @_;
-  
+
   return
     unless $system;
-  
+
   my @records = $self->_getRecords (
-    'system', 
+    'system',
     "name='$system' or alias like '%$system%'"
   );
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
@@ -481,23 +481,23 @@ sub FindSystem (;$) {
   my ($self, $system) = @_;
 
   $system ||= '';
-  
+
   my $condition = "name like '%$system%' or alias like '%$system%'";
-                         
+
   return $self->_getRecords ('system', $condition);
 } # FindSystem
 
 sub SearchSystem (;$) {\r
   my ($self, $condition) = @_;
-  
+
   $condition = "name like '%'" unless $condition;
-  
-  return $self->_getRecords ('system', $condition); \r
+
+  return $self->_getRecords ('system', $condition);\r
 } # SearchSystem
 
 sub AddPackage (%) {
   my ($self, %package) = @_;
-  
+
   my @requiredFields = (
     'system',
     'name',
@@ -505,48 +505,48 @@ sub AddPackage (%) {
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%package;
-  
+
   return -1, "AddPackage: $result"
     if $result;
-  
+
   return $self->_addRecord ('package', %package);
 } # AddPackage
 
 sub DeletePackage ($$) {
   my ($self, $system, $name) = @_;
-  
+
   return $self->_deleteRecord (
-    'package', 
+    'package',
     "(system='$system' or alias='$system') and name='$name'");
 } # DeletePackage
 
 sub UpdatePackage ($$%) {
   my ($self, $system, $name, %update) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   return $self->_updateRecord ('package', "system='$system'", %update);
 } # UpdatePackage
 
 sub GetPackage($$) {
   my ($self, $system, $name) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   return
     unless $name;
-    
+
   my @records = $self->_getRecords (
-    'package', 
+    'package',
     "system='$system' and name='$name'"
   );
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
@@ -560,18 +560,18 @@ sub FindPackage ($;$) {
   $name ||= '';
 
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   my $condition = "system='$system' and name like '%$name%'";
-  
+
   return $self->_getRecords ('package', $condition);
 } # FindPackage
 
 sub AddFilesystem (%) {
   my ($self, %filesystem) = @_;
-  
+
   my @requiredFields = (
     'system',
     'filesystem',
@@ -579,38 +579,38 @@ sub AddFilesystem (%) {
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%filesystem;
-  
+
   return -1, "AddFilesystem: $result"
     if $result;
-    
+
   # Default filesystem threshold
   $filesystem{threshold} ||= $defaultFilesystemThreshold;
-  
+
   return $self->_addRecord ('filesystem', %filesystem);
 } # AddFilesystem
 
 sub DeleteFilesystem ($$) {
   my ($self, $system, $filesystem) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   return $self->_deleteRecord (
-    'filesystem', 
+    'filesystem',
     "system='$system' and filesystem='$filesystem'"
   );
 } # DeleteFilesystem
 
 sub UpdateFilesystem ($$%) {
   my ($self, $system, $filesystem, %update) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   return $self->_updateRecord (
     'filesystem',
     "system='$system' and filesystem='$filesystem'",
@@ -620,20 +620,20 @@ sub UpdateFilesystem ($$%) {
 
 sub GetFilesystem ($$) {
   my ($self, $system, $filesystem) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   return
     unless $filesystem;
-    
+
   my @records = $self->_getRecords (
-    'filesystem', 
+    'filesystem',
     "system='$system' and filesystem='$filesystem'"
   );
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
@@ -643,49 +643,49 @@ sub GetFilesystem ($$) {
 
 sub FindFilesystem ($;$) {
   my ($self, $system, $filesystem) = @_;
-  
+
   $filesystem ||= '';
 
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
 
-  my $condition = "system='$system' and filesystem like '%$filesystem%'";     
-      
+  my $condition = "system='$system' and filesystem like '%$filesystem%'";
+
   return $self->_getRecords ('filesystem', $condition);
 } # FindFilesystem
 
 sub AddVob (%) {
   my ($self, %vob) = @_;
-  
+
   my @requiredFields = (
     'system',
     'tag',
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%vob;
-  
+
   return -1, "AddVob: $result"
     if $result;
-  
+
   return $self->_addRecord ('vob', %vob);
 } # AddVob
 
 sub DeleteVob ($) {
   my ($self, $tag) = @_;
-  
+
   return $self->_deleteRecord ('vob', "tag='$tag'");
 } # DeleteVob
 
 sub GetVob ($) {
   my ($self, $tag) = @_;
-  
-  return 
+
+  return
     unless $tag;
-    
+
   my @records = $self->_getRecords ('vob', "tag='$tag'");
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
@@ -695,40 +695,40 @@ sub GetVob ($) {
 
 sub FindVob ($) {
   my ($self, $tag) = @_;
-  
+
   return $self->_getRecords ('vob', "tag like '%$tag%'");
 } # FindVob
 
 sub AddView (%) {
   my ($self, %view) = @_;
-  
+
   my @requiredFields = (
     'system',
     'tag',
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%view;
-  
+
   return -1, "AddView: $result"
     if $result;
-  
+
   return $self->_addRecord ('view', %view);
 } # AddView
 
 sub DeleteView ($) {
   my ($self, $tag) = @_;
-  
+
   return $self->_deleteRecord ('vob', "tag='$tag'");
 } # DeleteView
 
 sub GetView ($) {
   my ($self, $tag) = @_;
-  
+
   return
     unless $tag;
-  
+
   my @records = $self->_getRecords ('view', "tag='$tag'");
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
@@ -743,9 +743,9 @@ sub FindView (;$$$$) {
   $region    ||= '';
   $tag       ||= '';
   $ownerName ||= '';
-  
+
   my $condition;
-  
+
   $condition  = "system like '%$system%'";
   $condition .= ' and ';
   $condition  = "region like '%$region%'";
@@ -753,44 +753,44 @@ sub FindView (;$$$$) {
   $condition .= "tag like '%$tag'";
   $condition .= ' and ';
   $condition .= "ownerName like '%$ownerName'";
-                         
+
   return $self->_getRecords ('view', $condition);
 } # FindView
 
 sub AddFS (%) {
   my ($self, %fs) = @_;
-  
+
   my @requiredFields = (
     'system',
     'filesystem',
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%fs;
-  
+
   return -1, "AddFS: $result"
     if $result;
-  
+
   # Timestamp record
   $fs{timestamp} = Today2SQLDatetime;
-  
+
   return $self->_addRecord ('fs', %fs);
 } # AddFS
 
 sub TrimFS ($$) {
   my ($self, $system, $filesystem) = @_;
-  
+
   my %filesystem = $self->GetFilesystem ($system, $filesystem);
-  
+
   return
     unless %filesystem;
-   
+
   my %task = $self->GetTask ('scrub');
-  
+
   $self->Error ("Unable to find scrub task!", 1) unless %task;
-   
+
   my $days;
   my $today = Today2SQLDatetime;
-  
+
   # TODO: SubtractDays uses just an approximation (i.e. subtracting 30 days when
   # in February is not right.
   if ($filesystem{filesystemHist} =~ /(\d+) month/i) {
@@ -800,44 +800,44 @@ sub TrimFS ($$) {
   } # if
 
   my $oldage = SubtractDays $today, $days;
-  
+
   my ($dberr, $dbmsg) = $self->_deleteRecord (
     'fs',
     "system='$system' and filesystem='$filesystem' and timestamp<='$oldage'"
   );
-  
+
   if ($dbmsg eq 'Records deleted') {
     return (0, $dbmsg)
       if $dberr == 0;
-      
+
     my %runlog;
-    
+
     $runlog{task}    = $task{name};
     $runlog{started} = $today;
     $runlog{status}  = 0;
-    $runlog{message} = 
+    $runlog{message} =
       "Scrubbed $dberr fs records for filesystem $system:$filesystem";
-    
+
     my ($err, $msg) = $self->AddRunlog (%runlog);
-    
+
     $self->Error ("Unable to add runlog - (Error: $err)\n$msg") if $err;
   } # if
-  
+
   return ($dberr, $dbmsg);
 } # TrimFS
 
 sub TrimLoadavg ($) {
   my ($self, $system) = @_;
-  
+
   my %system = $self->GetSystem ($system);
-  
+
   return
     unless %system;
-    
+
   my %task = $self->GetTask ('loadavg');
-  
+
   $self->Error ("Unable to find loadavg task!", 1) unless %task;
-   
+
   my $days;
   my $today = Today2SQLDatetime;
 
@@ -850,26 +850,26 @@ sub TrimLoadavg ($) {
   } # if
 
   my $oldage = SubtractDays $today, $days;
-  
+
   my ($dberr, $dbmsg) = $self->_deleteRecord (
     'loadavg',
     "system='$system' and timestamp<='$oldage'"
   );
-  
+
   if ($dbmsg eq 'Records deleted') {
     return (0, $dbmsg)
       if $dberr == 0;
-      
+
     my %runlog;
-    
+
     $runlog{task}    = $task{name};
     $runlog{started} = $today;
     $runlog{status}  = 0;
-    $runlog{message} = 
+    $runlog{message} =
       "Scrubbed $dberr loadavg records for system $system";
 
     my ($err, $msg) = $self->AddRunlog (%runlog);
-    
+
     $self->Error ("Unable to add runload (Error: $err)\n$msg") if $err;
   } # if
 
@@ -878,17 +878,17 @@ sub TrimLoadavg ($) {
 
 sub GetFS ($$;$$$$) {
   my ($self, $system, $filesystem, $start, $end, $count, $interval) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   return
     unless $filesystem;
-    
+
   $interval ||= 'Minute';
-  
+
   my $size = $interval =~ /month/i
            ? 7
            : $interval =~ /day/i
@@ -896,16 +896,16 @@ sub GetFS ($$;$$$$) {
            : $interval =~ /hour/i
            ? 13
            : 16;
-    
+
   undef $start if $start and $start =~ /earliest/i;
   undef $end   if $end   and $end   =~ /latest/i;
-  
+
   my $condition  = "system='$system' and filesystem='$filesystem'";
      $condition .= " and timestamp>='$start'" if $start;
      $condition .= " and timestamp<='$end'"   if $end;
-     
+
      $condition .= " group by left(timestamp,$size)";
-  
+
   if ($count) {
     # We can't simply do a "limit 0, $count" as that just gets the front end of
     # the records return (i.e. if $count = say 10 and the timestamp range
@@ -914,14 +914,14 @@ sub GetFS ($$;$$$$) {
     # $count
     my $nbrRecs = $self->Count ('fs', $condition);
     my $offset  = $nbrRecs - $count;
-  
+
     # Offsets of < 0 are not allowed.
     $offset = 0
       if $offset < 0;
 
     $condition .= " limit $offset, $count";
   } # if
-       
+
   my $statement = <<"END";
 select
   system,
@@ -938,49 +938,49 @@ from
 END
 
   my ($err, $msg);
-  
+
   my $sth = $self->{db}->prepare ($statement);
-  
+
   unless ($sth) {
     ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my $status = $sth->execute;
-  
+
   unless ($status) {
     ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my @records;
-  
+
   while (my $row = $sth->fetchrow_hashref) {
     push @records, $row;
   } # while
-  
+
   return @records;
 } # GetFS
 
 sub GetLatestFS ($$) {
   my ($self, $system, $filesystem) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   return
     unless $filesystem;
-    
+
   my @records = $self->_getRecords (
     'fs',
     "system='$system' and filesystem='$filesystem'"
   . " order by timestamp desc limit 0, 1",
   );
-  
+
   if ($records[0]) {
        return %{$records[0]};
   } else {
@@ -990,32 +990,32 @@ sub GetLatestFS ($$) {
 
 sub AddLoadavg () {
   my ($self, %loadavg) = @_;
-  
+
   my @requiredFields = (
     'system',
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%loadavg;
-  
+
   return -1, "AddLoadavg: $result"
     if $result;
-  
+
   # Timestamp record
   $loadavg{timestamp} = Today2SQLDatetime;
-  
+
   return $self->_addRecord ('loadavg', %loadavg);
 } # AddLoadavg
 
 sub GetLoadavg ($;$$$$) {
   my ($self, $system, $start, $end, $count, $interval) = @_;
-           
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   $interval ||= 'Minute';
-  
+
   my $size = $interval =~ /month/i
            ? 7
            : $interval =~ /day/i
@@ -1023,16 +1023,16 @@ sub GetLoadavg ($;$$$$) {
            : $interval =~ /hour/i
            ? 13
            : 16;
-    
+
   my $condition;
-  
+
   undef $start if $start and $start =~ /earliest/i;
   undef $end   if $end   and $end   =~ /latest/i;
-  
+
   $condition .= " system='$system'"        if $system;
   $condition .= " and timestamp>='$start'" if $start;
   $condition .= " and timestamp<='$end'"   if $end;
-  
+
   $condition .= " group by left(timestamp,$size)";
 
   if ($count) {
@@ -1043,14 +1043,14 @@ sub GetLoadavg ($;$$$$) {
     # $count
     my $nbrRecs = $self->Count ('loadavg', $condition);
     my $offset  = $nbrRecs - $count;
-  
+
     # Offsets of < 0 are not allowed.
     $offset = 0
       if $offset < 0;
 
     $condition .= " limit $offset, $count";
   } # if
-        
+
   my $statement = <<"END";
 select
   system,
@@ -1064,46 +1064,46 @@ from
 END
 
   my ($err, $msg);
-  
+
   my $sth = $self->{db}->prepare ($statement);
-  
+
   unless ($sth) {
     ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my $status = $sth->execute;
-  
+
   unless ($status) {
     ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my @records;
-  
+
   while (my $row = $sth->fetchrow_hashref) {
     push @records, $row;
   } # while
-  
+
   return @records;
 } # GetLoadvg
 
 sub GetLatestLoadavg ($) {
   my ($self, $system) = @_;
-  
+
   $system = $self->_aliasSystem ($system);
-  
+
   return
     unless $system;
-    
+
   my @records = $self->_getRecords (
     'loadavg',
     "system='$system'"
   . " order by timestamp desc limit 0, 1",
   );
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
@@ -1113,123 +1113,123 @@ sub GetLatestLoadavg ($) {
 
 sub AddTask (%) {
   my ($self, %task) = @_;
-  
+
   my @requiredFields = (
     'name',
     'command'
   );
-  
+
   my $result = _checkRequiredFields \@requiredFields, \%task;
-  
+
   return -1, "AddTask: $result"
     if $result;
-  
-  return $self->_addRecord ('task', %task);    
+
+  return $self->_addRecord ('task', %task);
 } # AddTask
 
 sub DeleteTask ($) {
   my ($self, $name) = @_;
-  
+
   return $self->_deleteRecord ('task', "name='$name'");
 } # DeleteTask
 
 sub FindTask ($) {
   my ($self, $name) = @_;
-  
+
   $name ||= '';
-  
+
   my $condition = "name like '%$name%'";
-                
+
   return $self->_getRecords ('task', $condition);
 } # FindTask
 
 sub GetTask ($) {
   my ($self, $name) = @_;
-  
+
   return
     unless $name;
-  
+
   my @records = $self->_getRecords ('task', "name='$name'");
 
   if ($records[0]) {
     return %{$records[0]};
   } else {
     return;
-  } # if  
+  } # if
 } # GetTask
 
 sub UpdateTask ($%) {
   my ($self, $name, %update) = @_;
-  
+
   return $self->_updateRecord ('task', "name='$name'", %update);
 } # Update
 
 sub AddSchedule (%) {
   my ($self, %schedule) = @_;
-  
+
   my @requiredFields = (
     'task',
   );
-  
+
   my $result = _checkRequiredFields \@requiredFields, \%schedule;
-  
+
   return -1, "AddSchedule: $result"
     if $result;
-  
-  return $self->_addRecord ('schedule', %schedule);    
+
+  return $self->_addRecord ('schedule', %schedule);
 } # AddSchedule
 
 sub DeleteSchedule ($) {
   my ($self, $name) = @_;
-  
+
   return $self->_deleteRecord ('schedule', "name='$name'");
 } # DeleteSchedule
 
 sub FindSchedule (;$$) {
   my ($self, $name, $task) = @_;
-  
+
   $name ||= '';
   $task||= '';
-  
+
   my $condition  = "name like '%$name%'";
      $condition .= ' and ';
      $condition .= "task like '%$task%'";
 
-  return $self->_getRecords ('schedule', $condition); 
+  return $self->_getRecords ('schedule', $condition);
 } # FindSchedule
 
 sub GetSchedule ($) {
   my ($self, $name) = @_;
-  
+
   my @records = $self->_getRecords ('schedule', "name='$name'");
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
     return;
-  } # if  
+  } # if
 } # GetSchedule
 
 sub UpdateSchedule ($%) {
   my ($self, $name, %update) = @_;
-  
+
   return $self->_updateRecord ('schedule', "name='$name'", %update);
 } # UpdateSchedule
 
 sub AddRunlog (%) {
   my ($self, %runlog) = @_;
-  
+
   my @requiredFields = (
     'task',
   );
-  
+
   my $result = _checkRequiredFields \@requiredFields, \%runlog;
-  
+
   return -1, "AddRunlog: $result"
     if $result;
-  
+
   $runlog{ended} = Today2SQLDatetime;
-  
+
   my ($err, $msg) = $self->_addRecord ('runlog', %runlog);
 
   return ($err, $msg, $self->_getLastID);
@@ -1237,29 +1237,29 @@ sub AddRunlog (%) {
 
 sub DeleteRunlog ($) {
   my ($self, $condition) = @_;
-  
+
   return $self->_deleteRecord ('runlog', $condition);
 } # DeleteRunlog
 
 sub FindRunlog (;$$$$$$) {
   my ($self, $task, $system, $status, $id, $start, $page) = @_;
-  
+
   $task ||= '';
-  
+
   # If ID is specified then that's all that really matters as it uniquely
   # identifies a runlog entry;
   my $condition;
-  
+
   unless ($id) {
     $condition  = "task like '%$task%'";
-    
+
     if ($system) {
       $condition .= " and system like '%$system%'"
         unless $system eq 'All';
     } else {
       $condition .= ' and system is null';
     } # unless
-        
+
     if (defined $status) {
       if ($status =~ /!(-*\d+)/) {
         $condition .= " and status<>$1";
@@ -1267,9 +1267,9 @@ sub FindRunlog (;$$$$$$) {
         $condition .= " and status=$status"
       } # if
     } # if
-    
-    $condition .= " order by started desc"; 
-    
+
+    $condition .= " order by started desc";
+
     if (defined $start) {
       $page ||= 10;
       $condition .= " limit $start, $page";
@@ -1277,60 +1277,60 @@ sub FindRunlog (;$$$$$$) {
   } else {
     $condition = "id=$id";
   } # unless
-  
+
   return $self->_getRecords ('runlog', $condition);
 } # FindRunlog
 
 sub GetRunlog ($) {
   my ($self, $id) = @_;
-  
+
   return
     unless $id;
-  
+
   my @records = $self->_getRecords ('runlog', "id=$id");
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
     return;
-  } # if  
+  } # if
 } # GetRunlog
 
 sub UpdateRunlog ($%) {
   my ($self, $id, %update) = @_;
-  
+
   return $self->_updateRecord ('runlog', "id=$id", %update);
 } # UpdateRunlog
 
 sub Count ($;$) {
   my ($self, $table, $condition) = @_;
-  
+
   $condition = $condition ? 'where ' . $condition : '';
-    
+
   my ($err, $msg);
-  
+
   my $statement = "select count(*) from $table $condition";
-  
+
   my $sth = $self->{db}->prepare ($statement);
-  
+
   unless ($sth) {
     ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my $status = $sth->execute;
-  
+
   unless ($status) {
     ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   # Hack! Statements such as the following:
   #
   # select count(*) from fs where system='jupiter' and filesystem='/dev/sdb5'
-  # > group by left(timestamp,10);                    
+  # > group by left(timestamp,10);
   # +----------+
   # | count(*) |
   # +----------+
@@ -1343,7 +1343,7 @@ sub Count ($;$) {
   # |      190 |
   # +----------+
   # 7 rows in set (0.00 sec)
-  # 
+  #
   # Here we want 7 but what we see in $records[0] is 49. So the hack is that if
   # statement contains "group by" then we assume we have the above and return
   # scalar @records, otherwise we return $records[0];
@@ -1365,9 +1365,9 @@ sub Count ($;$) {
 # us again.
 sub GetWork () {
   my ($self) = @_;
-  
+
   my ($err, $msg);
-  
+
   my $statement = <<"END";
 select
   schedule.name as schedulename,
@@ -1385,43 +1385,43 @@ where
   and schedule.active='true'
 order by lastrun
 END
-     
+
   my $sth = $self->{db}->prepare ($statement);
-  
+
   unless ($sth) {
     ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my $status = $sth->execute;
-  
+
   unless ($status) {
     ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement);
-    
+
     croak $msg;
   } # if
-  
-  my $sleep;  
+
+  my $sleep;
   my @records;
-  
+
   while (my $row = $sth->fetchrow_hashref) {
    if ($$row{system} !~ /localhost/i) {
      my %system = $self->GetSystem ($$row{system});
-    
+
      # Skip inactive systems
      next if $system{active} eq 'false';
    } # if
-    
+
     # If started is not defined then this task was never run so run it now.
     unless ($$row{lastrun}) {
       push @records, $row;
       next;
     } # unless
-    
+
     # TODO: Handle frequencies better.
     my $seconds;
-    
+
     if ($$row{frequency} =~ /(\d+) seconds/i) {
       $seconds = $1;
     } elsif ($$row{frequency} =~ /(\d+) minute/i) {
@@ -1434,23 +1434,23 @@ END
       warning "Don't know how to handle frequencies like $$row{frequency}";
       next;
     } # if
-    
+
     my $today    = Today2SQLDatetime;
     my $lastrun  = Add ($$row{lastrun}, (seconds => $seconds));
     my $waitTime = DateToEpoch ($lastrun) - DateToEpoch ($today);
-      
+
     if ($waitTime < 0) {
       # We're late - push this onto records and move on
       push @records, $row;
     } # if
-    
+
     $sleep ||= $waitTime;
-    
+
     if ($sleep > $waitTime) {
       $sleep = $waitTime;
     } # if
   } # while
-  
+
   # Even if there is nothing to do the caller should sleep a bit and come back
   # to us. So if it ends up there's nothing past due, and nothing upcoming, then
   # sleep for a minute and return here. Somebody may have added a new task next
@@ -1458,91 +1458,91 @@ END
   if (@records == 0 and not $sleep) {
     $sleep = 60;
   } # if
-  
-  return ($sleep, @records);  
+
+  return ($sleep, @records);
 } # GetWork
 
 sub GetUniqueList ($$) {
   my ($self, $table, $field) = @_;
-  
+
   my ($err, $msg);
-  
+
   my $statement = "select $field from $table group by $field";
-  
+
   my $sth = $self->{db}->prepare ($statement);
-  
+
   unless ($sth) {
     ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement);
-    
+
     croak $msg;
   } # if
-    
+
   my $status = $sth->execute;
-  
+
   unless ($status) {
     ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement);
-    
+
     croak $msg;
   } # if
 
   my @values;
-  
+
   while (my @row = $sth->fetchrow_array) {
     if ($row[0]) {
       push @values, $row[0];
     } else {
       push @values, '<NULL>';
     } # if
-  } # foreach
+  } # for
 
   return @values;
 } # GetUniqueList
 
 sub AddAlert(%) {
   my ($self, %alert) = @_;
-  
+
   my @requiredFields = (
     'name',
     'type',
   );
-  
+
   my $result = _checkRequiredFields \@requiredFields, \%alert;
-  
+
   return -1, "AddAlert: $result"
     if $result;
-  
-  return $self->_addRecord ('alert', %alert);  
+
+  return $self->_addRecord ('alert', %alert);
 } # AddAlert
 
 sub DeleteAlert ($) {
   my ($self, $name) = @_;
-  
+
   return $self->_deleteRecord ('alert', "name='$name'");
 } # DeleteAlert
 
 sub FindAlert (;$) {
   my ($self, $alert) = @_;
-  
+
   $alert ||= '';
-  
+
   my $condition = "name like '%$alert%'";
-    
-  return $self->_getRecords ('alert', $condition);                
+
+  return $self->_getRecords ('alert', $condition);
 } # FindAlert
 
 sub GetAlert ($) {
   my ($self, $name) = @_;
-  
+
   return
     unless $name;
-  
+
   my @records = $self->_getRecords ('alert', "name='$name'");
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
     return;
-  } # if  
+  } # if
 } # GetAlert
 
 sub SendAlert ($$$$$$$) {
@@ -1556,25 +1556,25 @@ sub SendAlert ($$$$$$$) {
     $to,
     $runlogID,
   ) = @_;
-  
+
   my $footing  = '<hr><p style="text-align: center;">';
      $footing .= '<font color="#bbbbbb">';
   my $year     = (localtime)[5] + 1900;
-     $footing .= "<a href='$CLEAROPTS{CLEARADM_WEBBASE}'>Clearadm</a><br>"; 
+     $footing .= "<a href='$CLEAROPTS{CLEARADM_WEBBASE}'>Clearadm</a><br>";
      $footing .= "Copyright &copy; $year, ClearSCM, Inc. - All rights reserved";
+
   my %alert = $self->GetAlert ($alert);
-  
+
   if ($alert{type} eq 'email') {
     my $from = 'Clearadm@' . hostdomain;
-    
+
     mail (
       from    => $from,
       to      => $to,
       subject => "Clearadm Alert: $system: $subject",
       mode    => 'html',
-      data    => $message, 
-      footing => $footing,     
+      data    => $message,
+      footing => $footing,
     );
   } else {
     $self->Error ("Don't know how to send $alert{type} alerts\n"
@@ -1589,40 +1589,40 @@ sub SendAlert ($$$$$$$) {
     notification => $notification,
     runlog       => $runlogID,
     timestamp    => Today2SQLDatetime,
-    message      => $subject,  
-  );  
-  
+    message      => $subject,
+  );
+
   return $self->AddAlertlog (%alertlog);
 } # SendAlert
 
 sub GetLastAlert ($$) {
   my ($self, $notification, $system) = @_;
-  
+
   my $statement = <<"END";
 select
   runlog,
   timestamp
-from 
+from
   alertlog
 where
       notification='$notification'
   and system='$system'
 order by
   timestamp desc
-limit 
+limit
   0, 1
 END
-                
+
   my $sth = $self->{db}->prepare ($statement)
     or return $self->_dberror ('Unable to prepare statement', $statement);
-    
+
   $sth->execute
     or return $self->_dberror ('Unable to execute statement', $statement);
-    
+
   my $alertlog= $sth->fetchrow_hashref;
-  
+
   $sth->finish;
-  
+
   if ($alertlog) {
     return %$alertlog;
   } else {
@@ -1632,38 +1632,38 @@ END
 
 sub GetLastTaskFailure ($$) {
   my ($self, $task, $system) = @_;
-  
+
   my $statement = <<"END";
 select
   id,
   ended
-from 
+from
   runlog
 where
-      status <> 0 
+      status <> 0
   and task='$task'
   and system='$system'
   and alerted='true'
 order by
   ended desc
-limit 
+limit
   0, 1
 END
-                
+
   my $sth = $self->{db}->prepare ($statement)
     or return $self->_dberror ('Unable to prepare statement', $statement);
-    
+
   $sth->execute
     or return $self->_dberror ('Unable to execute statement', $statement);
-    
+
   my $runlog= $sth->fetchrow_hashref;
-  
+
   $sth->finish;
-  
+
   if ($$runlog{ended}) {
     return %$runlog;
   } # if
-  
+
   # If we didn't get any ended in the last call then there's nothing that
   # qualified. Still let's return a record (%runlog) that has a valid id so
   # that the caller can update that runlog with alerted = 'true'.
@@ -1676,7 +1676,7 @@ where
       status <> 0
   and task='$task'
   and system='$system'
-order by 
+order by
   ended desc
 limit
   0, 1
@@ -1684,20 +1684,20 @@ END
 
   $sth = $self->{db}->prepare ($statement)
     or return $self->_dberror ('Unable to prepare statement', $statement);
-      
+
   $sth->execute
     or return $self->_dberror ('Unable to execute statement', $statement);
-      
+
   $runlog = $sth->fetchrow_hashref;
-    
+
   $sth->finish;
-    
+
   if ($runlog) {
     return %$runlog;
   } else {
     return
   } # if
-} # GetLastTaskFailure 
+} # GetLastTaskFailure
 
 sub Notify ($$$$$$) {
   my (
@@ -1713,9 +1713,9 @@ sub Notify ($$$$$$) {
 
   $runlogID = $self->_getLastID
     unless $runlogID;
-    
+
   my ($err, $msg);
-  
+
   # Update filesystem, if $filesystem was specified
   if ($filesystem) {
     ($err, $msg) = $self->UpdateFilesystem (
@@ -1724,26 +1724,26 @@ sub Notify ($$$$$$) {
         notification => $notification,
       ),
     );
-    
+
     $self->Error ("Unable to set notification for filesystem $system:$filesystem "
                . "(Status: $err)\n$msg", $err) if $err;
   } # if
-  
+
   # Update system
   ($err, $msg) = $self->UpdateSystem (
     $system, (
       notification => $notification,
     ),
   );
-  
+
   my %notification = $self->GetNotification ($notification);
-  
+
   my %lastnotified = $self->GetLastAlert ($notification, $system);
-  
+
   if (%lastnotified and $lastnotified{timestamp}) {
     my $today        = Today2SQLDatetime;
     my $lastnotified = $lastnotified{timestamp};
-      
+
     if ($notification{nomorethan} =~ /hour/i) {
       $lastnotified = Add ($lastnotified, (hours => 1));
     } elsif ($notification{nomorethan} =~ /day/i) {
@@ -1753,13 +1753,13 @@ sub Notify ($$$$$$) {
     } elsif ($notification{nomorethan} =~ /month/i) {
       $lastnotified = Add ($lastnotified, (month => 1));
     } # if
-      
+
     # If you want to fake an alert in the debugger just change $diff accordingly
     my $diff = Compare ($today, $lastnotified);
-    
+
     return
       if $diff <= 0;
-  } # if  
+  } # if
 
   my $when       = Today2SQLDatetime;
   my $nomorethan = lc $notification{nomorethan};
@@ -1771,7 +1771,7 @@ sub Notify ($$$$$$) {
   unless ($to) {
     if ($system) {
       my %system = $self->GetSystem ($system);
-    
+
       $to = $system{email};
     } else {
       # If we don't know what system this error occurred on we'll have to notify
@@ -1780,13 +1780,13 @@ sub Notify ($$$$$$) {
       $to = $self->{NOTIFY};
     } # if
   } # unless
-  
+
   unless ($to) {
     Error "To undefined";
   } # unless
-  
+
   $message .= "<p>You will receive this alert no more than $nomorethan.</p>";
-  
+
   ($err, $msg) = $self->SendAlert (
     $notification{alert},
     $system,
@@ -1796,7 +1796,7 @@ sub Notify ($$$$$$) {
     $to,
     $runlogID,
   );
+
   $self->Error ("Unable to send alert (Status: $err)\n$msg", $err) if $err;
 
   verbose "Sent alert to $to";
@@ -1807,44 +1807,44 @@ sub Notify ($$$$$$) {
       alerted => 'true',
     ),
   );
-  
+
   $self->Error ("Unable to update runlog (Status: $err)\n$msg", $err) if $err;
 
-  return;  
+  return;
 } # Notify
 
 sub ClearNotifications ($$;$) {
   my ($self, $system, $filesystem) = @_;
-  
+
   my ($err, $msg);
-  
+
   if ($filesystem) {
     ($err, $msg) = $self->UpdateFilesystem (
       $system,
       $filesystem, (notification => undef),
     );
-    
+
     error "Unable to clear notification for filesystem $system:$filesystem "
         . "(Status: $err)\n$msg", $err
       if $err;
-    
+
     # Check to see any of this system's filesystems have notifications. If none
-    # then it's save to say we've turned off the last notification for a 
+    # then it's save to say we've turned off the last notification for a
     # filesystem involved with this system and if $system{notification} was
     # 'Filesystem' then we can toggle off the notification on the system too
     my $filesystemsAlerted = 0;
-    
-    foreach ($self->FindFilesystem ($system)) {
-      $filesystemsAlerted++ 
+
+    for ($self->FindFilesystem ($system)) {
+      $filesystemsAlerted++
         if $$_{notification};
-    } # foreach
-    
+    } # for
+
     my %system = $self->GetSystem ($system);
-    
+
     return
       unless $system;
-      
-    if ($system{notification}                 and 
+
+    if ($system{notification}                 and
         $system{notification} eq 'Filesystem' and
         $filesystemsAlerted == 0) {
       ($err, $msg) = $self->UpdateSystem ($system, (notification => undef));
@@ -1854,11 +1854,11 @@ sub ClearNotifications ($$;$) {
     } # if
   } else {
     ($err, $msg) = $self->UpdateSystem ($system, (notification => undef));
-       
+
     $self->Error ("Unable to clear notification for system $system "
                 . "(Status: $err)\n$msg", $err) if $err;
   } # if
-  
+
   return;
 } # ClearNotifications
 
@@ -1867,20 +1867,20 @@ sub SystemAlive (%) {
 
   # If we've never heard from this system then we will assume that the system
   # has not been set up to run clearagent and has never checked in. In any event
-  # we cannot say the system died because we've never known it to be alive!  
+  # we cannot say the system died because we've never known it to be alive!
   return 1
     unless $system{lastheardfrom};
-    
+
   # If a system is not active (may have been temporarily been deactivated) then
   # we don't want to turn on the bells and whistles alerting people it's down.
   return 1
     if $system{active} eq 'false';
-    
+
   my $today         = Today2SQLDatetime;
   my $lastheardfrom = $system{lastheardfrom};
-      
+
   my $tenMinutes = 10 * 60;
-  
+
   $lastheardfrom = Add ($lastheardfrom, (seconds => $tenMinutes));
 
   if (DateToEpoch ($lastheardfrom) < DateToEpoch ($today)) {
@@ -1889,7 +1889,7 @@ sub SystemAlive (%) {
         notification => 'Heartbeat'
       ),
     );
-   
+
     return;
   } else {
     if ($system{notification}) {
@@ -1905,7 +1905,7 @@ sub SystemAlive (%) {
 
 sub UpdateAlert ($%) {
   my ($self, $name, %update) = @_;
-  
+
   return $self->_updateRecord (
     'alert',
     "name='$name'",
@@ -1915,29 +1915,29 @@ sub UpdateAlert ($%) {
 
 sub AddAlertlog (%) {
   my ($self, %alertlog) = @_;
-  
+
   my @requiredFields = (
     'alert',
     'notification',
   );
-  
+
   my $result = _checkRequiredFields \@requiredFields, \%alertlog;
-  
+
   return -1, "AddAlertlog: $result"
     if $result;
-  
+
   # Timestamp record
   $alertlog{timestamp} = Today2SQLDatetime;
-  
-  return $self->_addRecord ('alertlog', %alertlog);  
+
+  return $self->_addRecord ('alertlog', %alertlog);
 } # AddAlertlog
 
 sub DeleteAlertlog ($) {
   my ($self, $condition) = @_;
-  
+
   return
     unless $condition;
-    
+
   if ($condition =~ /all/i) {
     return $self->_deleteRecord ('alertlog');
   } else {
@@ -1947,18 +1947,18 @@ sub DeleteAlertlog ($) {
 
 sub FindAlertlog (;$$$$$) {
   my ($self, $alert, $system, $notification, $start, $page) = @_;
-  
+
   $alert        ||= '';
   $system       ||= '';
   $notification ||= '';
-  
+
   my $condition  = "alert like '%$alert%'";
      $condition .= ' and ';
      $condition .= "system like '%$system%'";
      $condition .= ' and ';
      $condition .= "notification like '%$notification%'";
      $condition .= " order by timestamp desc";
-     
+
      if (defined $start) {
        $page ||= 10;
        $condition .= " limit $start, $page";
@@ -1969,22 +1969,22 @@ sub FindAlertlog (;$$$$$) {
 
 sub GetAlertlog ($) {
   my ($self, $alert) = @_;
-  
+
   return
     unless $alert;
-  
+
   my @records = $self->_getRecords ('alertlog', "alert='$alert'");
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
     return;
-  } # if  
+  } # if
 } # GetAlertlog
 
 sub UpdateAlertlog ($%) {
   my ($self, $alert, %update) = @_;
-  
+
   return $self->_updateRecord (
     'alertlog',
     "alert='$alert'",
@@ -1994,57 +1994,57 @@ sub UpdateAlertlog ($%) {
 
 sub AddNotification (%) {
   my ($self, %notification) = @_;
-  
+
   my @requiredFields = (
     'name',
     'alert',
     'cond'
   );
-  
+
   my $result = _checkRequiredFields \@requiredFields, \%notification;
-  
+
   return -1, "AddNotification: $result"
     if $result;
-  
-  return $self->_addRecord ('notification', %notification);  
+
+  return $self->_addRecord ('notification', %notification);
 } # AddNotification
 
 sub DeleteNotification ($) {
   my ($self, $name) = @_;
-  
+
   return $self->_deleteRecord ('notification', "name='$name'");
 } # DeletePackage
 
 sub FindNotification (;$$) {
   my ($self, $name, $cond, $ordering) = @_;
-  
+
   $name ||= '';
-  
+
   my $condition  = "name like '%$name%'";
      $condition .= " and $cond"
        if $cond;
-  
-  return $self->_getRecords ('notification', $condition);                
+
+  return $self->_getRecords ('notification', $condition);
 } # FindNotification
 
 sub GetNotification ($) {
   my ($self, $name) = @_;
-  
+
   return
     unless $name;
-  
+
   my @records = $self->_getRecords ('notification', "name='$name'");
-  
+
   if ($records[0]) {
     return %{$records[0]};
   } else {
     return;
-  } # if  
+  } # if
 } # GetNotification
 
 sub UpdateNotification ($%) {
   my ($self, $name, %update) = @_;
-  
+
   return $self->_updateRecord (
     'notification',
     "name='$name'",
@@ -2078,7 +2078,7 @@ L<Net::Domain|Net::Domain>
 
 =head2 ClearSCM Perl Modules
 
-=begin man 
+=begin man
 
  DateUtils
  Display
index d449473..17ccb6e 100644 (file)
@@ -48,7 +48,7 @@ use strict;
 use base 'Exporter';
 
 use CGI qw (
-  :standard 
+  :standard
    start_a
    end_a
    start_div
@@ -82,7 +82,7 @@ my $clearadm = Clearadm->new;
 our $APPNAME= 'Clearadm';
 our $VERSION  = '$Revision: 1.46 $';
    ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
-  
+
 our @EXPORT = qw (
   autoScale
   displayError
@@ -160,74 +160,74 @@ our @PREDEFINED_MULTIPLIERS = (
 
 sub dbug ($) {
   my ($msg) = @_;
-  
+
   display font ({-class => 'error'}, '<br>DEBUG: '). $msg;
-  
+
   return;
 } # dbug
 
 sub displayError ($) {
   my ($msg) = @_;
-  
+
   display font ({-class => 'error'}, 'Error: ') . $msg;
-  
+
   return
 } # displayError;
 
 sub setField ($;$) {
   my ($field, $label) = @_;
-  
+
   $label ||= 'Unknown';
 
   my $undef = font {-class => 'unknown'}, $label;
-  
+
   return defined $field ? $field : $undef;
 } # setField
 
 sub setFields ($%) {
   my ($label, %rec) = @_;
-  
+
   $rec{$_} = setField ($rec{$_}, $label)
     foreach keys %rec;
-    
+
   return %rec;
 } # setFields;
 
 sub dumpVars (%) {
   my (%vars) = @_;
-  
+
   foreach (keys %vars) {
     dbug "$_: $vars{$_}";
   } # foreach
-  
+
   return;
 } # dumpVars
 
 sub graphError ($) {
   my ($msg) = @_;
-  
+
   use GD;
-  
+
   # Make the image fit the message. It seems that characters are ~ 7px wide.
   my $imageLength = length ($msg) * 7;
-  
+
   my $errorImage = GD::Image->new ($imageLength, 20);
 
   # Allocate some colors
   my $white = $errorImage->colorAllocate (255, 255, 255);
   my $red   = $errorImage->colorAllocate (255, 0, 0);
-  
+
   # Allow the text to shine through
   $errorImage->transparent($white);
   $errorImage->interlaced('true');
 
-  # Now put out the message  
+  # Now put out the message
   $errorImage->string (gdMediumBoldFont, 0, 0, $msg, $red);
 
   # And return it
   print "Content-type: image/png\n\n";
   print $errorImage->png;
-  
+
   # Since we've "returned" the error in the form of an image, there's nothing
   # left for us to do so we can exit
   exit;
@@ -235,29 +235,29 @@ sub graphError ($) {
 
 sub autoScale ($) {
   my ($amount) = @_;
-  
+
   my $kbyte = 1024;
   my $meg   = (1024 * $kbyte);
   my $gig   = (1024 * $meg);
-  
+
   my $size = $amount > $gig
            ? sprintf ('%.2f Gig',   $amount / $gig)
            : $amount > $meg
            ? sprintf ('%.2f Meg',   $amount / $meg)
            : sprintf ('%.2f Kbyte', $amount / $kbyte);
-           
-  return $size;         
+
+  return $size;
 } # autoScale
 
 sub _makeAlertlogSelection ($$) {
   my ($name, $default) = @_;
-  
+
   $default ||= 'All';
 
   my %values;
 
   $values{All} = 'All';
-  
+
   $values{$$_{$name}} = $$_{$name}
     foreach ($clearadm->FindAlertlog);
 
@@ -266,128 +266,128 @@ sub _makeAlertlogSelection ($$) {
     class   => 'dropdown',
     values  => [sort keys %values],
     default => $default,
-  };  
-  
+  };
+
   return $dropdown;
 } # _makeAlertlogSelection
 
 sub _makeRunlogSelection ($$) {
   my ($name, $default) = @_;
-  
+
   $default ||= 'All';
 
   my @values = sort $clearadm->GetUniqueList ('runlog', $name);
-  
+
   unshift @values, 'All';
-  
+
   my %values;
-  
+
   foreach (@values) {
      unless ($_ eq '') {
        $values{$_} = $_;
      } else {
        $values{NULL} = '<NULL>';
-     } #if 
+     } #if
   } # foreach
-  
+
   my $dropdown = popup_menu {
     name    => $name,
     class   => 'dropdown',
     values  => \@values,
     default => $default,
     labels  => \%values,
-  };  
-  
+  };
+
   return $dropdown;
 } # _makeRunlogSelection
 
 sub _makeRunlogSelectionNumeric ($$) {
   my ($name, $default) = @_;
-  
+
   $default ||= 'All';
 
   my @values = sort {$a <=> $b} $clearadm->GetUniqueList ('runlog', $name);
-  
+
   unshift @values, 'All';
-  
+
   my $dropdown = popup_menu {
     name    => $name,
     class   => 'dropdown',
     values  => [@values],
     default => $default,
-  };  
-  
+  };
+
   return $dropdown;
 } # _makeRunlogSelection
 
 sub makeAlertDropdown (;$$) {
   my ($label, $default) = @_;
-  
+
   $label ||= '';
 
   my @values;
 
   push @values, $$_{name}
     foreach ($clearadm->FindAlert);
-  
+
   my $dropdown  = "$label ";
      $dropdown .= popup_menu {
     name    => 'alert',
     class   => 'dropdown',
     values  => [sort @values],
     default => $default,
-  };  
-  
+  };
+
   return $dropdown;
 } # makeAlertDropdown
 
 sub makeMultiplierDropdown (;$$) {
   my ($label, $default) = @_;
-  
+
   $label ||= '';
-  
+
   my $dropdown  = "$label ";
      $dropdown .= popup_menu {
     name    => 'multiplier',
     class   => 'dropdown',
     values  => [sort @PREDEFINED_MULTIPLIERS],
     default => $default,
-  };     
+  };
 
   return $dropdown;
 } # makeMultiplierDropdown
 
 sub makeNoMoreThanDropdown (;$$) {
   my ($label, $default) = @_;
-  
+
   $label ||= '';
-  
+
   my $dropdown  = "$label ";
      $dropdown .= popup_menu {
     name    => 'nomorethan',
     class   => 'dropdown',
     values  => [sort @PREDEFINED_NOTMORETHAN],
     default => $default,
-  };     
+  };
 
   return $dropdown;
 } # makeNoMorThanDropdown
+
 sub makeFilesystemDropdown ($;$$$) {
   my ($system, $label, $default, $onchange) = @_;
 
   $label ||= '';
-  
+
   my %filesystems;
-  
+
   foreach ($clearadm->FindFilesystem ($system)) {
     my %filesystem = %{$_};
-    
+
     my $value = "$filesystem{filesystem} ($filesystem{mount})";
 
     $filesystems{$filesystem{filesystem}} = $value;
   } # foreach
-  
+
   my $dropdown .= "$label ";
      $dropdown .= popup_menu {
     name     => 'filesystem',
@@ -397,15 +397,15 @@ sub makeFilesystemDropdown ($;$$$) {
     onChange => ($onchange) ? $onchange : '',
     default  => $default,
   };
-    
-  return span {id => 'filesystems'}, $dropdown;  
+
+  return span {id => 'filesystems'}, $dropdown;
 } # makeFilesystemDropdown
 
 sub makeIntervalDropdown (;$$$) {
   my ($label, $default, $onchange) = @_;
-  
+
   $label ||= '';
-  
+
   my @intervals = (
     'Minute',
     'Hour',
@@ -415,7 +415,7 @@ sub makeIntervalDropdown (;$$$) {
 
   $default = ucfirst lc $default
     if $default;
-  
+
   my $dropdown  = "$label ";
      $dropdown .= popup_menu {
     name     => 'scaling',
@@ -425,49 +425,49 @@ sub makeIntervalDropdown (;$$$) {
     default  => $default,
     onchange => $onchange,
   };
-   
-   return span {id => 'scaling'}, $dropdown; 
+
+   return span {id => 'scaling'}, $dropdown;
 } # makeIntervalDropdown;
 
 sub makeNotificationDropdown (;$$) {
   my ($label, $default) = @_;
-  
+
   $label ||= '';
 
   my @values;
-  
-  push @values, $$_{name} 
+
+  push @values, $$_{name}
     foreach ($clearadm->FindNotification);
-  
+
   my $dropdown  = "$label ";
      $dropdown .= popup_menu {
     name    => 'notification',
     class   => 'dropdown',
     values  => [sort @values],
     default => $default,
-  };  
-  
+  };
+
   return $dropdown;
 } # makeNotificationDropdown
 
 sub makeRestartableDropdown (;$$) {
   my ($label, $default) = @_;
-  
+
   $label ||= '';
 
   my @values = (
     'true',
     'false',
   );
-  
+
   my $dropdown  = "$label ";
      $dropdown .= popup_menu {
     name    => 'restartable',
     class   => 'dropdown',
     values  => [@values],
     default => $default,
-  };  
-  
+  };
+
   return $dropdown;
 } # makeRestartableDropdown
 
@@ -475,16 +475,16 @@ sub makeSystemDropdown (;$$$%) {
   my ($label, $default, $onchange, %systems) = @_;
 
   $label ||= '';
-  
+
   foreach ($clearadm->FindSystem) {
     my %system = %{$_};
-    
+
     my $value  = $system{name};
        $value .= $system{alias} ? " ($system{alias})" : '';
 
     $systems{$system{name}} = $value;
   } # foreach
-  
+
   my $systemDropdown .= "$label ";
      $systemDropdown .= popup_menu {
        name     => 'system',
@@ -494,28 +494,28 @@ sub makeSystemDropdown (;$$$%) {
        onchange => ($onchange) ? $onchange : '',
        default  => $default,
     };
-    
+
   return span {id => 'systems'}, $systemDropdown;
 } # makeSystemDropdown
 
 sub makeTaskDropdown (;$$) {
   my ($label, $default) = @_;
-  
+
   $label ||= '';
 
   my @values;
 
   push @values, $$_{name}
     foreach ($clearadm->FindTask);
-  
+
   my $taskDropdown  = "$label ";
      $taskDropdown .= popup_menu {
     name    => 'task',
     class   => 'dropdown',
     values  => [sort @values],
     default => $default,
-  };  
-  
+  };
+
   return $taskDropdown;
 } # makeTaskDropdown
 
@@ -532,11 +532,11 @@ sub makeTimeDropdown ($$$;$$$$$) {
   ) = @_;
 
   $label ||= '';
-    
+
   my @times;
-  
+
   $name ||= lc $label;
-  
+
   push @times, 'Earliest';
 
   if ($table =~ /loadavg/i) {
@@ -545,14 +545,14 @@ sub makeTimeDropdown ($$$;$$$$$) {
   } elsif ($table =~ /filesystem/i) {
     push @times, $$_{timestamp}
       foreach ($clearadm->GetFS ($system, $filesystem, undef, undef, undef, $interval));
-  } # if  
+  } # if
 
   push @times, 'Latest';
-  
+
   unless ($default) {
     $default = $name eq 'start' ? 'Earliest' : 'Latest';
   } # unless
-  
+
   my $timeDropdown = "$label ";
      $timeDropdown .= span {id => $elementID}, popup_menu {
     name    => $name,
@@ -560,8 +560,8 @@ sub makeTimeDropdown ($$$;$$$$$) {
     values  => [@times],
     default => $default,
   };
-  
-  return $timeDropdown;   
+
+  return $timeDropdown;
 } # makeTimeDropdown
 
 sub heading (;$$) {
@@ -572,7 +572,7 @@ sub heading (;$$) {
   } else {
     $title = $APPNAME;
   } # if
-  
+
   display header;
   display start_html {
        -title  => $title,
@@ -589,21 +589,21 @@ sub heading (;$$) {
   }, $title;
 
   return if $type;
-  
+
   my $ieTableWrapStart = '<!--[if gt IE 6]><!--></a><!--<![endif]--><!--'
                        . '[if lt IE 7]><table border="0" cellpadding="0" '
                        . 'cellspacing="0"><tr><td><![endif]-->';
   my $ieTableWrapEnd   = '<!--[if lte IE 6]></td></tr></table></a><![endif]-->';
-            
+
   # Menubar
   display div {id=>'mastheadlogo'}, h1 {class => 'title'}, $APPNAME;
   display start_div {class => 'menu'};
-  
+
   # Home
   display ul li a {href => '/clearadm'}, 'Home';
-  
+
   my @allSystems = $clearadm->FindSystem;
-  
+
   # Systems
   display start_ul;
     display start_li;
@@ -614,7 +614,7 @@ sub heading (;$$) {
             my $sysName  = ucfirst $system{name};
                $sysName .= " ($system{alias})"
                  if $system{alias};
-                 
+
             display li a {
               href => "systemdetails.cgi?system=$system{name}"
             }, ucfirst "&nbsp;$sysName";
@@ -624,7 +624,7 @@ sub heading (;$$) {
         display end_li;
     display end_li;
   display end_ul;
-  
+
   # Filesystems
   display start_ul;
     display start_li;
@@ -635,7 +635,7 @@ sub heading (;$$) {
             my $sysName  = ucfirst $system{name};
                $sysName .= " ($system{alias})"
                  if $system{alias};
-                             
+
             display li a {
               href => "filesystems.cgi?system=$system{name}"
             }, ucfirst "&nbsp;$sysName";
@@ -644,7 +644,7 @@ sub heading (;$$) {
         display $ieTableWrapEnd;
     display end_li;
   display end_ul;
-  
+
   # Servers
   display start_ul;
     display start_li;
@@ -658,7 +658,7 @@ sub heading (;$$) {
         display end_ul;
         display $ieTableWrapEnd;
         display end_li;
-        
+
         display start_li;
         display start_a {href => 'views.cgi'};
         display "<span class='drop'><span>View</span>&raquo;</span>$ieTableWrapStart";
@@ -671,7 +671,7 @@ sub heading (;$$) {
       display $ieTableWrapEnd;
     display end_li;
   display end_ul;
+
   # Vobs
   display start_ul;
     display start_li;
@@ -684,8 +684,8 @@ sub heading (;$$) {
       display end_ul;
       display $ieTableWrapEnd;
     display end_li;
-  display end_ul;  
-  
+  display end_ul;
+
   # Views
   display start_ul;
     display start_li;
@@ -696,7 +696,7 @@ sub heading (;$$) {
       display end_ul;
       display $ieTableWrapEnd;
     display end_li;
-  display end_ul;  
+  display end_ul;
 
   # Configure
   display start_ul;
@@ -710,8 +710,8 @@ sub heading (;$$) {
       display end_ul;
       display $ieTableWrapEnd;
     display end_li;
-  display end_ul;  
-  
+  display end_ul;
+
   # Logs
   display start_ul;
     display start_li;
@@ -722,8 +722,8 @@ sub heading (;$$) {
       display end_ul;
       display $ieTableWrapEnd;
     display end_li;
-  display end_ul;  
-        
+  display end_ul;
+
   # Help
   display start_ul;
     display start_li;
@@ -735,15 +735,15 @@ sub heading (;$$) {
     display end_li;
   display end_ul;
   display end_div;
-  
+
   display start_div {class => 'page'};
-  
+
   return;
 } # heading
 
 sub displayAlert (;$) {
   my ($alert) = @_;
-  
+
   display start_table {cellspacing => 1};
 
   display start_Tr;
@@ -753,15 +753,15 @@ sub displayAlert (;$) {
     display th {class => 'labelCentered'}, 'Who';
     display th {class => 'labelCentered'}, 'Category';
   display end_Tr;
-  
+
   foreach ($clearadm->FindAlert ($alert)) {
     my %alert = %{$_};
-   
+
     $alert{who} = setField $alert{who}, 'System Administrator';
-    
+
     display start_Tr;
       my $areYouSure = "Are you sure you want to delete the $alert{name} alert?";
-                   
+
       my $actions = start_form {
         method => 'post',
         action => 'processalert.cgi',
@@ -782,7 +782,7 @@ sub displayAlert (;$) {
           alt      => 'Delete',
           value    => 'Delete',
           title    => 'Cannot delete predefined alert',
-        };     
+        };
         $actions .= input {
           name     => 'edit',
           disabled => 'true',
@@ -812,10 +812,10 @@ sub displayAlert (;$) {
         };
       } # if
 
-      display end_form;     
+      display end_form;
 
       my $who = $alert{who};
-      
+
       if ($who =~ /^([a-zA-Z0-9._-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})$/) {
         $who = a {href => "mailto:$1\@$2"}, $who;
       } # if
@@ -829,8 +829,8 @@ sub displayAlert (;$) {
     display end_Tr;
   } # foreach
 
-  display end_table; 
-  
+  display end_table;
+
   display p {class => 'center'}, a {
     href => 'processalert.cgi?action=Add',
   }, 'New alert ', img {
@@ -843,18 +843,18 @@ sub displayAlert (;$) {
 
 sub displayAlertlog (%) {
   my (%opts) = @_;
-  
+
   my $optsChanged;
-  
+
   unless (($opts{oldalert}        and $opts{alert}         and
            $opts{oldalert}        eq  $opts{alert})        and
           ($opts{oldsystem}       and $opts{system}        and
            $opts{oldsystem}       eq  $opts{system})       and
           ($opts{oldnotification} and $opts{notification}  and
            $opts{oldnotification} eq  $opts{notification})) {
-    $optsChanged = 1;           
+    $optsChanged = 1;
   } # unless
-  
+
   my $condition;
 
   unless ($opts{id}) {
@@ -881,7 +881,7 @@ sub displayAlertlog (%) {
     $opts{start} = 0;
   } # if
 
-  my $next = $opts{start} + $opts{page} < $total 
+  my $next = $opts{start} + $opts{page} < $total
            ? $opts{start} + $opts{page}
            : $opts{start};
   my $prev = $opts{start} - $opts{page} >= 0
@@ -896,14 +896,14 @@ sub displayAlertlog (%) {
      $opts .= " of $total";
 
   display start_form {
-    method => 'post', 
+    method => 'post',
     action => 'alertlog.cgi'
   };
 
   # Hidden fields to pass along
   display input {name  => 'prev', type  => 'hidden', value => $prev};
   display input {name  => 'next', type  => 'hidden', value => $next};
-  
+
   display input {
     name  => 'oldalert',
     type  => 'hidden',
@@ -942,7 +942,7 @@ sub displayAlertlog (%) {
         disabled => 'disabled',
       };
     } # unless
-  
+
     $caption .= td {align => 'center'}, $opts;
 
     unless ($opts{id}) {
@@ -1013,9 +1013,9 @@ sub displayAlertlog (%) {
       type    => 'button',
       value   => 'Clear All Events',
       onclick => "return AreYouSure('Are you sure you want to delete all alerts?');",
-    }; 
+    };
   display end_Tr;
-  
+
   my $i = $opts{start};
 
   foreach ($clearadm->FindAlertlog (
@@ -1026,10 +1026,10 @@ sub displayAlertlog (%) {
     $opts{page},
     )) {
     my %alertlog = setFields 'N/A', %{$_};
-     
+
     display start_Tr;
       my %system = $clearadm->GetSystem ($alertlog{system});
-    
+
       display td {class => 'dataCentered'}, ++$i;
       display td {class => 'dataCentered'}, a {
         href => "deletealertlog.cgi?alertlogid=$alertlog{id}"
@@ -1059,8 +1059,8 @@ sub displayAlertlog (%) {
 
   display end_form;
 
-  display end_table; 
-  
+  display end_table;
+
   return;
 } # displayAlertlog
 
@@ -1068,7 +1068,7 @@ sub displayFilesystem ($) {
   my ($systemName) = @_;
 
   display start_table {cellspacing => 1, width => '98%'};
-  
+
   display start_Tr;
     display th {class => 'labelCentered'}, 'Action';
     display th {class => 'labelCentered'}, 'Name';
@@ -1082,16 +1082,16 @@ sub displayFilesystem ($) {
     display th {class => 'labelCentered'}, 'Threshold';
     display th {class => 'labelCentered'}, 'Usage';
   display end_Tr;
-  
+
   foreach ($clearadm->FindSystem ($systemName)) {
     my %system = %{$_};
-  
+
     %system = setFields ('N/A', %system);
 
     my $admin = ($system{email} !~ 'N/A')
               ? a {-href => "mailto:$system{email}"}, $system{admin}
               : $system{admin};
-              
+
     foreach ($clearadm->FindFilesystem ($system{name})) {
       my %filesystem = %{$_};
 
@@ -1101,9 +1101,9 @@ sub displayFilesystem ($) {
       my $used = autoScale $fs{used};
       my $free = autoScale $fs{free};
 
-      # TODO: Note that this percentages does not agree with df output. I'm not 
+      # TODO: Note that this percentages does not agree with df output. I'm not
       # sure why.
-      my $usedPct = $fs{size} == 0 ? 0 
+      my $usedPct = $fs{size} == 0 ? 0
                   : sprintf ('%.0f',
                      (($fs{reserve} + $fs{used}) / $fs{size} * 100));
 
@@ -1112,19 +1112,19 @@ sub displayFilesystem ($) {
                     href => "systemdetails.cgi?system=$system{name}"
                   }, $system{alias}
                 : $system{alias};
-                  
-      my $class         = $usedPct < $filesystem{threshold} 
+
+      my $class         = $usedPct < $filesystem{threshold}
                         ? 'data'
                         : 'dataAlert';
-      my $classRight    = $usedPct < $filesystem{threshold} 
+      my $classRight    = $usedPct < $filesystem{threshold}
                         ? 'dataRight'
                         : 'dataRightAlert';
-      my $classCentered = $usedPct < $filesystem{threshold} 
+      my $classCentered = $usedPct < $filesystem{threshold}
                         ? 'dataCentered'
                         : 'dataCenteredAlert';
       my $classRightTop = $usedPct < $filesystem{threshold}
                         ? 'dataRightTop'
-                        : 'dataRightAlertTop'; 
+                        : 'dataRightAlertTop';
 
       display start_Tr;
         display start_td {class => 'dataCentered'};
@@ -1138,7 +1138,7 @@ sub displayFilesystem ($) {
           method => 'post',
           action => "processfilesystem.cgi",
         };
-        
+
         display input {
           type  => 'hidden',
           name  => 'system',
@@ -1149,7 +1149,7 @@ sub displayFilesystem ($) {
           name  => 'filesystem',
           value => $filesystem{filesystem},
         };
-        
+
         display input {
           name    => 'delete',
           type    => 'image',
@@ -1167,20 +1167,20 @@ sub displayFilesystem ($) {
           value   => 'Edit',
           title   => 'Edit',
         };
-        
+
         if ($filesystem{notification}) {
           display a {
             href => "alertlog.cgi?system=$filesystem{system}"}, img {
             src    => 'alert.png',
             border => 0,
             alt    => 'Alert!',
-            title  => 'This filesystem has alerts', 
+            title  => 'This filesystem has alerts',
           };
-        } # if        
-                
+        } # if
+
         display end_form;
-        
-        display end_td;      
+
+        display end_td;
         display td {class => $class},
           a {-href => "systemdetails.cgi?system=$system{name}"}, $system{name};
         display td {class => $class}, $alias;
@@ -1189,11 +1189,11 @@ sub displayFilesystem ($) {
         display td {class => $class}, $filesystem{mount};
         display td {class => $class}, $filesystem{fstype};
         display td {class => $classCentered}, $filesystem{filesystemHist};
-        display td {class => $classRightTop}, "$used ($usedPct%)<br>", 
+        display td {class => $classRightTop}, "$used ($usedPct%)<br>",
           font {class => 'unknown'}, "$fs{timestamp}";
         display td {class => $classRightTop}, "$filesystem{threshold}%";
         display td {class => $class},
-          a {href => 
+          a {href =>
             "plot.cgi?type=filesystem&system=$system{name}"
           . "&filesystem=$filesystem{filesystem}&scaling=Day&points=7"
           }, img {
@@ -1206,13 +1206,13 @@ sub displayFilesystem ($) {
   } # foreach
 
   display end_table;
-  
+
   return;
 } # displayFilesystem
 
 sub displayNotification (;$) {
   my ($notification) = @_;
-  
+
   display start_table {cellspacing => 1};
 
   display start_Tr;
@@ -1223,14 +1223,14 @@ sub displayNotification (;$) {
     display th {class => 'labelCentered'}, 'Not More Than';
     display th {class => 'labelCentered'}, 'Category';
   display end_Tr;
-  
+
   foreach ($clearadm->FindNotification ($notification)) {
     my %notification= setFields 'N/A', %{$_};
-  
+
     display start_Tr;
     my $areYouSure = "Are you sure you want to delete the $notification{name} "
                    . 'notification?';
-                   
+
     my $actions = start_form {
       method => 'post',
       action => 'processnotification.cgi',
@@ -1241,7 +1241,7 @@ sub displayNotification (;$) {
       type   => 'hidden',
       value  => $notification{name},
     };
-  
+
     if (InArray $notification{name}, @PREDEFINED_NOTIFICATIONS) {
       $actions .= input {
         name     => 'delete',
@@ -1251,7 +1251,7 @@ sub displayNotification (;$) {
         alt      => 'Delete',
         value    => 'Delete',
         title    => 'Cannot delete predefined notification',
-      };     
+      };
       $actions .= input {
         name     => 'edit',
         disabled => 'true',
@@ -1280,8 +1280,8 @@ sub displayNotification (;$) {
         title   => 'Edit',
       };
     } # if
-                
-    display end_form;     
+
+    display end_form;
 
     display td {class => 'dataCentered'}, $actions;
     display td {class => 'data'},         $notification{name};
@@ -1291,15 +1291,15 @@ sub displayNotification (;$) {
     display td {class => 'data'},         $notification{cond};
     display td {class => 'data'},         $notification{nomorethan};
     display td {class => 'data'},
-      (InArray $notification{name}, @PREDEFINED_NOTIFICATIONS) 
+      (InArray $notification{name}, @PREDEFINED_NOTIFICATIONS)
       ? 'Predefined'
       : 'User Defined';
-      
+
     display end_Tr;
   } # foreach
 
   display end_table;
-  
+
   display p {class => 'center'}, a {
     href => 'processnotification.cgi?action=Add',
   }, 'New notification', img {
@@ -1312,9 +1312,9 @@ sub displayNotification (;$) {
 
 sub displayRunlog (%) {
   my (%opts) = @_;
-  
+
   my $optsChanged;
-  
+
   unless (($opts{oldtask}   and $opts{task}    or
            $opts{oldtask}   eq  $opts{task})   and
           ($opts{oldsystem} and $opts{system}  or
@@ -1323,29 +1323,29 @@ sub displayRunlog (%) {
            $opts{oldnot}    eq  $opts{not})    and
           ($opts{oldstatus} and $opts{status}  or
            $opts{oldstatus} eq  $opts{status})) {
-    $optsChanged = 1;           
+    $optsChanged = 1;
   } # unless
-            
-  my $condition;  
+
+  my $condition;
 
   unless ($opts{id}) {
     $condition  = "task like '%";
     $condition .= $opts{task} ? $opts{task} : '';
     $condition .= "%'";
-    
+
     if ($opts{system}) {
       if ($opts{system} eq '<NULL>') {
         $condition .= ' and system is null';
         undef $opts{system}
       } elsif ($opts{system} ne 'All') {
-        $condition .= " and system like '%$opts{system}%'";;        
+        $condition .= " and system like '%$opts{system}%'";;
       } # if
     } # if
 
     if (defined $opts{status}) {
       $condition .= ' and ';
       unless ($opts{not}) {
-        $condition .= "status=$opts{status}";    
+        $condition .= "status=$opts{status}";
       } else {
         $condition .= "status<>$opts{status}";
       } # unless
@@ -1353,13 +1353,13 @@ sub displayRunlog (%) {
   } # unless
 
   my $total = $clearadm->Count ('runlog', $condition);
-  
+
   $opts{start} = $opts{'nextArrow.x'} ? $opts{next} : $opts{prev};
   $opts{start} ||= 0;
   $opts{start} = 0
     if $optsChanged;
-    
-  my $next = $opts{start} + $opts{page} < $total 
+
+  my $next = $opts{start} + $opts{page} < $total
            ? $opts{start} + $opts{page}
            : $opts{start};
   my $prev = $opts{start} - $opts{page} >= 0
@@ -1374,7 +1374,7 @@ sub displayRunlog (%) {
      $opts .= " of $total";
 
   display start_form {
-    method => 'post', 
+    method => 'post',
     action => 'runlog.cgi'
   };
 
@@ -1408,7 +1408,7 @@ sub displayRunlog (%) {
       disabled => 'disabled',
     };
   } # unless
-  
+
   $caption .= td {align => 'center'}, $opts;
 
   unless ($opts{id}) {
@@ -1444,12 +1444,12 @@ sub displayRunlog (%) {
     display th {class => 'labelCentered'}, 'Status';
     display th {class => 'labelCentered'}, 'Message';
   display end_Tr;
-  
+
   display start_Tr;
     $opts{not} ||= 'false';
 
     display start_form {
-      method => 'post', 
+      method => 'post',
       action => 'runlog.cgi'
     };
     display td {
@@ -1482,20 +1482,20 @@ sub displayRunlog (%) {
       type  => 'submit',
       value => 'Update',
     };
-    
+
     display end_form;
   display end_Tr;
 
   my $i = $opts{start};
 
   my $status;
-  
+
   if (defined $opts{status}) {
     if ($opts{status} !~ /all/i) {
       $status = $opts{not} ne 'true' ? $opts{status} : "!$opts{status}";
     } # if
   } # if
-  
+
   foreach ($clearadm->FindRunlog (
     $opts{task},
     $opts{system},
@@ -1505,8 +1505,8 @@ sub displayRunlog (%) {
     $opts{page},
     )) {
     my %runlog = setFields 'N/A', %{$_};
-    my $class         = $runlog{status} == 0 
+
+    my $class         = $runlog{status} == 0
                       ? 'data'
                       : 'dataAlert';
     my $classCentered = $runlog{status} == 0
@@ -1515,7 +1515,7 @@ sub displayRunlog (%) {
     my $classRight    = $runlog{status} == 0
                       ? 'dataRight'
                       : 'dataAlertRight';
-   
+
     display start_Tr;
       display td {class => 'dataCentered'}, ++$i;
       display td {class => 'dataCentered'}, $runlog{id};
@@ -1530,16 +1530,16 @@ sub displayRunlog (%) {
       display td {class => 'dataCentered'}, $runlog{started};
       display td {class => 'dataCentered'}, $runlog{ended};
       display td {class => $classRight},    $runlog{status};
-     
+
       my $message = $runlog{message};
          $message =~ s/\r\n/<br>/g;
-     
+
       display td {class => $class, width => '50%'},         $message;
     display end_Tr;
   } # foreach
 
   display end_table;
-  
+
   return;
 } # displayRunlog
 
@@ -1555,14 +1555,14 @@ sub displaySchedule () {
     display th {class => 'labelCentered'}, 'Frequency';
     display th {class => 'labelCentered'}, 'Category';
   display end_Tr;
-  
+
   foreach ($clearadm->FindSchedule) {
     my %schedule = setFields 'N/A', %{$_};
-  
+
     display start_Tr;
     my $areYouSure = "Are you sure you want to delete the $schedule{name} "
                    . "schedule?";
-                   
+
     my $actions = start_form {
       method => 'post',
       action => 'processschedule.cgi',
@@ -1573,7 +1573,7 @@ sub displaySchedule () {
       type   => 'hidden',
       value  => $schedule{name},
     };
-  
+
     if (InArray $schedule{name}, @PREDEFINED_SCHEDULES) {
       $actions .= input {
         name     => 'delete',
@@ -1583,7 +1583,7 @@ sub displaySchedule () {
         alt      => 'Delete',
         value    => 'Delete',
         title    => 'Cannot delete predefined schedule',
-      };     
+      };
       $actions .= input {
         name     => 'edit',
         disabled => 'true',
@@ -1612,9 +1612,9 @@ sub displaySchedule () {
         title   => 'Edit',
       };
     } # if
-                
-    display end_form; 
-    
+
+    display end_form;
+
     display td {class => 'dataCentered'}, $actions;
     display td {class => 'dataCentered'}, checkbox {
       disabled => 'disabled',
@@ -1629,15 +1629,15 @@ sub displaySchedule () {
     }, $schedule{notification};
     display td {class => 'data'},         $schedule{frequency};
     display td {class => 'data'},
-      (InArray $schedule{name}, @PREDEFINED_SCHEDULES) 
-        ? 'Predefined' 
-        : 'User Defined';    
-      
+      (InArray $schedule{name}, @PREDEFINED_SCHEDULES)
+        ? 'Predefined'
+        : 'User Defined';
+
     display end_Tr;
   } # foreach
 
   display end_table;
-  
+
   display p {class => 'center'}, a {
     href => 'processschedule.cgi?action=Add',
   }, 'New schedule', img {
@@ -1650,17 +1650,17 @@ sub displaySchedule () {
 
 sub displaySystem ($) {
   my ($systemName) = @_;
-    
+
   my %system = $clearadm->GetSystem ($systemName);
-  
+
   unless (%system) {
     displayError "Nothing known about system $systemName";
     return;
   } # unless
-  
+
   my $lastheardfromClass = 'dataCentered';
   my $lastheardfromData  = $system{lastheardfrom};
-  
+
   my %load = $clearadm->GetLatestLoadavg ($systemName);
 
   unless ($clearadm->SystemAlive (%system)) {
@@ -1676,18 +1676,18 @@ sub displaySystem ($) {
   my $admin = ($system{email})
             ? a {-href => "mailto:$system{email}"}, $system{admin}
             : $system{admin};
-                    
+
   $system{alias}  = setField $system{alias},  'N/A';
   $system{region} = setField $system{region}, 'N/A';
 
   display start_table {cellspacing => 1};
-  
+
   display start_Tr;
     my $areYouSure = 'Are you sure you want to delete this system?\n'
                    . "Doing so will remove all records related to $system{name}"
                    . '\nincluding filesystem records and history as well as '
                    . 'loadavg history.';
-                   
+
     my $actions = start_form {
       method => 'post',
       action => 'processsystem.cgi',
@@ -1698,7 +1698,7 @@ sub displaySystem ($) {
       type   => 'hidden',
       value  => $system{name},
     };
-  
+
     $actions .= input {
       name    => 'delete',
       type    => 'image',
@@ -1719,18 +1719,18 @@ sub displaySystem ($) {
     $actions .= checkbox {
       disabled => 'disabled',
       checked  => $system{active} eq 'true' ? 1 : 0,
-    };    
-    
+    };
+
     if ($system{notification}) {
       $actions .= a {
         href => "alertlog.cgi?system=$system{name}"}, img {
         src    => 'alert.png',
         border => 0,
         alt    => 'Alert!',
-        title  => 'This system has alerts', 
+        title  => 'This system has alerts',
       };
     } # if
-                
+
     display th {class => 'label'},                      "$actions Name:";
     display end_form;
     display td {class => 'dataCentered', colspan => 2}, $system{name};
@@ -1741,12 +1741,12 @@ sub displaySystem ($) {
     display th {class => 'label', colspan => 2},        'Type:';
     display td {class => 'dataCentered'},               $system{type};
   display end_Tr;
-  
+
   display start_Tr;
     display th {class => 'label'},               'OS Version:';
-    display td {class => 'data', colspan => 10}, $system{os}; 
+    display td {class => 'data', colspan => 10}, $system{os};
   display end_Tr;
-  
+
   display start_Tr;
     display th {class => 'label'}, 'Last Contacted:';
     display td {
@@ -1762,23 +1762,23 @@ sub displaySystem ($) {
     display td {class => 'dataCentered'}, $system{loadavgHist};
     display th {class => 'label'},        'Load Avg:';
     display td {class => 'data'},
-      a {href => 
+      a {href =>
         "plot.cgi?type=loadavg&system=$system{name}&scaling=Hour&points=24"
         }, img {
           src    => "plotloadavg.cgi?system=$system{name}&tiny=1",
           border => 0,
       };
-    
+
   my $description = $system{description};
   $description =~ s/\r\n/<br>/g;
-   
+
   display start_Tr;
     display th {class => 'label'},               'Description:';
-    display td {class => 'data', colSpan => 10}, $description; 
+    display td {class => 'data', colSpan => 10}, $description;
   display end_Tr;
-  
+
   display end_table;
-  
+
   display p {class => 'center'}, a {
     href => 'processsystem.cgi?action=Add',
   }, 'New system', img {
@@ -1786,11 +1786,11 @@ sub displaySystem ($) {
     border => 0,
   };
 
-  display h1 {class => 'center'}, 
+  display h1 {class => 'center'},
     'Filesystem Details: ' . ucfirst $system{name};
-  
+
   display start_table {cellspacing => 1};
-  
+
   display start_Tr;
     display th {class => 'labelCentered'}, 'Action';
     display th {class => 'labelCentered'}, 'Filesystem';
@@ -1803,32 +1803,32 @@ sub displaySystem ($) {
     display th {class => 'labelCentered'}, 'Threshold';
     display th {class => 'labelCentered'}, 'History';
     display th {class => 'labelCentered'}, 'Usage';
-  display end_Tr;  
-  
+  display end_Tr;
+
   foreach ($clearadm->FindFilesystem ($system{name})) {
     my %filesystem = %{$_};
-    
+
     my %fs = $clearadm->GetLatestFS (
-      $filesystem{system}, 
+      $filesystem{system},
       $filesystem{filesystem}
     );
-    
+
     my $size = autoScale $fs{size};
     my $used = autoScale $fs{used};
-    my $free = autoScale $fs{free};  
+    my $free = autoScale $fs{free};
 
-    # TODO: Note that this percentages does not agree with df output. I'm not 
+    # TODO: Note that this percentages does not agree with df output. I'm not
     # sure why.
-    my $usedPct = $fs{size} == 0 ? 0 
+    my $usedPct = $fs{size} == 0 ? 0
                 : sprintf ('%.0f',
                    (($fs{reserve} + $fs{used}) / $fs{size} * 100));
-    
-    my $class         = $usedPct < $filesystem{threshold} 
+
+    my $class         = $usedPct < $filesystem{threshold}
                       ? 'data'
                       : 'dataAlert';
     my $classCentered = $class . 'Centered';
     my $classRight    = $class . 'Right';
-    
+
     display start_Tr;
         display start_td {class => 'data'};
 
@@ -1841,7 +1841,7 @@ sub displaySystem ($) {
           method => 'post',
           action => 'processfilesystem.cgi',
         };
-        
+
         display input {
           type  => 'hidden',
           name  => 'system',
@@ -1852,7 +1852,7 @@ sub displaySystem ($) {
           name  => 'filesystem',
           value => $filesystem{filesystem},
         };
-        
+
         display input {
           name    => 'delete',
           type    => 'image',
@@ -1870,18 +1870,18 @@ sub displaySystem ($) {
           value   => 'Edit',
           title   => 'Edit',
         };
-        
+
         if ($filesystem{notification}) {
           display a {
             href => "alertlog.cgi?system=$filesystem{system}"}, img {
             src    => 'alert.png',
             border => 0,
             alt    => 'Alert!',
-            title  => 'This filesystem has alerts', 
+            title  => 'This filesystem has alerts',
           };
-        } # if        
+        } # if
 
-        display end_form;    
+        display end_form;
       display td {class => $class},         $filesystem{filesystem};
       display td {class => $classCentered}, $filesystem{fstype};
       display td {class => $class},         $filesystem{mount};
@@ -1891,8 +1891,8 @@ sub displaySystem ($) {
       display td {class => $classRight},    "$usedPct%";
       display td {class => $classRight},    "$filesystem{threshold}%";
       display td {class => $classCentered}, $filesystem{filesystemHist};
-      display td {class => $classCentered},        
-        a {href => 
+      display td {class => $classCentered},
+        a {href =>
           "plot.cgi?type=filesystem&system=$system{name}"
         . "&filesystem=$filesystem{filesystem}"
         . "&scaling=Day&points=7"
@@ -1906,13 +1906,13 @@ sub displaySystem ($) {
   } # foreach
 
   display end_table;
-  
+
   return;
 } # displaySystem
 
 sub displayTask (;$) {
   my ($task) = @_;
-  
+
   display start_table {cellspacing => 1, width => '98%'};
 
   display start_Tr;
@@ -1924,16 +1924,16 @@ sub displayTask (;$) {
     display th {class => 'labelCentered'}, 'Restartable';
     display th {class => 'labelCentered'}, 'Category';
   display end_Tr;
-  
+
   foreach ($clearadm->FindTask ($task)) {
     my %task = %{$_};
-    
+
     $task{system} = 'All Systems'
       unless $task{system};
-   
+
     display start_Tr;
       my $areYouSure = "Are you sure you want to delete the $task{name} task?";
-                   
+
       my $actions = start_form {
         method => 'post',
         action => 'processtask.cgi',
@@ -1954,7 +1954,7 @@ sub displayTask (;$) {
           alt      => 'Delete',
           value    => 'Delete',
           title    => 'Cannot delete predefined task',
-        };     
+        };
         $actions .= input {
           name     => 'edit',
           disabled => 'true',
@@ -1984,34 +1984,34 @@ sub displayTask (;$) {
         };
       } # if
 
-      display end_form;     
+      display end_form;
 
       display td {class => 'dataCentered'}, $actions;
       display td {class => 'data'},         $task{name};
-      display td {class => 'data'},         $task{system};      
+      display td {class => 'data'},         $task{system};
       display td {class => 'data'},         $task{description};
       display td {class => 'data'},         $task{command};
       display td {class => 'dataCentered'}, $task{restartable};
-      display td {class => 'data'},         
+      display td {class => 'data'},
         (InArray $task{name}, @PREDEFINED_TASKS) ? 'Predefined' : 'User Defined';
     display end_Tr;
   } # foreach
 
-  display end_table; 
-  
+  display end_table;
+
   display p {class => 'center'}, a {
     href => 'processtask.cgi?action=Add',
   }, 'New task', img {
     src    => 'add.png',
     border => 0,
   };
-  
+
   return;
 } # DisplayAlerts
 
 sub editAlert (;$) {
   my ($alert) = @_;
-  
+
   display start_form (
     -method   => 'post',
     -action   => 'processalert.cgi',
@@ -2022,10 +2022,10 @@ sub editAlert (;$) {
 
   if ($alert) {
     %alert = $clearadm->GetAlert ($alert);
-  
+
     return
-      unless %alert;      
-      
+      unless %alert;
+
     display input {
       name  => 'oldname',
       type  => 'hidden',
@@ -2034,21 +2034,21 @@ sub editAlert (;$) {
   } else {
     $alert= '';
   } # if
-  
+
   display input {
     name  => 'action',
     type  => 'hidden',
     value => 'Post',
   };
-  
+
   display start_table {cellspacing => 1};
-  
+
   display start_Tr;
     display th {class => 'labelCentered'}, 'Name';
     display th {class => 'labelCentered'}, 'Type';
     display th {class => 'labelCentered'}, 'Who';
   display end_Tr;
-  
+
   display start_Tr;
     display td {
       class => 'data',
@@ -2080,26 +2080,26 @@ sub editAlert (;$) {
     };
   display end_Tr;
   display end_table;
-  
+
   display '<center>';
   display p submit ({value => $alert ? 'Update' : 'Add'}),  reset;
   display '</center>';
-  
+
   display end_form;
-  
+
   return;
 } # editAlert
 
 sub editFilesystem ($$) {
   my ($system, $filesystem) = @_;
-  
+
   display start_form (
     -method => 'post',
     -action => 'processfilesystem.cgi',
   );
 
   display start_table {width => '800px', cellspacing => 1};
-  
+
   display start_Tr;
     display th {class => 'labelCentered'}, 'Filesystem';
     display th {class => 'labelCentered'}, 'Type';
@@ -2110,11 +2110,11 @@ sub editFilesystem ($$) {
     display th {class => 'labelCentered'}, 'Used %';
     display th {class => 'labelCentered'}, 'History';
     display th {class => 'labelCentered'}, 'Threshold';
-  display end_Tr;  
-  
+  display end_Tr;
+
   my %filesystem = $clearadm->GetFilesystem ($system, $filesystem);
   my %fs         = $clearadm->GetLatestFS   ($system, $filesystem);
-  
+
   display input {
     name  => 'action',
     type  => 'hidden',
@@ -2124,13 +2124,13 @@ sub editFilesystem ($$) {
     name  => 'system',
     type  => 'hidden',
     value => $filesystem{system},
-  };  
+  };
   display input {
     name  => 'filesystem',
     type  => 'hidden',
     value => $filesystem{filesystem},
-  } ; 
-  
+  } ;
+
   my $size = autoScale $fs{size};
   my $used = autoScale $fs{used};
   my $free = autoScale $fs{free};
@@ -2142,11 +2142,11 @@ sub editFilesystem ($$) {
     display td {class => 'dataRight'},    $size;
     display td {class => 'dataRight'},    $used;
     display td {class => 'dataRight'},    $free;
-    # TODO: Note that this percentages does not agree with df output. I'm not 
+    # TODO: Note that this percentages does not agree with df output. I'm not
     # sure why.
     display td {class => 'dataCentered'},
       sprintf ('%.0f%%', (($fs{reserve} + $fs{used}) / $fs{size} * 100));
-      
+
     my $historyDropdown = popup_menu {
       name    => 'filesystemHist',
       class   => 'dropdown',
@@ -2166,34 +2166,34 @@ sub editFilesystem ($$) {
       ],
       default => $system ? $filesystem{filesystemHist} : '6 months',
     };
-        
+
     display td {
       class => 'dataRight',
-    }, $historyDropdown; 
-  
+    }, $historyDropdown;
+
     my $thresholdDropdown = popup_menu {
       name    => 'threshold',
       class   => 'dropdown',
       values  => [1 .. 100],
       default => $filesystem{threshold},
-    };        
+    };
     display td {class => 'dataCentered'}, $thresholdDropdown . '%';
   display end_Tr;
-  
-  display end_table; 
-  
+
+  display end_table;
+
   display '<center>';
   display p submit ({value => 'Update'}),  reset;
   display '</center>';
-  
+
   display end_form;
-  
+
   return;
 } # editFilesytem
 
 sub editNotification (;$) {
   my ($notification) = @_;
-  
+
   display start_form (
     -method   => 'post',
     -action   => 'processnotification.cgi',
@@ -2204,10 +2204,10 @@ sub editNotification (;$) {
 
   if ($notification) {
     %notification = $clearadm->GetNotification ($notification);
-  
+
     return
-      unless %notification;      
-      
+      unless %notification;
+
     display input {
       name  => 'oldname',
       type  => 'hidden',
@@ -2216,22 +2216,22 @@ sub editNotification (;$) {
   } else {
     $notification = '';
   } # if
-  
+
   display input {
     name  => 'action',
     type  => 'hidden',
     value => 'Post',
   };
-  
+
   display start_table {cellspacing => 1};
-  
+
   display start_Tr;
     display th {class => 'labelCentered'}, 'Name';
     display th {class => 'labelCentered'}, 'Alert';
     display th {class => 'labelCentered'}, 'Condition';
     display th {class => 'labelCentered'}, 'Not More Than';
   display end_Tr;
-  
+
   display start_Tr;
     display td {
       class => 'data',
@@ -2243,13 +2243,13 @@ sub editNotification (;$) {
       type      => 'text',
       value     => $notification ? $notification{name} : '',
     };
-    
+
     display td {
       class => 'dataCentered',
-    }, makeAlertDropdown undef, $notification{alert} 
+    }, makeAlertDropdown undef, $notification{alert}
        ? $notification{alert}
        : 'Email admin';
-    
+
     display td {
       class => 'data',
     }, input {
@@ -2263,22 +2263,22 @@ sub editNotification (;$) {
     display td {
       class => 'dataCentered',
     }, makeNoMoreThanDropdown undef, $notification{nomorethan};
-    
+
   display end_Tr;
   display end_table;
-  
+
   display '<center>';
   display p submit ({value => $notification ? 'Update' : 'Add'}),  reset;
   display '</center>';
-  
+
   display end_form;
-  
+
   return;
 } # editNotification
 
 sub editSchedule (;$) {
   my ($schedule) = @_;
-  
+
   display start_form (
     -method   => 'post',
     -action   => 'processschedule.cgi',
@@ -2289,10 +2289,10 @@ sub editSchedule (;$) {
 
   if ($schedule) {
     %schedule = $clearadm->GetSchedule ($schedule);
-  
+
     return
-      unless %schedule;      
-      
+      unless %schedule;
+
     display input {
       name  => 'oldname',
       type  => 'hidden',
@@ -2301,15 +2301,15 @@ sub editSchedule (;$) {
   } else {
     $schedule = '';
   } # if
-  
+
   display input {
     name  => 'action',
     type  => 'hidden',
     value => 'Post',
   };
-  
+
   display start_table {cellspacing => 1};
-  
+
   display start_Tr;
     display th {class => 'labelCentered'}, 'Active';
     display th {class => 'labelCentered'}, 'Name';
@@ -2317,7 +2317,7 @@ sub editSchedule (;$) {
     display th {class => 'labelCentered'}, 'Notification';
     display th {class => 'labelCentered'}, 'Frequency';
   display end_Tr;
-  
+
   display start_Tr;
     display td {
       class => 'dataCentered',
@@ -2339,21 +2339,21 @@ sub editSchedule (;$) {
     };
     display td {
       class => 'dataCentered',
-    }, makeTaskDropdown undef, $schedule{task}; 
+    }, makeTaskDropdown undef, $schedule{task};
     display td {
       class => 'dataCentered',
-    }, makeNotificationDropdown undef, $schedule{notification}; 
-    
+    }, makeNotificationDropdown undef, $schedule{notification};
+
     my $nbr        = 5;
     my $multiplier = 'minutes';
-    
+
     if ($schedule{frequency} =~ /(\d+)\s(\S+)/ ) {
       $nbr        = $1;
       $multiplier = $2;
-      
+
       $multiplier .= 's' if $nbr == 1;
     } # if
-        
+
     display td {
       class => 'data',
     }, input {
@@ -2363,25 +2363,25 @@ sub editSchedule (;$) {
       size      => 1,
       type      => 'text',
       value     => $nbr,
-    }, 
+    },
       ' ',
       makeMultiplierDropdown undef, $multiplier;
-    
+
   display end_Tr;
   display end_table;
-  
+
   display '<center>';
   display p submit ({value => $schedule ? 'Update' : 'Add'}),  reset;
   display '</center>';
-  
+
   display end_form;
-  
+
   return;
 } # editSchedule
 
 sub editSystem (;$) {
   my ($system) = @_;
-  
+
   display start_form (
     -method   => 'post',
     -action   => 'processsystem.cgi',
@@ -2389,13 +2389,13 @@ sub editSystem (;$) {
   );
 
   my %system;
-  
+
   if ($system) {
     %system = $clearadm->GetSystem ($system);
-  
+
     return
       unless %system;
-      
+
     display input {
       name  => 'name',
       type  => 'hidden',
@@ -2404,15 +2404,15 @@ sub editSystem (;$) {
   } else {
     $system = '';
   } # if
-  
+
   display input {
     name  => 'action',
     type  => 'hidden',
     value => 'Post',
   };
-  
+
   display start_table {cellspacing => 1};
-  
+
   display start_Tr;
     display th {class => 'label'}, checkbox ({
       name    => 'active',
@@ -2420,7 +2420,7 @@ sub editSystem (;$) {
       checked => $system{active} eq 'false' ? 0 : 1,
       label   => '',
     }) . ' Name: ';
-    
+
     if ($system) {
       display td {class => 'data'},  $system{name};
     } else {
@@ -2434,7 +2434,7 @@ sub editSystem (;$) {
         type      => 'text',
       };
     } # if
-    
+
     display th {class => 'label'}, 'Alias:';
     display td {
       class => 'data',
@@ -2456,24 +2456,24 @@ sub editSystem (;$) {
       name      => 'port',
       size      => 4,
       type      => 'text',
-      value     => $system 
+      value     => $system
                  ? $system{port}
                  : $Clearadm::CLEAROPTS{CLEARADM_PORT},
     };
-    
+
     my $systemTypeDropdown = popup_menu {
       name    => 'type',
       class   => 'dropdown',
       values  => ['Unix', 'Linux', 'Windows'],
       default => $system ? $system{type} : 'Linux',
     };
-    
+
     display th {class => 'label'}, 'Type:';
     display td {
       class   => 'dataRight',
     },  $systemTypeDropdown;
   display end_Tr;
-  
+
   display start_Tr;
     display th {class => 'label'}, 'Admin:';
     display td {
@@ -2507,11 +2507,11 @@ sub editSystem (;$) {
       name      => 'loadavgThreshold',
       size      => 3,
       type      => 'text',
-      value     => $system 
+      value     => $system
                  ? $system{loadavgThreshold}
                  : $Clearadm::CLEAROPTS{CLEARADM_LOADAVG_THRESHOLD},
     };
-        
+
     my $historyDropdown = popup_menu {
       name    => 'loadavgHist',
       class   => 'dropdown',
@@ -2531,15 +2531,15 @@ sub editSystem (;$) {
       ],
       default => $system ? $system{loadavgHist} : '6 months',
     };
-        
+
     display th {class => 'label'}, 'History:';
     display td {
       class => 'dataRight',
-    }, $historyDropdown; 
-    
+    }, $historyDropdown;
+
   my $description = $system ? $system{description} : '';
      $description =~ s/\r\n/<br>/g;
-     
+
   display start_Tr;
     display th {class => 'label'}, 'Description:';
     display td {
@@ -2554,19 +2554,19 @@ sub editSystem (;$) {
     };
   display end_Tr;
   display end_table;
-  
+
   display '<center>';
   display p submit ({value => $system ? 'Update' : 'Add'}),  reset;
   display '</center>';
-  
+
   display end_form;
-  
+
   return;
 } # editSystem
 
 sub editTask (;$) {
   my ($task) = @_;
-  
+
   display start_form (
     -method   => 'post',
     -action   => 'processtask.cgi',
@@ -2577,10 +2577,10 @@ sub editTask (;$) {
 
   if ($task) {
     %task = $clearadm->GetTask ($task);
-  
+
     return
       unless %task;
-      
+
     display input {
       name  => 'oldname',
       type  => 'hidden',
@@ -2589,15 +2589,15 @@ sub editTask (;$) {
   } else {
     $task = '';
   } # if
-  
+
   display input {
     name  => 'action',
     type  => 'hidden',
     value => 'Post',
   };
-  
+
   display start_table {cellspacing => 1};
-  
+
   display start_Tr;
     display th {class => 'labelCentered'}, 'Name';
     display th {class => 'labelCentered'}, 'System';
@@ -2605,7 +2605,7 @@ sub editTask (;$) {
     display th {class => 'labelCentered'}, 'Command';
     display th {class => 'labelCentered'}, 'Restartable';
   display end_Tr;
-  
+
   display start_Tr;
     display td {
       class => 'data',
@@ -2625,8 +2625,8 @@ sub editTask (;$) {
         'Localhost'   => 'Localhost',
       ),
     );
-        
-    display td {class => 'data'}, $systemDropdown;      
+
+    display td {class => 'data'}, $systemDropdown;
 
     display td {
       class => 'data',
@@ -2638,7 +2638,7 @@ sub editTask (;$) {
       type      => 'text',
       value     => $task ? $task{description} : '',
     };
-    
+
     display td {
       class => 'data',
     }, input {
@@ -2653,50 +2653,50 @@ sub editTask (;$) {
     display td {
       class => 'dataCentered',
     }, makeRestartableDropdown undef, $task{restartable};
-    
+
   display end_Tr;
   display end_table;
-  
+
   display '<center>';
   display p submit ({value => $task ? 'Update' : 'Add'}),  reset;
   display '</center>';
-  
+
   display end_form;
-  
+
   return;
 } # editTask
 
 sub footing () {
   my $clearscm = a {-href => 'http://clearscm.com'}, 'ClearSCM, Inc.';
-  
+
   # Figure out which script by using CLEARADM_BASE.
-  my $script = basename (url {-absolute => 1}); 
+  my $script = basename (url {-absolute => 1});
      $script = 'index.cgi'
        if $script eq 'clearadm';
 
   my $scriptFullPath = "$Clearadm::CLEAROPTS{CLEARADM_BASE}/$script";
-  
-  my ($year, $mon, $mday, $hour, $min, $sec) = 
+
+  my ($year, $mon, $mday, $hour, $min, $sec) =
     ymdhms ((stat ($scriptFullPath))[9]);
 
   my $dateModified = "$mon/$mday/$year @ $hour:$min";
-  
+
   $script = a {
     -href => "http://clearscm.com/php/scm_man.php?file=clearadm/$script"
   }, $script;
-  
+
   display end_div;
-  
+
   display start_div {-class => 'copyright'};
     display "$script: Last modified: $dateModified";
     display br "Copyright &copy; $year, $clearscm - All rights reserved";
   display end_div;
-  
+
   print end_html;
-  
+
   return;
 } # footing
-    
+
 1;
 
 =pod
@@ -2725,13 +2725,13 @@ L<GD>
 
 =head2 ClearSCM Perl Modules
 
-=begin man 
+=begin man
 
  Clearadm
  DateUtils
  Display
  Utils
+
 =end man
 
 =begin html
index 27371c9..410a94e 100644 (file)
@@ -38,7 +38,7 @@ The results are sent back as follows:
 
  Status: <status>
  <command output>
+
 This allows the caller to determine if the command execution was successful as
 well as capture the commands output.
 
@@ -282,7 +282,7 @@ sub _serviceClient ($$) {
       $self->_debug ("Status: $status");
     } # if
 
-    print $client "$_\n" foreach (@output);
+    print $client "$_\n" for (@output);
     print $client "Clearexec Status: $status\n";
 
     $self->_debug ("Looping around for next command");
@@ -319,7 +319,7 @@ sub startServer (;$) {
 
   while () {
     $client = $self->{socket}->accept;
-    
+
     if ($? == -1) {\r
       if ($!{EINTR}) {
         next;
@@ -394,7 +394,7 @@ L<Net::hostent|Net::hostent>
 
 =head2 ClearSCM Perl Modules
 
-=begin man 
+=begin man
 
  DateUtils
  Display
index 9a0605a..2203c29 100644 (file)
@@ -31,16 +31,16 @@ $Date: 2011/01/09 01:03:10 $
 This module implements a User object which returns information about a user.
 
  my $user = new User ('adefaria');
+
  print "Fullname: $user->{fullname}\n";
  print "EMail: $user->{email}\n";
+
 =head2 DESCRIPTION
 
-This module instanciates a user object for the given user identifier and 
+This module instanciates a user object for the given user identifier and
 then collects information about the user such as fullname, email, etc. It does
 so by contacting Active Directory in a Windows domain or other directory servers
-depending on the site. As such exactly what data members are available may 
+depending on the site. As such exactly what data members are available may
 change or be different from site to site.
 
 =cut
@@ -60,7 +60,7 @@ our %CLEAROPTS= GetConfig ("$FindBin::Bin/etc/clearuser.conf");
 
 our $VERSION  = '$Revision: 1.4 $';
    ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
-   
+
 # Override options if in the environment
 $CLEAROPTS{CLEARUSER_LDAPHOST} = $ENV{CLEARUSER_LDAPHOST}
   if $ENV{CLEARUSER_LDAPHOST};
@@ -91,7 +91,7 @@ sub unix2sso ($) {
 
 sub GetOwnerInfo ($) {
   my ($userid) = @_;
-  
+
   my @parts = split /(\/|\\)/, $userid;
 
   if (@parts == 3) {
@@ -99,28 +99,28 @@ sub GetOwnerInfo ($) {
   } # if
 
   my $sso = unix2sso ($userid);
-  
+
   unless ($ldap) {
     $ldap = Net::LDAP->new ($CLEAROPTS{CLEARUSER_LDAPHOST})
       or croak 'Unable to create LDAP object';
-      
+
     $ad = $ldap->bind (
       "$CLEAROPTS{CLEARUSER_USERNAME}\@$CLEAROPTS{CLEARUSER_BIND}",
       password => $CLEAROPTS{CLEARUSER_PASSWORD});
   } # unless
-  
+
   $ad = $ldap->search (
     base   => $CLEAROPTS{CLEARUSER_BASEDN},
     filter => "(&(objectclass=user)(sAMAccountName=$sso))",
   );
-  
-  $ad->code 
+
+  $ad->code
     && croak $ad->error;
-    
+
   my @entries = $ad->entries;
 
   my %ownerInfo;
-    
+
   if (@entries == 1) {
     for (my $i = 0; $i < $ad->count; $i++) {
       my $entry = $ad->entry ($i);
@@ -129,11 +129,11 @@ sub GetOwnerInfo ($) {
         $ownerInfo{$attribute} = $entry->get_value ($attribute)
       } # foreach
     } # for
-    
+
     return %ownerInfo;
   } else {
     return;
-  } # if 
+  } # if
 } # GetOwnerInfo
 
 =pod
@@ -191,16 +191,16 @@ sub new ($) {
 
   croak "Must specify userid to User constructor"
     if @_ == 1;
-    
+
   my %members;
-  
+
   $members{id} = $userid;
-  
+
   my %ownerInfo = GetOwnerInfo ($userid);
-  
+
   $members{$_} = $ownerInfo{$_}
     foreach (keys %ownerInfo);
-  
+
   return bless \%members, $class;
 } # new
 
@@ -226,7 +226,7 @@ L<Net::LDAP|Net::LDAP>
 
 =head2 ClearSCM Perl Modules
 
-=begin man 
+=begin man
 
  GetConfig
 
index 7d9873e..83d6961 100644 (file)
 # Column 4 ClearCase Version (if applicable)
 # Column 5 Owner (if known)
 # Column 6 Usage (if known)
-chargers:Sun:Solaris 5.9:70.1.1:ccadm:ranview1
+chargers:Sun:Solaris 5.9:7.0.1.1:ccadm:ranview1
 colts:Sun:Solaris 5.9:7.0.1.0:ccadm:ranview2
 cowboys:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob1/registry server
-niners:Sun:Solaris 5.9:2003.06.10+:ccadm:?
-patriots:Sun:?:Solaris 5.9:7.0.1.0:ccadm:ranvob2
+niners:Sun:Solaris 5.9:2003.06.10+:ccadm:
+patriots:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob2
 rams:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob3/registry server
-#ranadm1:Sun:Solaris 5.9:?:ccadm:Jumpstart, PowerBroker, NIS, SMTP, DNS, NTP
+#ranadm1:Sun:Solaris 5.9::ccadm:Jumpstart, PowerBroker, NIS, SMTP, DNS, NTP
 ranadm2:Sun:Solaris 5.9:2003.06.10+:ccadm:License server, Sys admin, NIS, Home Directory server
-ranbkp2:?:?:?:ccadm:?
+ranbkp2::::ccadm:Backup
 ranbuild1:Sun:Solaris 5.8:7.0.1.0:ccadm:builds
 ranbuild2:Sun:Solaris 5.9:2003.06.10+:ccadm:builds
 ranbuild4:Sun:Solaris 5.9:7.0.1.1:ccadm:builds
-rancpp01:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:?
-rancpp02:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:?
-rancpp03:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:?
-rancpp10:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:?
-#randbs:Sun:Solaris 5.9:?:ccadm:CQ DB server/Bldforge
+rancpp01:Redhat Linux:2.6.18.53.Eel5xen::ccadm:
+rancpp02:Redhat Linux:2.6.18.53.Eel5xen::ccadm:
+rancpp03:Redhat Linux:2.6.18.53.Eel5xen::ccadm:
+rancpp10:Redhat Linux:2.6.18.53.Eel5xen::ccadm:
+#randbs:Sun:Solaris 5.9::ccadm:CQ DB server/Bldforge
 randws094:Sun:Solaris 5.10:7.0.1.1:John Hartin:Old workstation
-randws103:Sun:Solaris 5.9:7.0.1.1:?:?
-randws106:Sun:Solaris 5.9:2003.06.10+:?:?
-randws113:Sun:Solaris 5.9:7.0.1.1:?:?
-randws114:Sun:Solaris 5.9:2003.06.10+:Tony Trujilo:?
+randws103:Sun:Solaris 5.9:7.0.1.1::
+randws106:Sun:Solaris 5.9:2003.06.10+::
+randws113:Sun:Solaris 5.9:7.0.1.1::
+randws114:Sun:Solaris 5.9:2003.06.10+:Tony Trujilo:
 randws119:Sun:Solaris 5.9:7.0.1.1:Hy Truong:Workstation
-ranlin03:Redhat Linux:2.4.21-50.Elsmp:?:ccadm:?
-ranray:Sun:Solaris 5.9:2003.06.10+:ccadm:?
+ranlin03:Redhat Linux:2.4.21-50.Elsmp::ccadm:
+ranray:Sun:Solaris 5.9:2003.06.10+:ccadm:
diff --git a/etc/machines.sql b/etc/machines.sql
new file mode 100644 (file)
index 0000000..3691e75
--- /dev/null
@@ -0,0 +1,62 @@
+-- -----------------------------------------------------------------------------\r
+--\r
+-- File:        $RCSfile: Machines.sql,v $\r
+-- Revision:    $Revision: 1.$\r
+-- Description: Create the Machines database\r
+-- Author:      Andrew@DeFaria.com\r
+-- Created:     Fri, Jul 13, 2018 10:51:18 AM\r
+-- Modified:    $Date: $\r
+-- Language:    SQL\r
+--\r
+-- Copyright (c) 2010, ClearSCM, Inc., all rights reserved\r
+--\r
+-- -----------------------------------------------------------------------------\r
+-- Warning: The following line will delete the old database!\r
+-- drop database if exists machines;\r
+\r
+-- Create a new database\r
+create database machines;\r
+\r
+-- Now let's focus on this new database\r
+use machines;\r
+\r
+-- system: Define what makes up a system or machine\r
+create table system (\r
+  name             varchar (255) not null,\r
+  model            tinytext,\r
+  alias            varchar (255),\r
+  active           enum (\r
+                     'true',\r
+                     'false'\r
+                   ) not null default 'true',\r
+  admin            tinytext,\r
+  email            tinytext,\r
+  os               tinytext,\r
+  ccver            tinytext,\r
+  type             enum (\r
+                     'Linux',\r
+                     'Unix',\r
+                     'Windows',\r
+                     'Mac'\r
+                   ) not null,\r
+  lastheardfrom    datetime,\r
+  description      text,\r
+\r
+  primary key (name)\r
+) engine=innodb; -- system\r
+\r
+-- package: A package is any software package that we wish to keep track of\r
+create table package (\r
+  system      varchar (255) not null,\r
+  name        varchar (255) not null,\r
+  version     tinytext not null,\r
+  vendor      tinytext,\r
+  description text,\r
+\r
+  key packageIndex (name),\r
+  key systemIndex (system),\r
+  foreign key systemLink (system) references system (name)\r
+    on delete cascade\r
+    on update cascade,\r
+  primary key (system, name)\r
+) engine=innodb; -- package\r
index 6693f14..b1c73c0 100644 (file)
@@ -30,7 +30,7 @@ $Date: 2011/12/31 02:13:37 $
 
 Provides an interface to the Clearquest database over the network.
 
-This library implements both the daemon portion of the server and the client 
+This library implements both the daemon portion of the server and the client
 API.
 
 =head1 DESCRIPTION
@@ -42,7 +42,7 @@ write to the Clearquest database for write access to succeed.
 A hash is passed into to the execute method, which the client should use to talk
 to the server, that describes relatively simple protocol to tell the server what
 action to perform. In both the read case and the read/write case a field named
-id should be defined that has a value of "<record>=<id>" (e.g. 
+id should be defined that has a value of "<record>=<id>" (e.g.
 "defect=BUGDB00034429").
 
 For the read case the rest of the keys are the names of the fields to retrieve
@@ -50,7 +50,7 @@ with values that are undef'ed. For read/write, the rest of hash contains name
 value pairs of fields to set and their values.
 
 Execute returns a status and a hash of name value pairs for the read case and an
-array of lines for any error messages for the read/write case. 
+array of lines for any error messages for the read/write case.
 
 =head1 ROUTINES
 
@@ -83,7 +83,7 @@ our %OPTS = GetConfig $config;
 
 our $VERSION  = '$Revision: 1.2 $';
    ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
-   
+
 # Override options if in the environment
 $OPTS{CQD_HOST}          = $ENV{CQD_HOST}
   if $ENV{CQD_HOST};
@@ -116,31 +116,31 @@ sub _tag ($) {
   my $tag  = YMDHMS;
      $tag .= ' ';
      $tag .= $self->{pid} ? "[$self->{pid}] " : '';
-  
+
   return "$tag$msg";
 } # _tag
 
-sub _verbose ($) {
+ sub _verbose ($) {
   my ($self, $msg) = @_;
 
   verbose $self->_tag ($msg);
-  
+
   return;
 } # _verbose
 
 sub _debug ($) {
   my ($self, $msg) = @_;
-  
+
   debug $self->_tag ($msg);
-  
+
   return;
 } # _debug
 
 sub _log ($) {
   my ($self, $msg) = @_;
-  
+
   display $self->_tag ($msg);
-  
+
   return;
 } # log
 
@@ -149,9 +149,9 @@ sub _funeral () {
 
   while (my $childpid = waitpid (-1, WNOHANG) > 0) {
     my $status = $?;
-  
+
     debug "childpid: $childpid - status: $status";
-  
+
     if ($childpid != -1) {
       local $SIG{CHLD} = \&_funeral;
 
@@ -164,21 +164,21 @@ sub _funeral () {
       debug "All children reaped";
     } # if
   } # while
-  
+
   return;
 } # _funeral
 
 sub _endServer () {
   display "CQDService V$VERSION shutdown at " . localtime;
-  
+
   # Kill process group
   kill 'TERM', -$$;
-  
+
   # Wait for all children to die
   while (wait != -1) {
     # do nothing
-  } # while 
-  
+  } # while
+
   # Now that we are alone, we can simply exit
   exit;
 } # _endServer
@@ -186,7 +186,7 @@ sub _endServer () {
 sub _restartServer () {
   # Not sure what to do on a restart server
   display 'Entered _restartServer';
-  
+
   return;
 } # _restartServer
 
@@ -211,7 +211,7 @@ sub connectToServer (;$$) {
 
   $host ||= $OPTS{CQD_HOST};
   $port ||= $OPTS{CQD_PORT};
-  
+
   $self->{socket} = IO::Socket::INET->new (
     Proto       => 'tcp',
     PeerAddr    => $host,
@@ -219,7 +219,7 @@ sub connectToServer (;$$) {
   );
 
   return unless $self->{socket};
-  
+
   $self->{socket}->autoflush;
 
   $self->{host} = $host;
@@ -233,10 +233,10 @@ sub disconnectFromServer () {
 
   if ($self->{socket}) {
    close $self->{socket};
-   
+
    undef $self->{socket};
   } # if
-  
+
   return;
 } # disconnectFromServer
 
@@ -249,7 +249,7 @@ sub _serviceClient ($$) {
   # Set autoflush for client
   $client->autoflush
     if $client;
-  
+
   # Input is simple and consists of the following:
   #
   # <recordType>=<ID>
@@ -260,69 +260,69 @@ sub _serviceClient ($$) {
   #
   # Notes: <ID> can be <ID_scope>. Also a += means append this fieldvalue to
   # the existing value for the field.
-  
+
   # First get record line
   my $line = <$client>;
-  
+
   if ($line) {
     chomp $line; chop $line if $line =~ /\r$/;
   } else {
     $self->_verbose ("Host $host went away!");
-    
+
     close $client;
-    
+
     return;
   } # if
-  
+
   if ($line =~ /stopserver/i) {
     if ($self->{server}) {
       $self->_verbose ("$host requested to stop server [$self->{server}]");
-                
+
       # Send server hangup signal
       kill 'HUP', $self->{server};
     } else {
       $self->_verbose ('Shutting down server');
-        
+
       print $client "CQDService Status: 0\n";
-        
+
       exit;
     } # if
   } # if
 
   my ($record, $id) = split /=/, $line;
-  
+
   unless ($id) {
     $self->_verbose ('Garbled record line - rejected request');
-    
+
     close $client;
-    
+
     return;
   } # unless
-  
+
   $self->_verbose ("Client wishes to deal with $id");
-  
+
   my $scope;
-  
+
   if ($id =~ /_(\S+)/) {
     $scope = $1;
   } # if
-  
+
   $self->_debug ("$host wants $record:$id");
-  
+
   my ($read, %fields);
-    
-  # Now read name/value pairs  
+
+  # Now read name/value pairs
   while () {
     # Read command from client
-    $line = <$client>; 
-    
+    $line = <$client>;
+
     if ($line) {
       chomp $line; chop $line if $line =~ /\r$/;
     } else {
       $self->_verbose ("Host $host went away!");
-      
+
       close $client;
-      
+
       return;
     } # if
 
@@ -331,86 +331,86 @@ sub _serviceClient ($$) {
     # Collect name/values. Note if only names are requested then we will instead
     # return data.
     my ($name, $value) = split /=/, $line;
-      
+
     if ($value) {
       # Transform %0A's back to \n
       $value =~ s/\%0A/\n/g;
-    
+
       $self->_verbose ("Will set $name to $value");
     } else {
       $read = 1;
       $self->_verbose ("Will retrieve $name");
-    } # if 
-            
+    } # if
+
     $fields{$name} = $value;
   } # while
-  
+
   # Get record
   my $entity;
-  
+
   $self->_verbose ("Getting $record:$id");
-  
+
   eval { $entity = $self->{session}->GetEntity ($record, $id) };
-  
+
   unless ($entity) {
     print $client "Unable to GetEntity $record:$id\n";
-    
+
     close $client;
-    
+
     return;
   } # unless
 
   if ($read) {
     print $client "$_@@" . $entity->GetFieldValue ($_)->GetValue . "\n"
-      foreach (keys %fields);
+      for (keys %fields);
     print $client "CQD Status: 0\n";
-    
+
     close $client;
-    
+
     return;
   } # if
-    
+
   # Edit record
   $self->_verbose ("Editing $id");
-  
+
   $entity->EditEntity ('Backend');
-  
+
   my $status;
-  
-  foreach my $fieldName (keys %fields) {
+
+  for my $fieldName (keys %fields) {
     if ($fieldName =~ /(.+)\*$/) {
       my $newValue = delete $fields{$fieldName};
 
       $fieldName = $1;
-      
+
       $fields{$fieldName} = $entity->GetFieldValue ($fieldName)->GetValue
                           . $newValue;
     } # if
 
     $self->_verbose ("Setting $fieldName to $fields{$fieldName}");
-        
+
     $status = $entity->SetFieldValue ($fieldName, $fields{$fieldName});
-    
+
     if ($status ne '') {
       $self->_verbose ($status);
-      
+
       print $client "$status\n";
       print $client "CQD Status: 1\n";
-      
+
       close $client;
-      
+
       return;
     } # if
-  } # foreach
-  
+  } # for
+
   $self->_verbose ("Validating $id");
-  
+
   $status = $entity->Validate;
-  
+
   if ($status eq '') {
     $self->_verbose ('Committing');
     $entity->Commit;
-    
+
     print $client "Successfully updated $id\n";
     print $client "CQD Status: 0\n";
   } else {
@@ -419,66 +419,66 @@ sub _serviceClient ($$) {
     print $client "$status\n";
     print $client "CQD Status: 1\n";
   } # if
-  
+
   close $client;
-  
+
   $self->_verbose ("Serviced requests from $host");
-  
+
   return;
 }  # _serviceClient
 
 sub execute (%) {
   my ($self, %request) = @_;
-  
+
   $self->connectToServer or croak 'Unable to connect to CQD Service';
 
   return (-1, 'Unable to talk to server')
     unless $self->{socket};
-  
+
   my ($status, @output) = (-1, ());
-  
+
   my $server = $self->{socket};
-  
+
   my $id = delete $request{id};
-  
+
   print $server "$id\n";
-  
+
   my $read;
-  
-  foreach (keys %request) {
+
+  for (keys %request) {
     if ($request{$_}) {
       print $server "$_=$request{$_}\n";
     } else {
       $read = 1;
       print $server "$_\n";
     } # if
-  } # foreach
+  } # for
 
   print $server "end\n";
-  
+
   my ($response, %output);
-  
+
   while (defined ($response = <$server>)) {
     if ($response =~ /CQD Status: (-*\d+)/) {
       $status = $1;
       last;
     } # if
-    
+
     if ($read) {
       chomp $response; chop $response if $response =~ /\r$/;
-      
+
       my ($field, $value) = split /\@\@/, $response;
-      
+
       $output{$field} = $value;
     } else {
       push @output, $response;
     } # if
   } # while
-  
+
   chomp @output unless $read;
-  
+
   $self->disconnectFromServer;
-  
+
   if ($status != 0 or $read == 0) {
     return ($status, @output);
   } else {
@@ -487,9 +487,9 @@ sub execute (%) {
 } # execute
 
 sub startServer (;$$$$$) {
-  
+
   require 'Clearquest.pm';
-  
+
   my ($self, $port, $username, $password, $db, $dbset) = @_;
 
   $port     ||= $OPTS{CQD_PORT};
@@ -497,7 +497,7 @@ sub startServer (;$$$$$) {
   $password ||= $OPTS{CQD_PASSWORD};
   $db       ||= $OPTS{CQD_DATABASE};
   $dbset    ||= $OPTS{CQD_DBSET};
-  
+
   # Create new socket to communicate to clients with
   $self->{socket} = IO::Socket::INET->new(
     Proto     => 'tcp',
@@ -518,7 +518,7 @@ sub startServer (;$$$$$) {
 
   # Announce ourselves
   $self->_log ("CQD V$VERSION accepting clients at " . localtime);
-  
+
   # Now wait for an incoming request
   LOOP:
   my $client;
@@ -538,7 +538,7 @@ sub startServer (;$$$$$) {
 
       error "Can't fork: $!"
         unless defined ($childpid = fork);
-        
+
       if ($childpid) {
         $self->{pid} = $$;
 
@@ -600,7 +600,7 @@ L<POSIX>
 
 =head2 ClearSCM Perl Modules
 
-=begin man 
+=begin man
 
  DateUtils
  Display
index 74b0bd8..2d11280 100644 (file)
@@ -151,7 +151,7 @@ Database Set name (Default: From cq.conf)
 =back
 
 =cut
-  
+
 our (%RECORDS, %FIELDS);
 
 # FieldTypes ENUM
@@ -169,14 +169,14 @@ my $RECORD_TYPE      = 9;
 
 sub _callREST ($$$;%) {
   my ($self, $type, $url, $body, %parms) = @_;
-  
+
   # Set error and errmsg to no error
   $self->error (0);
   $self->{errmsg} = '';
-  
+
   # Upshift the call type as the calls are actually like 'GET' and not 'get'
   $type = uc $type;
-  
+
   # We only support these call types
   croak "Unknown call type \"$type\""
     unless $type eq 'GET'     or
@@ -186,7 +186,7 @@ sub _callREST ($$$;%) {
            $type eq 'PUT'     or
            $type eq 'DELETE'  or
            $type eq 'HEAD';
-  
+
   # If the caller did not give us authorization then use the login member we
   # already have in the object
   unless ($parms{Authorization}) {
@@ -198,10 +198,10 @@ sub _callREST ($$$;%) {
   if ($url =~ /oslc.where/) {
     $parms{'OSLC-Core-Version'} = '2.0';
   } # if
-  
+
   # Remove the host portion if any
   $url =~ s/^http.*$self->{server}//;
-  
+
   # Call the REST call (Different calls have different numbers of parameters)
   if ($type eq 'GET'     or
       $type eq 'DELETE'  or
@@ -211,29 +211,29 @@ sub _callREST ($$$;%) {
   } else {
     $self->{rest}->$type ($url, $body, \%parms);
   } # if
-  
+
   return $self->error;
 } # _callREST
 
 sub _getRecordName ($) {
   my ($self, $query) = @_;
-  
+
   $self->_callREST ('get', $query);
-  
+
   if ($self->error) {
     $self->errmsg ("Unable to get record name for $query");
-    
+
     return;
   } # if
 
   my %record = %{XMLin ($self->{rest}->responseContent)};
-  
+
   return $record{element}{name};
 } # _getRecordName
 
 sub _getAttachmentList ($$) {
   my ($self, $result, $fields) = @_;
-  
+
   croak ((caller(0))[3] . ' is not implemented');
 
   return;
@@ -247,14 +247,14 @@ sub _getInternalID ($$) {
   $query .= "rcm.name=$key";  
 
   $self->_callREST ('get', $query);
-  
+
   unless ($self->error) {
     my %result = %{XMLin ($self->{rest}->responseContent)};
 
     return $result{entry}{id};
   } else {
     $self->errmsg ("Record not found (Table: $table, Key: \"$key\")");
-    
+
     return $self->errmsg;
   } # unless
 } # _getInternalID
@@ -263,21 +263,21 @@ sub _getRecord ($$@) {
   my ($self, $table, $url, @fields) = @_;
 
   $self->{fields} = [$self->_setFields ($table, @fields)];
-    
+
   $self->_callREST ('get', $url);
-  
+
   return if $self->error;
 
   # Now parse the results
   my %result = %{XMLin ($self->{rest}->responseContent)};
-  
+
   if ($result{entry}{content}{$table}) {
     return $self->_parseFields ($table, %{$result{entry}{content}{$table}});
   } elsif (ref \%result eq 'HASH') {
     # The if test above will create an empty $result{entry}{content}. We need
     # to delete that
     delete $result{entry};
-    
+
     return $self->_parseFields ($table, %result);
   } else {
     return;
@@ -288,7 +288,7 @@ sub _getRecordID ($) {
   my ($self, $table) = @_;
 
   $self->records;
-  
+
   return $RECORDS{$table};
 } # _getRecordID
 
@@ -296,44 +296,44 @@ sub _getRecordURL ($$;@) {
   my ($self, $table, $url, @fields) = @_;
 
   $self->{fields} = [$self->_setFields ($table, @fields)];
-    
+
   $self->error ($self->_callREST ('get', $url));
-  
+
   return if $self->error;
-  
+
   return $self->_parseFields ($table, %{XMLin ($self->{rest}->responseContent)});
 } # _getRecordURL
 
 sub _getReferenceList ($$) {
   my ($self, $url, $field) = @_;
-  
+
   $self->error ($self->_callREST ('get', $url));
-  
+
   return if $self->error;
-  
+
   my %result = %{XMLin ($self->{rest}->responseContent)};
 
   my @values;
-  
+
   # Need to find the field array here...
   foreach my $key (keys %result) {
     if (ref $result{$key} eq 'ARRAY') {
       foreach (@{$result{$key}}) {
         push @values, $$_{'oslc_cm:label'};
       } # foreach
-      
+
       last;
     } elsif (ref $result{$key} eq 'HASH' and $result{$key}{'oslc_cm:label'}) {
       push @values, $result{$key}{'oslc_cm:label'};
     } # if
   } # foreach
-  
+
   return @values;
 } # _getReferenceList
 
 sub _parseCondition ($$) {
   my ($self, $table, $condition) = @_;
-  
+
   # Parse simple conditions only
   my ($field, $operator, $value);
 
@@ -354,13 +354,13 @@ sub _parseCondition ($$) {
       return "$field in [$value]"
     } # if
   } # if
-  
+
   if ($operator eq '=' and $value =~ /^null$/i) {
     return "$field in [\"\"]";
   } elsif ($operator eq '!=' and $value =~ /^null$/i) {
     return "$field in [*]";
   } # if
-  
+
   # Trim quotes if any:
   if ($value =~ /^\s*\'/) {
     $value =~ s/^\s*\'//;
@@ -369,17 +369,17 @@ sub _parseCondition ($$) {
     $value =~ s/^\s*\"//;
     $value =~ s/\"\s*$//;
   } # if
-  
+
   # Trim leading and trailing whitespace
   $value =~ s/^\s+//;
   $value =~ s/\s+$//;
-  
+
   # Convert datetimes to Zulu
   if ($self->fieldType ($table, $field) == $DATE_TIME and
       $value !~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/) {
     $value = Clearquest::_UTCTime ($value);        
   } # if
-  
+
   return "$field $operator \"$value\""; 
 } # _parseCondition
 
@@ -387,28 +387,28 @@ sub _parseConditional ($$) {
   my ($self, $table, $condition) = @_;
 
   return 'oslc_cm.query=' unless $condition;
-  
+
   my $parsedConditional;
-  
+
   # Special case when the condition is ultra simple
   if ($condition !~ /(\w+)\s*(==|=|!=|<>|<|>|<=|>=|in|is\s+null|is\s+not\s+null)\s*(.*)/i) {
     return "rcm.name=$condition";
   } # if  
-  
+
   # TODO: This section needs improvement to handle more complex conditionals
   while () {
     if ($condition =~ /(.+?)\s+(and|or)\s+(.+)/i) {
       my $leftSide = $self->_parseCondition ($table, $1);
-      
+
       $parsedConditional .= "$leftSide $2 ";
       $condition          = $3;
     } else {
       $parsedConditional .= $self->_parseCondition ($table, $condition);
-      
+
       last;
     } # if
   } # while
-    
+
   # TODO: How would this work if we have a condition like 'f1 = "value" and
   # f2 is not null'?
   if ($parsedConditional =~ /in \[\*\]/) {
@@ -420,16 +420,16 @@ sub _parseConditional ($$) {
 
 sub _parseFields ($%) {
   my ($self, $table, %record) = @_;
-  
+
   foreach my $field (keys %record) {
     if ($field =~ /:/     or
         $field eq 'xmlns' or
         grep {/^$field$/} @{$self->{fields}} == 0) {
       delete $record{$field};
-      
+
       next;
     } # if
-    
+
     my $fieldType = $self->fieldType ($table, $field);
 
     if (ref $record{$field} eq 'HASH') {      
@@ -441,7 +441,7 @@ sub _parseFields ($%) {
         $record{$field} = \@values;
       } elsif ($fieldType == $ATTACHMENT_LIST) {
         my @attachments = $self->_getAttachmentList ($record{$field}{'oslc_cm:collref'}, $field);
-          
+
         $record{$field} = \@attachments;
       } elsif ($fieldType == $RECORD_TYPE) {
         $record{$field} = $record{$field}{'oslc_cm:label'};
@@ -449,33 +449,33 @@ sub _parseFields ($%) {
         $record{$field} = undef;
       } # if
     } # if
-      
+
     $record{$field} ||= '' if $self->{emptyStringForUndef};
 
     if ($fieldType == $DATE_TIME) {
       $record{$field} = Clearquest::_UTC2Localtime $record{$field};
     } # if
   } # foreach
-  
+
   return %record;  
 } # _parseFields
 
 sub _parseRecordDesc ($) {
   my ($self, $table) = @_;
-  
+
   # Need to get fieldType info
   my $recordID = $self->_getRecordID ($table);
-  
+
   return unless $recordID;
-  
+
   my $url = "$self->{uri}/record-type/$recordID";
-  
+
   $self->_callREST ('get', $url);
-  
+
   return if $self->error;
-  
+
   my %result = %{XMLin ($self->{rest}->responseContent)};
-  
+
   # Reach in deep for field definitions
   my %fields = %{$result{element}{complexType}{choice}{element}};
 
@@ -520,15 +520,15 @@ sub _parseRecordDesc ($) {
     } else {
       $FIELDS{$table}{$_}{FieldType} = $UNKNOWN;
     } # if
-    
+
     if ($fields{$_}{'cq:systemOwned'} and $fields{$_}{'cq:systemOwned'} eq 'true') {
       $FIELDS{$table}{$_}{SystemField} = 1;
     } else { 
       $FIELDS{$table}{$_}{SystemField} = 0;
     } # if
   } # foreach
-  
-  return;  
+
+  return;
 } # _parseRecordDesc
 
 sub _isSystemField ($$) {
@@ -557,17 +557,17 @@ sub _setFields ($@) {
 
   # Cause %FIELDS to be expanded for $table
   $self->_parseRecordDesc ($table);
-    
+
   unless (@fields) {
     foreach ($self->fields ($table)) {
       unless ($self->{returnSystemFields}) {
         next if $FIELDS{$table}{$_}{SystemField}
       } # unless
-      
+
       push @fields, $_;
     } # foreach
   } # unless 
+
   push @fields, 'dbid' unless grep { /dbid/ } @fields;
 
   return @fields;
@@ -577,9 +577,9 @@ sub _setFieldValue ($$$) {
   my ($self, $table, $fieldName, $fieldValue) = @_;
 
   return if $self->_isSystemField ($table, $fieldName);
-  
+
   my $xml .= "<$fieldName>";
-    
+
   my $fieldType = $self->fieldType ($table, $fieldName);
 
   if ($fieldType == $STRING           or
@@ -589,39 +589,39 @@ sub _setFieldValue ($$$) {
     # Fix MULTILINE_STRINGs
     if ($fieldType == $MULTILINE_STRING and ref $fieldValue eq 'ARRAY') {
       chomp @{$fieldName};
-        
+
       $fieldValue= join "\n", @$fieldValue;
     } # if
-      
+
     $xml .= escapeHTML $fieldValue;
   } elsif ($fieldType == $REFERENCE) {
     my $tableReferenced = $self->fieldReference ($table, $fieldName);
-      
+
     if ($tableReferenced) {
       $xml .= $self->_getInternalID ($tableReferenced, $fieldValue);
     } else {
       $self->error (600);
       $self->errmsg ("Could not determine reference for $fieldName");
-        
+
       return; 
     } # if
   } elsif ($fieldType == $REFERENCE_LIST) {
     # We'll allow either an array reference or a single value, which we will
     # turn into an array
     my @values;
-      
+
     @values = ref $fieldValue eq 'ARRAY' ? @$fieldValue
                                          : ($fieldValue);
-                                               
+
     my $tableReferenced = $self->fieldReference ($table, $fieldName);
-      
+
     unless ($tableReferenced) {
       $self->error (600);
       $self->errmsg ("Could not determine reference for $fieldName");
-      
+
       return;
     } # if
-        
+
     foreach (@values) {
       my $internalID = $self->_getInternalID ($tableReferenced, $_);
 
@@ -630,7 +630,7 @@ sub _setFieldValue ($$$) {
       } else {
         $self->error (600);
         $self->errmsg ("Could not find a valid/active $tableReferenced with a key of \"$_\"");
-        
+
         return 
       } # if
     } # foreach
@@ -639,13 +639,13 @@ sub _setFieldValue ($$$) {
   } # if
 
   $xml .= "</$fieldName>\n";
-  
+
   return $xml;   
 } # _setFieldValue
 
 sub _startXML ($) {
   my ($table) = @_;
-  
+
   my $xml = << "XML";
 <?xml version="1.0" encoding="UTF-8"?>
 <$table
@@ -654,7 +654,7 @@ sub _startXML ($) {
   xmlns:dc="http://purl.org/dc/terms/"
   xmlns:oslc_cm="http://open-services.net/xmlns/cm/1.0/">
 XML
+
   return $xml
 } # _startXML
 
@@ -723,15 +723,15 @@ Error message (if any)
 
   # First process all fields in the @ordering, if specified
   $xml .= $self->_setFieldValue ($table, $_, $record{$_}) foreach (@ordering);
-  
+
   foreach my $field (keys %record) {
     next if InArray $field, @ordering;
-    
+
     $xml .= $self->_setFieldValue ($table, $field, $record{$field});
   } # foreach
-  
+
   $xml .= "</$table>";
-  
+
   $self->_callREST ('post', $uri, $xml);
 
   # Get the DBID of the newly created record  
@@ -744,7 +744,7 @@ Error message (if any)
 
 sub connect (;$$$$) {
   my ($self, $username, $password, $database, $dbset) = @_;
-  
+
 =pod
 
 =head2 connect (;$$$$)
@@ -795,7 +795,7 @@ Returns:
 
   if (ref $username eq 'HASH') {
     my %opts = %$username;
-    
+
     $self->{username} = delete $opts{CQ_USERNAME};
     $self->{password} = delete $opts{CQ_PASSWORD};
     $self->{database} = delete $opts{CQ_DATABASE};
@@ -806,17 +806,17 @@ Returns:
     $self->{database} = $database if $database;
     $self->{dbset}    = $dbset    if $dbset;
   } # if
-  
+
   # Set URI in case anything changed
   $self->{uri}      = "/cqweb/oslc/repo/$self->{dbset}/db/$self->{database}";
   $self->{loggedin} = 1;
-  
+
   return 1;
 } # connect
 
 sub connected () {
   my ($self) = @_;
-  
+
 =pod
 
 =head2 connected ()
@@ -848,7 +848,7 @@ Returns:
 =for html </blockquote>
 
 =cut
-  
+
   return $self->{loggedin};  
 } # connected
 
@@ -934,7 +934,7 @@ sub dbsets () {
 
 sub delete ($$) {
   my ($self, $table, $key) = @_;
-  
+
 =pod
 
 =head2 delete ($table, $key)
@@ -976,7 +976,7 @@ Error message (if any)
 =cut
 
   my $query = $self->_getInternalID ($table, $key);
-  
+
   # Need to remove $self->{server} from beginning of $query
   $query =~ s/^http.*$self->{server}//;
 
@@ -992,13 +992,13 @@ sub DESTROY () {
   # global destruction (like when you die or exit), the ordering of destruction
   # is unpredictable so we might not succeed.
   return unless $self->{rest};
-  
+
   # Delete session - ignore error as there's really nothing we can do if this
   # fails.
   $self->_callREST ('delete', '/cqweb/oslc/session/');
-  
+
   croak "Unable to release REST session in destructor" if $self->error;
-  
+
   return;
 } # DESTROY
 
@@ -1051,9 +1051,9 @@ Error number (if any)
 =cut
 
   return unless $self->{rest};
-  
+
   $self->_callREST ('delete', '/cqweb/oslc/session/');
-  
+
   return $self->error;
 } # disconnect
 
@@ -1106,10 +1106,10 @@ Last error message
       return $self->{errmsg};
     } else {
       my $response = $self->response;
-      
+
       if ($response and $response ne '') {
         my %xml = %{XMLin ($self->response)};
-    
+
         if ($xml{Error}{message}) {
           $self->{errmsg} = $xml{Error}{message};
         } elsif (ref $xml{message} ne 'HASH' and $xml{message}) {
@@ -1122,13 +1122,13 @@ Last error message
       } # if
     } # if
   } # if
-  
+
   return $self->{errmsg};
 } # errmsg
 
 sub error (;$) {
   my ($self, $error) = @_;
-  
+
 =pod
 
 =head2 error ($error)
@@ -1164,8 +1164,7 @@ Last error
 =for html </blockquote>
 
 =cut
-  
-  
+
   if (defined $error) {
     $self->{responseCode} = $error;
   } else {
@@ -1187,7 +1186,7 @@ Last error
 
 sub fields ($) {
   my ($self, $table) = @_;
-  
+
 =pod
 
 =head2 fields ($table)
@@ -1225,19 +1224,19 @@ Array of the fields names for $table
 =cut
 
   my $recordID = $self->_getRecordID ($table);
-  
+
   return unless $recordID;
-  
+
   my $url = "$self->{uri}/record-type/$recordID";
 
   $self->_callREST ('get', $url);
-  
+
   return if $self->error;
 
   my %result = %{XMLin ($self->{rest}->responseContent)};
-  
+
   my @fields = keys %{$result{element}{complexType}{choice}{element}};
-   
+
   return @fields; 
 } # fields
 
@@ -1283,7 +1282,7 @@ Fieldtype enum
 =for html </blockquote>
 
 =cut
-  
+
   # If we've already computed the fieldTypes for the fields in this table then
   # return the value
   if ($FIELDS{$table}) {
@@ -1360,7 +1359,7 @@ this is not a reference or reference list field.
 
 sub find ($;$@) {
   my ($self, $table, $condition, @fields) = @_;
-  
+
 =pod
 
 =head2 find ($;$@)
@@ -1413,34 +1412,34 @@ is also returned.
 
   $self->{url} = "$self->{uri}/record/?rcm.type=$table&"
                . $self->_parseConditional ($table, $condition);
-  
+
   @fields = $self->_setFields ($table, @fields);
-  
+
   # Remove dbid for find
   @fields = grep { $_ ne 'dbid' } @fields;
-  
+
   if (@fields) {
     $self->{url} .= "&oslc_cm.properties=";
     $self->{url} .= join ',', @fields;
   } # if
-  
+
   # Save some fields for getNext
   $self->{fields} = \@fields;
   $self->{table}  = $table;
-  
+
   $self->{url} .= "&oslc_cm.pageSize=1";
-  
+
   return $self->{url} unless wantarray;
-  
+
   # If the user wants an array then he wants ($reesult, $nbrRecs) and so we need
   # to go out and get that info.
   $self->_callREST ('get', $self->{url});
-  
+
   return (undef, 0) if $self->error;
 
   # Now parse the results
   my %result = %{XMLin ($self->{rest}->responseContent)};
-  
+
   return ($self->{url}, $result{'oslc_cm:totalCount'}{content});
 } # find
 
@@ -1511,7 +1510,7 @@ An hash representing the qualifying record.
 
 sub getDBID ($$;@) {
   my ($self, $table, $dbid, @fields) = @_;
-  
+
 =pod
 
 =head2 get ($table, $key, @fields)
@@ -1567,13 +1566,13 @@ An hash representing the qualifying record.
      $url .= $self->_getRecordID ($table);
      $url .= '-';
      $url .= $dbid;
-    
+
   if (@fields) {
     $url .= "?oslc_cm.properties=";
     $url .= 'dbid,' unless grep { /dbid/i } @fields;
     $url .= join ',', @fields;
   } # if
-  
+
   return $self->_getRecord ($table, $url);
 } # getDBID
 
@@ -1583,7 +1582,7 @@ sub getDynamicList () {
 
 sub getNext ($) {
   my ($self, $result) = @_;
-  
+
 =pod
 
 =head2 getNext ($)
@@ -1619,33 +1618,33 @@ Hash of name/value pairs for the @fields specified to find.
 =for html </blockquote>
 
 =cut
-  
+
   return unless $self->{url};
-  
+
   my $url = $self->{url};
 
   $self->_callREST ('get', $url);
-  
+
   return if $self->error;
 
   # Now parse the results
   my %result = %{XMLin ($self->{rest}->responseContent)};
-  
+
   # Get the next link
   undef $self->{url};
-  
+
   if (ref $result{link} eq 'ARRAY') {
     foreach (@{$result{link}}) {
       if ($$_{rel} eq 'next') {
         ($self->{url}) = ($$_{href} =~ /^http.*$self->{server}(.*)/);
-  
+
         last;
       } # if
     } # foreach
   } # if
-  
+
   my %record;
-  
+
   if (ref $result{entry}{content}{$self->{table}} eq 'HASH') {
     %record = $self->_parseFields ($self->{table}, %{$result{entry}{content}{$self->{table}}});
   } elsif (ref $result{entry} eq 'HASH') {
@@ -1653,18 +1652,18 @@ Hash of name/value pairs for the @fields specified to find.
       %record = $self->_getRecordURL ($self->{table}, $result{entry}{id}, @{$self->{fields}});
     } # if
   } # if
-  
+
   # Get dbid
   if ($result{entry}{link}{href} =~ /-(\d+)$/) {
     $record{dbid} = $1;
   } # if
-  
+
   return %record;
 } # getNext
 
 sub key ($$) {
   my ($self, $table, $dbid) = @_;
-  
+
 =pod
 
 =head2 key ($$)
@@ -1710,7 +1709,7 @@ Returns:
 
 sub modify ($$$$;@) {
   my ($self, $table, $key, $action, $values, @ordering) = @_;
-  
+
 =pod
 
 =head2 modify ($table, $key, $action, $values, @ordering)
@@ -1778,36 +1777,36 @@ Error message (if any)
 
   my %values = %$values;
   my $xml    = _startXML $table;
-  
+
   $action ||= 'Modify';
-  
+
   my $query = $self->_getInternalID ($table, $key);
-  
+
   # Remove host portion
   $query =~ s/^http.*$self->{server}//;
-    
+
   # Add on action
   $query .= "?rcm.action=$action";
-  
+
   # First process all fields in the @ordering, if specified
   $xml .= $self->_setFieldValue ($table, $_, $values{$_}) foreach (@ordering);
-  
+
   foreach my $field (keys %values) {
     next if InArray $field, @ordering;
-    
+
     $xml .= $self->_setFieldValue ($table, $field, $values{$field});
   } # foreach
-  
+
   $xml .= "</$table>";
 
   $self->_callREST ('put', $query, $xml);
-  
+
   return $self->errmsg;
 } # modify
 
 sub modifyDBID ($$$$;@) {
   my ($self, $table, $dbid, $action, $values, @ordering) = @_;
-  
+
 =pod
 
 =head2 modifyDBID ($table, $dbid, $action, %update)
@@ -1875,36 +1874,36 @@ Error message (if any)
 
   my %values = %$values;
   my $xml    = _startXML $table;
-  
+
   $action ||= 'Modify';
-  
+
   my $query  = "$self->{uri}/record/";
      $query .= $self->_getRecordID ($table);
      $query .= '-';
      $query .= $dbid;
-  
+
   # Add on action
   $query .= "?rcm.action=$action";
-  
+
   # First process all fields in the @ordering, if specified
   $xml .= $self->_setFieldValue ($table, $_, $values{$_}) foreach (@ordering);
-  
+
   foreach my $field (keys %values) {
     next if InArray $field, @ordering;
-    
+
     $xml .= $self->_setFieldValue ($table, $field, $values{$field});
   } # foreach
-  
+
   $xml .= "</$table>";
 
   $self->_callREST ('put', $query, $xml);
-  
+
   return $self->errmsg;
 } # modifyDBID
 
 sub new (;%) {
   my ($class, $self) = @_;
-  
+
 =pod
 
 =head2 new (%parms)
@@ -1941,7 +1940,7 @@ Returns:
 =cut
 
   $self->{server} ||= $Clearquest::OPTS{CQ_SERVER};
-  
+
   $$self{base_url} = "$self->{server}/cqweb/oslc",
   $$self{uri}      = "/cqweb/oslc/repo/$self->{dbset}/db/$self->{database}",
   $$self{login}    = {
@@ -1950,19 +1949,19 @@ Returns:
     Authorization       => 'Basic '
       . encode_base64 "$self->{username}:$self->{password}",
   };
-  
+
   bless $self, $class;
-  
+
   # We create this UserAgent and Cookie Jar so we can set cookies to be 
   # remembered and passed back and forth automatically. By doing this we re-use
   # the JSESSIONID cookie we allows us to reuse our login and to dispose of the
   # login session properly when we are destroyed.
   my $userAgent = LWP::UserAgent->new;
-  
+
   # Set the cookie jar to use in-memory cookie management, cookies can be
   # persisted to disk, see HTTP::Cookies for more info.
   $userAgent->cookie_jar (HTTP::Cookies->new);
-  
+
   $self->{rest} = REST::Client->new (
     host      => $self->{server},
     timeout   => 15,
@@ -1975,7 +1974,7 @@ Returns:
 
 sub records () {
   my ($self) = @_;
-  
+
 =pod
 
 =head2 records ()
@@ -2011,27 +2010,27 @@ Hash of records and their record numbers
 =cut
 
   return if %RECORDS;
-  
+
   my $url = "$self->{uri}/record-type/";
 
   $self->_callREST ('get', $url);
-  
+
   unless ($self->error) {
     my %result = %{XMLin ($self->{rest}->responseContent)};
 
     foreach my $uri (keys %{$result{entry}}) {
       my ($recordID) = ($uri =~ /\/(\d+)/);
-      
+
       $RECORDS{$result{entry}{$uri}{title}} = $recordID;
     } # foreach
   } # unless
-  
+
   return %RECORDS;
 } # records
 
 sub response () {
   my ($self) = @_;
-  
+
 =pod
 
 =head2 response ()
index 6a514c5..d016e4e 100644 (file)
@@ -87,14 +87,14 @@ sub new (;%) {
   my ($class, %parms) = @_;
 
   my $self;
-  
+
   $parms{CQ_DATABASE}      ||= $Clearquest::OPTS{CQ_DATABASE};
   $parms{CQ_USERNAME}      ||= $Clearquest::OPTS{CQ_USERNAME};
   $parms{CQ_PASSWORD}      ||= $Clearquest::OPTS{CQ_PASSWORD};
   $parms{CQ_DBSET}         ||= $Clearquest::OPTS{CQ_DBSET};
   $parms{CQ_SERVER}        ||= $Clearquest::OPTS{CQ_SERVER};
   $parms{CQ_PORT}          ||= $Clearquest::OPTS{CQ_PORT};
-  
+
   $parms{CQ_MULTITHREADED} = $Clearquest::OPTS{CQ_MULTITHREADED} 
     unless defined $parms{CQ_MULTITHREADED};
 
@@ -110,7 +110,7 @@ sub new (;%) {
   $self->{port}          = $parms{CQ_PORT};
   $self->{module}        = $parms{CQ_MODULE};
   $self->{multithreaded} = $parms{CQ_MULTITHREADED};
-  
+
   return bless $self, $class;
 } # new
 
@@ -120,7 +120,7 @@ sub _tag ($) {
   my $tag  = YMDHMS;
      $tag .= ' ';
      $tag .= $self->{pid} ? '[' . abs ($self->{pid}) . '] ' : '';
-  
+
   return "$tag$msg";
 } # _tag
 
@@ -128,32 +128,32 @@ sub _verbose ($) {
   my ($self, $msg) = @_;
 
   verbose $self->_tag ($msg);
-  
+
   return;
 } # _verbose
 
 sub _debug ($) {
   my ($self, $msg) = @_;
-  
+
   debug $self->_tag ($msg);
-  
+
   return;
 } # _debug
 
 sub _log ($) {
   my ($self, $msg) = @_;
-  
+
   display $self->_tag ($msg);
-  
+
   return;
 } # log
 
 sub _funeral () {
   debug "Entered _funeral";
-  
+
   while (my $childpid = waitpid (-1, WNOHANG) > 0) {
     my $status = $?;
-  
+
     if ($childpid != -1) {
       local $SIG{CHLD} = \&_funeral;
 
@@ -164,21 +164,21 @@ sub _funeral () {
         if $status;
     } # if
   } # while
-  
+
   return;
 } # _funeral
 
 sub _endServer () {
   display "Clearquest::Server V$VERSION shutdown at " . localtime;
-  
+
   # Kill process group
   kill 'TERM', -$$;
-  
+
   # Wait for all children to die
   while (wait != -1) {
     # do nothing
   } # while 
-  
+
   # Now that we are alone, we can simply exit
   exit;
 } # _endServer
@@ -186,39 +186,39 @@ sub _endServer () {
 sub _restartServer () {
   # Not sure what to do on a restart server
   display 'Entered _restartServer';
-  
+
   return;
 } # _restartServer
 
 sub _printStatus ($) {
   my ($self, $client) = @_;
-  
+
   my $status = $self->{clearquest}->error;
-  
+
   $status ||= 0;
-  
+
   $self->_debug ("Printing status: " . __PACKAGE__ . " Status: $status");
-  
+
   print $client __PACKAGE__ . " Status: $status\n";
-  
+
   $self->_debug ("After print");
-  
+
   return; 
 } # printStatus
 
 sub _connectToClearquest ($$$$) {
   my ($self, $database, $username, $password, $dbset) = @_;
-  
+
   my %parms;
-  
+
   $parms{CQ_DATABASE} = $database;
   $parms{CQ_USERNAME} = $username;
   $parms{CQ_PASSWORD} = $password;
   $parms{CQ_DBSET}    = $dbset;
-  
+
   # The server always uses the standard Clearquest API
   $parms{CQ_MODULE} = 'api';
-  
+
   # Connect to Clearquest database
   $self->{clearquest} = Clearquest->new (%parms);
 
@@ -227,22 +227,22 @@ sub _connectToClearquest ($$$$) {
         . " for $self->{clientname}");
 
   $self->{loggedin} = $self->{clearquest}->connect;
-  
+
   return $self->{loggedin};
 } # _connectToClearquest
 
 sub _processCommand ($$@) {
   my ($self, $client, $call, @parms) = @_;
-  
+
   $self->_debug ("Client wishes to execute $call");
 
   if ($call eq 'end') {
     $self->_verbose ("Serviced requests from $self->{clientname}");
-    
+
     close $client;
 
     $self->disconnectFromClient;
-      
+
     return 1;
   } elsif ($call eq 'open') {
     debug "connectToClearquest";
@@ -261,7 +261,7 @@ sub _processCommand ($$@) {
     $self->_printStatus ($client);    
   } elsif ($call eq 'get') {
     my %record = $self->{clearquest}->get (@parms);
-    
+
     unless ($self->{clearquest}->error) {
       foreach my $field (keys %record) {
         # TODO: Need to handle field types better...
@@ -269,20 +269,20 @@ sub _processCommand ($$@) {
           foreach (@{$record{$field}}) {
             # Change \n's to &#10;
             s/\r\n/&#10;/gm;
-      
+
             print $client "$field\@\@$_\n";
           } # foreach
         } else {
           # Change \n's to &#10;
           $record{$field} =~ s/\r\n/&#10;/gm;
-      
+
           print $client "$field\@\@$record{$field}\n";
         } # if
       } # foreach
     } else {
       print $client $self->{clearquest}->errmsg . "\n";
     } # unless
-    
+
     $self->_printStatus ($client);
   } elsif ($call eq 'find') {
     my ($result, $nbrRecs) = $self->{clearquest}->find (@parms);
@@ -292,14 +292,14 @@ sub _processCommand ($$@) {
     } else {
       # Store away $result so we can use it later
       $self->{result} = $result;
-      
+
       print $client "$result\n$nbrRecs\n";
     } # if
 
     $self->_printStatus ($client);       
   } elsif ($call eq 'getnext') {
     my %record = $self->{clearquest}->getNext ($self->{result});
-    
+
     unless ($self->{clearquest}->error) {
       foreach my $field (keys %record) {
         # TODO: Need to handle field types better...
@@ -307,37 +307,37 @@ sub _processCommand ($$@) {
           foreach (@{$record{$field}}) {
             # Change \n's to &#10;
             s/\r\n/&#10;/gm;
-      
+
             print $client "$field\@\@$_\n";
           } # foreach
         } else {
           # Change \n's to &#10;
           $record{$field} =~ s/\r\n/&#10;/gm;
-      
+
           print $client "$field\@\@$record{$field}\n";
         } # if
       } # foreach
     } else {
       print $client $self->{clearquest}->errmsg . "\n";
     } # unless
-    
+
     $self->_printStatus ($client);
   } elsif ($call eq 'getdynamiclist') {
     # TODO Better error handling/testing
     my @entry = $self->{clearquest}->getDynamicList (@parms);
-    
+
     print $client "$_\n" foreach @entry;
-    
+
     $self->_printStatus ($client);
   } elsif ($call eq 'dbsets') {
     # TODO Better error handling/testing
     print $client "$_\n" foreach ($self->{clearquest}->DBSets);
-    
+
     $self->_printStatus ($client);
   } elsif ($call eq 'key') {
     # TODO Better error handling/testing
     print $client $self->{clearquest}->key (@parms) . "\n";
-    
+
     $self->_printStatus ($client);
   } elsif ($call eq 'modify' or $call eq 'modifyDBID') {
     my $table  = shift @parms;
@@ -345,29 +345,29 @@ sub _processCommand ($$@) {
     my $action = shift @parms;
 
     # Need to turn off strict for eval here...
-    my ($values, @ordering);      
+    my ($values, @ordering);
     no strict;
     eval $parms[0];
-    
+
     $values = $VAR1;
     use strict;
-    
+
     @ordering = @{$parms[1]} if ref $parms[1] eq 'ARRAY';
-  
+
     my $errmsg;
-    
+
     if ($call eq 'modify') {
       $errmsg = $self->{clearquest}->modify ($table, $key, $action, $values, @ordering);
     } elsif ($call eq 'modifyDBID') {
       $errmsg = $self->{clearquest}->modifyDBID ($table, $key, $action, $values, @ordering);      
     } # if
-    
+
     print $client "$errmsg\n" if $errmsg ne '';
 
     $self->_printStatus ($client);
   } elsif ($call eq 'add') {
     my $dbid = $self->{clearquest}->add (@parms);
-    
+
     if ($self->{clearquest}->error) {
       print $client 'ERROR: ' . $self->{clearquest}->errmsg () . "\n";
     } # if
@@ -384,12 +384,12 @@ sub _processCommand ($$@) {
   } else {
     $self->{clearquest}->{errnbr} = -1;
     $self->{clearquest}->{errmsg} = "Unknown call $call";
-    
+
     print $client $self->{clearquest}->errmsg . "\n";
-    
+
     $self->_printStatus ($client);
   } # if
-  
+
   return;
 } # _processCommand
 
@@ -400,28 +400,28 @@ sub _serviceClient ($) {
 
   # Set autoflush for client
   $client->autoflush if $client;
-  
+
   my $line;
-  
+
   $self->_debug ("Reading request from client");
-  
+
   while ($line = <$client>) {
     $self->_debug ("Request read: $line");
-    
+
     if ($line) {
       chomp $line; chop $line if $line =~ /\r$/;
     } else {
       $self->_verbose ("Host $self->{clientname} went away!");
-      
+
       close $client;
-      
+
       return;
     } # if
 
     if ($line =~ /^shutdown/i) {
       if ($self->{server}) {
         $self->_verbose ("$self->{clientname} requested to shutdown the server");
-          
+
         print $client __PACKAGE__ . " Status: 0\n";
       } # if
 
@@ -430,26 +430,26 @@ sub _serviceClient ($) {
 
       exit 1;
     } # if
-    
+
     # Parse command line
     my ($call, @parms);
-      
+
     if ($line =~ /^\s*(\S+)\s+(.*)/) {
       $call = lc $1;
-      
+
       no strict;
       eval $2;
-      
+
       @parms = @$VAR1;
       use strict;
-      
+
       my $i = 0;
-      
+
       foreach (@parms) {
         if (/^\$VAR1/) {
           no strict;
           eval;
-        
+
           $parms[$i++] = $VAR1;
           use strict;
         } else {
@@ -461,7 +461,7 @@ sub _serviceClient ($) {
       @parms = ();
     } else {
       my $errmsg = "Garbled command line: '$line'";
-      
+
       if ($self->{clearquest}) {
         $self->{clearquest}->{errnbr} = -1;
         $self->{clearquest}->{errmsg} = $errmsg;
@@ -470,17 +470,17 @@ sub _serviceClient ($) {
       } else {
         print "$errmsg\n";
       } # if
-      
+
       $self->_printStatus ($client);
-  
+
       return;
     } # if
-    
+
     $self->_debug ("Processing command $call @parms");
-    
+
     last if $self->_processCommand ($client, $call, @parms);
   } # while
-  
+
   return;
 }  # _serviceClient
 
@@ -488,9 +488,9 @@ sub multithreaded (;$) {
   my ($self, $newValue) = @_;
 
   my $oldValue = $self->{multithreaded};
-  
+
   $self->{multithreaded} = $newValue if $newValue;
-  
+
   return $oldValue
 } # multithreaded
 
@@ -502,27 +502,27 @@ sub disconnectFromClient () {
 
   $self->_verbose ("Disconnected from client $self->{clientname}")
     if $self->{clientname};
-  
+
   undef $self->{clientname};
-        
+
   return;
 } # disconnectFromClient  
 
 sub DESTROY () {
   my ($self) = @_;
-  
-    $self->disconnectFromClient;
-  
+
+  $self->disconnectFromClient;
+
   if ($self->{socket}) {
-   close $self->{socket};
-   
-   undef $self->{socket};
-  } # if  
+    close $self->{socket};
+
+    undef $self->{socket};
+  } # if
 } # DESTROY
-  
+
 sub startServer () {
   my ($self) = @_;
-  
+
   # Create new socket to communicate to clients with
   $self->{socket} = IO::Socket::INET->new (
     Proto     => 'tcp',
@@ -536,9 +536,9 @@ sub startServer () {
 
   # Announce ourselves
   $self->_log (__PACKAGE__ . " V$VERSION accepting clients at " . localtime);
-  
+
   $SIG{HUP}  = \&_endServer;
-  
+
   # Now wait for an incoming request
   my $client;
 
@@ -551,10 +551,10 @@ sub startServer () {
       } else {
         error "Accept called failed (Error: $?) - $!", 1;
       } # if
-    } # if    
-    
+    } # if
+
     my $hostinfo = gethostbyaddr $client->peeraddr;
-    
+
     $self->{clientname} = $hostinfo ? $hostinfo->name : $client->peerhost;
 
     $self->_verbose ("$self->{clientname} is requesting service");
@@ -568,7 +568,7 @@ sub startServer () {
 
       error "Can't fork: $!"
         unless defined ($childpid = fork);
-        
+
       if ($childpid) {
         $self->{pid} = $$;
 
@@ -585,18 +585,18 @@ sub startServer () {
       } else {
         # In child process - ServiceClient
         $self->{pid} = $$;
-        
+
         # Now exec the caller but set STDIN to be the socket. Also pass
         # -serviceClient to the caller which will need to handle that and call
         # _serviceClient.
         $self->_debug ("Client: $client");
         open STDIN, '+<&', $client
           or croak "Unable to dup client";
-        
+
         my $cmd = "cqperl \"$FindBin::Bin/$FindBin::Script -serviceClient=$self->{clientname} -verbose -debug";
-        
+
         $self->_debug ("Execing: $cmd");
-        
+
         exec 'cqperl', "\"$FindBin::Bin/$FindBin::Script\"", "-serviceClient=$self->{clientname}", '-verbose', '-debug'
           or croak "Unable to exec $cmd";
       } # if
@@ -604,7 +604,7 @@ sub startServer () {
       $self->_serviceClient ($client);
     } # if
   } # while
-  
+
   # On Windows we can't catch SIGCHLD so we need to loop around. Ugly!
   goto LOOP if $^O =~ /win/i;
 } # startServer
diff --git a/lib/Machines.pm b/lib/Machines.pm
new file mode 100755 (executable)
index 0000000..76c1dfb
--- /dev/null
@@ -0,0 +1,357 @@
+=pod\r
+\r
+=head1 NAME $RCSfile: Machines.pm,v $\r
+\r
+Object oriented interface to list of managed machines\r
+\r
+=head1 VERSION\r
+\r
+=over\r
+\r
+=item Author:\r
+\r
+Andrew DeFaria <Andrew@DeFaria.com>\r
+\r
+=item Revision:\r
+\r
+$Revision: 1.0 $\r
+\r
+=item Created:\r
+\r
+Thu, Jul 12, 2018  5:11:44 PM\r
+\r
+=item Modified:\r
+\r
+$Date: $\r
+\r
+=back\r
+\r
+=head1 SYNOPSIS\r
+\r
+Perl module to specify a list of managed machines for rexec.pl\r
+\r
+  $machines = Machines->new (filename => "/opt/clearscm/data/machines");\r
+\r
+  my @machines = $machines->all;\r
+\r
+  my @linux_machines = $machines->select(condition => 'OS = "linux"');\r
+\r
+=head1 DESCRIPTION\r
+\r
+Machines is an OO interface to a list of managed machines. By default it parses\r
+a file that contains machine names and other identifying information.\r
+\r
+=head1 ROUTINES\r
+\r
+The following routines are exported:\r
+\r
+=cut\r
+\r
+package Machines;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+use base 'Exporter';\r
+\r
+use Carp;\r
+\r
+sub _parseFile() {\r
+  my ($self) = @_;\r
+\r
+  my %machines;\r
+\r
+  # Simple parse for now\r
+  open my $machineFile, '<', $self->{filename}\r
+    or croak "Unable to open $self->{filename} - $!";\r
+\r
+  while (<$machineFile>) {\r
+    chomp;\r
+\r
+    next if /^#/; # Skip comments\r
+\r
+    my ($name, $model, $os, $ccver, $owner, $usage) = split /:/;\r
+\r
+    my %machineInfo = (\r
+      model => $model,\r
+      os    => $os,\r
+      ccver => $ccver,\r
+      owner => $owner,\r
+      usage => $usage,\r
+    );\r
+\r
+    $machines{$name} = \%machineInfo;\r
+  } # while\r
+\r
+  close $machineFile;\r
+\r
+  return \%machines;\r
+} # _parseFile\r
+\r
+sub new(;%){\r
+  my ($class, %parms) = @_;\r
+\r
+=pod\r
+\r
+=head2 new (<parms>)\r
+\r
+Construct a new Machines object. The following OO style arguments are\r
+supported:\r
+\r
+Parameters:\r
+\r
+=for html <blockquote>\r
+\r
+=over\r
+\r
+=item filename:\r
+\r
+Filename to parse\r
+\r
+=item path:\r
+\r
+Path where file resides\r
+\r
+=back\r
+\r
+=for html </blockquote>\r
+\r
+Returns::\r
+\r
+=for html <blockquote>\r
+\r
+=over\r
+\r
+=item Machines object\r
+\r
+=back\r
+\r
+=for html </blockquote>\r
+\r
+=cut\r
+\r
+  $parms{filename} ||= 'machines';\r
+\r
+  if (! -r $parms{filename}) {\r
+    croak "Unable to read $parms{filename}";\r
+  } # if\r
+\r
+  my $self = bless {\r
+    filename => $parms{filename},\r
+  }, $class; # bless\r
+\r
+  # Parse file\r
+  $self->{machines} = $self->_parseFile;\r
+\r
+  return $self;\r
+} # new\r
+\r
+sub select(;$) {\r
+  my ($self, $condition) = @_;\r
+\r
+=pod\r
+\r
+=head3 select\r
+\r
+Return machines that qualify based on $condition\r
+\r
+Parameters:\r
+\r
+=for html <blockquote>\r
+\r
+=over\r
+\r
+=item $condition\r
+\r
+Condition to apply to machine list\r
+\r
+=back\r
+\r
+=for html </blockquote>\r
+\r
+Returns:\r
+\r
+=for html <blockquote>\r
+\r
+=over\r
+\r
+=item Array of qualifying machines\r
+\r
+=back\r
+\r
+=for html </blockquote>\r
+\r
+=cut\r
+\r
+  $condition //= '';\r
+\r
+  if ($condition) {\r
+       croak "Not supporting conditions yet";\r
+  } else {\r
+    return %{$self->{machines}};\r
+  } # if\r
+} # select\r
+\r
+sub GetSystem($) {\r
+  my ($self, $systemName) = @_;\r
+\r
+  return;\r
+} # getSystem\r
+\r
+sub AddSystem(%) {\r
+  my ($self, %system) = @_;\r
+\r
+  return;\r
+} # addSystem\r
+\r
+sub ChangeSystem(%){\r
+  my ($self, %system) = @_;\r
+\r
+  return;\r
+} # changeSystem\r
+\r
+sub DeleteSystem($) {\r
+  my ($self, $systemName) = @_;\r
+\r
+  return;\r
+} # deleteSystem\r
+\r
+sub DumpSystems(;$) {\r
+  my ($self, $filename) = @_;\r
+\r
+  $filename ||= 'machines';\r
+\r
+  open my $file, '>', $filename\r
+    or croak "Unable to open $filename for writing - $!";\r
+\r
+  # Write header\r
+  print $file <<"END";\r
+################################################################################\r
+#\r
+# File:         $filename\r
+# Description:  Dump of machines for use with rexec.pl\r
+# Author:       Andrew\@DeFaria.com\r
+#\r
+################################################################################\r
+# Column 1 Machine name\r
+# Column 2 Alias\r
+# Column 3 Active\r
+# Column 4 Admin name\r
+# Column 5 Admin email\r
+# Column 6 OS version\r
+# Column 7 OS Type\r
+# Column 8 Last heard from\r
+# Column 9 Description\r
+END\r
+\r
+  # Write out machine info\r
+  my @fields = qw(name alias active admin email os type lastheardfrom description);\r
+\r
+  for my $record ($self->select) {\r
+    my %machine = %$record;\r
+\r
+    for (@fields) {\r
+      print $file "$machine{$_}|"\r
+    } # for\r
+\r
+    print $file "\n";\r
+  } # for\r
+\r
+  close $file;\r
+\r
+  return;\r
+} # DumpSystems\r
+\r
+sub ReadSystemsFile(;$) {\r
+  my ($self, $filename) = @_;\r
+\r
+  $filename ||= 'machines';\r
+\r
+  open my $file, '<', $filename\r
+    or croak "Unable to open $filename - $!";\r
+\r
+  my @systems;\r
+\r
+  while (<$file>) {\r
+    chomp;\r
+\r
+    next if /^#/;\r
+\r
+    my ($name, $model, $osver, $ccver, $owner, $usage) = split ':';\r
+    my %system = (\r
+      name        => $name,\r
+      model       => $model,\r
+      ccver       => $ccver,\r
+      admin       => $owner,\r
+      os          => $osver,\r
+      type        => 'Unix',\r
+      description => $usage,\r
+    );\r
+\r
+    push @systems, \%system;\r
+  } # while\r
+\r
+  close $file;\r
+\r
+  return @systems;\r
+} # ReadSystemsFile\r
+\r
+1;\r
+\r
+=pod\r
+\r
+=head2 CONFIGURATION AND ENVIRONMENT\r
+\r
+DEBUG: If set then $debug in this module is set.\r
+\r
+VERBOSE: If set then $verbose in this module is set.\r
+\r
+=head2 DEPENDENCIES\r
+\r
+=head3 Perl Modules\r
+\r
+L<File::Spec>\r
+\r
+L<IO::Handle>\r
+\r
+=head3 ClearSCM Perl Modules\r
+\r
+=for html <p><a href="/php/scm_man.php?file=lib/DateUtils.pm">DateUtils</a></p>\r
+\r
+=for html <p><a href="/php/scm_man.php?file=lib/Display.pm">Display</a></p>\r
+\r
+=for html <p><a href="/php/scm_man.php?file=lib/Mail.pm">Mail</a></p>\r
+\r
+=for html <p><a href="/php/scm_man.php?file=lib/OSDep.pm">OSDep</a></p>\r
+\r
+=for html <p><a href="/php/scm_man.php?file=lib/Utils.pm">Utils</a></p>\r
+\r
+=head2 INCOMPATABILITIES\r
+\r
+None yet...\r
+\r
+=head2 BUGS AND LIMITATIONS\r
+\r
+There are no known bugs in this module.\r
+\r
+Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.\r
+\r
+=head2 LICENSE AND COPYRIGHT\r
+\r
+This Perl Module is freely available; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License as\r
+published by the Free Software Foundation; either version 2 of the\r
+License, or (at your option) any later version.\r
+\r
+This Perl Module is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+General Public License (L<http://www.gnu.org/copyleft/gpl.html>) for more\r
+details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this Perl Module; if not, write to the Free Software Foundation,\r
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+reserved.\r
+\r
+=cut\r
diff --git a/lib/Machines/MySQL.pm b/lib/Machines/MySQL.pm
new file mode 100755 (executable)
index 0000000..398fd8f
--- /dev/null
@@ -0,0 +1,242 @@
+=pod\r
+\r
+=head1 NAME $RCSfile: MySQL.pm,v $\r
+\r
+MySQL Backend for Machines module\r
+\r
+=head1 VERSION\r
+\r
+=over\r
+\r
+=item Author\r
+\r
+Andrew DeFaria <Andrew@DeFaria.com>\r
+\r
+=item Revision\r
+\r
+$Revision: $\r
+\r
+=item Created\r
+\r
+Mon, Jul 16, 2018 10:13:12 AM\r
+\r
+=item Modified\r
+\r
+$Date: $\r
+\r
+=back\r
+\r
+=head1 SYNOPSIS\r
+\r
+Interfaces to a MySQL backend for machine information\r
+\r
+=head1 DESCRIPTION\r
+\r
+The rexec.pl script allows you to execute an arbitrary command on a set of\r
+machines, however what set of machines? Primative exeuction involves just a\r
+flat file with machine information listed in it. This module instead provides\r
+a MySQL backend for this machine data.\r
+\r
+=head1 ROUTINES\r
+\r
+The following methods are available:\r
+\r
+=cut\r
+\r
+package Machines::MySQL;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+use Carp;\r
+use DBI;\r
+\r
+use parent qw(Machines);\r
+\r
+our $VERSION  = '$Revision: 1.0 $';\r
+   ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);\r
+\r
+my %MACHINEOPTS = (\r
+  SERVER   => 'localhost',\r
+  USERNAME => 'machines',\r
+  PASSWORD => 'w0rk$harder',\r
+);\r
+\r
+sub _connect (;$) {\r
+  my ($self, $dbserver) = @_;\r
+\r
+  $dbserver ||= $MACHINEOPTS{SERVER};\r
+\r
+  my $dbname   = 'machines';\r
+  my $dbdriver = 'mysql';\r
+\r
+  $self->{db} = DBI->connect (\r
+    "DBI:$dbdriver:$dbname:$dbserver",\r
+    $MACHINEOPTS{USERNAME},\r
+    $MACHINEOPTS{PASSWORD},\r
+    {PrintError => 0},\r
+  ) or croak (\r
+    "Couldn't connect to $dbname database "\r
+  . "as $MACHINEOPTS{USERNAME}\@$MACHINEOPTS{SERVER}"\r
+  );\r
+\r
+  $self->{dbserver} = $dbserver;\r
+\r
+  return;\r
+} # _connect\r
+\r
+sub _checkRequiredFields ($$) {\r
+  my ($fields, $rec) = @_;\r
+\r
+  for my $fieldname (@$fields) {\r
+    my $found = 0;\r
+\r
+    for (keys %$rec) {\r
+      if ($fieldname eq $_) {\r
+        $found = 1;\r
+        last;\r
+      } # if\r
+    } # for\r
+\r
+    return "$fieldname is required"\r
+      unless $found;\r
+  } # for\r
+\r
+  return;\r
+} # _checkRequiredFields\r
+\r
+# Internal methods\r
+sub _dberror ($$) {\r
+  my ($self, $msg, $statement) = @_;\r
+\r
+  my $dberr    = $self->{db}->err;\r
+  my $dberrmsg = $self->{db}->errstr;\r
+\r
+  $dberr    ||= 0;\r
+  $dberrmsg ||= 'Success';\r
+\r
+  my $message = '';\r
+\r
+  if ($dberr) {\r
+    my $function = (caller (1)) [3];\r
+\r
+    $message = "$function: $msg\nError #$dberr: $dberrmsg\n"\r
+             . "SQL Statement: $statement";\r
+  } # if\r
+\r
+  return $dberr, $message;\r
+} # _dberror\r
+\r
+sub _formatValues (@) {\r
+  my ($self, @values) = @_;\r
+\r
+  my @returnValues;\r
+\r
+  # Quote data values\r
+  push @returnValues, $_ eq '' ? 'null' : $self->{db}->quote ($_)\r
+    for (@values);\r
+\r
+  return @returnValues;\r
+} # _formatValues\r
+\r
+sub _formatNameValues (%) {\r
+  my ($self, %rec) = @_;\r
+\r
+  my @nameValueStrs;\r
+\r
+  push @nameValueStrs, "$_=" . $self->{db}->quote ($rec{$_})\r
+    for (keys %rec);\r
+\r
+  return @nameValueStrs;\r
+} # _formatNameValues\r
+\r
+sub _addRecord ($%) {\r
+  my ($self, $table, %rec) = @_;\r
+\r
+  my $statement  = "insert into $table (";\r
+     $statement .= join ',', keys %rec;\r
+     $statement .= ') values (';\r
+     $statement .= join ',', $self->_formatValues (values %rec);\r
+     $statement .= ')';\r
+\r
+  my ($err, $msg);\r
+\r
+  $self->{db}->do ($statement);\r
+\r
+  return $self->_dberror ("Unable to add record to $table", $statement);\r
+} # _addRecord\r
+\r
+sub _getRecords ($;$) {\r
+  my ($self, $table, $condition) = @_;\r
+\r
+  my ($err, $msg);\r
+\r
+  my $statement  = "select * from $table";\r
+\r
+  if ($condition) {\r
+    $condition .= ' and ';\r
+  } # if\r
+\r
+  $condition .= 'active = "true"';\r
+  $statement .= " where $condition";\r
+\r
+  my $sth = $self->{db}->prepare($statement);\r
+\r
+  unless ($sth) {\r
+    ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement);\r
+\r
+    croak $msg;\r
+  } # if\r
+\r
+  my $status = $sth->execute;\r
+\r
+  ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement);\r
+\r
+  return ($err, $msg) if $err;\r
+\r
+  my %records;\r
+\r
+  while (my $row = $sth->fetchrow_hashref) {\r
+    # Change undef to ''\r
+    $row->{$_} ||= '' for keys %$row;\r
+\r
+    my $name = delete $row->{name};\r
+\r
+    $records{$name} = $row;\r
+  } # while\r
+\r
+  return %records;\r
+} # _getRecord\r
+\r
+sub new (;$) {\r
+  my ($class, $db) = @_;\r
+\r
+  my $self = bless {}, $class;\r
+\r
+  $self->_connect ($db);\r
+\r
+  return $self;\r
+} # new\r
+\r
+sub select(;$) {\r
+  my ($self, $condition) = @_;\r
+\r
+  return $self->_getRecords('system', $condition);\r
+} # select\r
+\r
+sub AddSystem (%) {\r
+  my ($self, %system) = @_;\r
+\r
+  my @requiredFields = (\r
+    'name',\r
+    'type',\r
+  );\r
+\r
+  my $result = _checkRequiredFields \@requiredFields, \%system;\r
+\r
+  return -1, "AddSystem: $result" if $result;\r
+\r
+  return $self->_addRecord ('system', %system);\r
+} # AddSystem\r
+\r
+1;
\ No newline at end of file
index 2d54e48..6fdaf4b 100644 (file)
@@ -44,3 +44,5 @@
 
 [push]
   default = simple
+[http]
+       sslVerify = false
index bbbc234..d188ad2 100644 (file)
--- a/rc/system
+++ b/rc/system
@@ -2,7 +2,7 @@
 ################################################################################
 #
 # File:         $RCSfile: system,v $
-# Revision:    $Revision: 1.6 $
+# Revision:     $Revision: 1.6 $
 # Description:  System specific settings
 # Author:       Andrew@DeFaria.com
 # Created:      Mon Aug 20 17:35:01  2001