Added caching to clearadm
authorAndrew DeFaria <Andrew@DeFaria.com>
Fri, 28 Dec 2018 01:34:26 +0000 (18:34 -0700)
committerAndrew DeFaria <Andrew@DeFaria.com>
Fri, 28 Dec 2018 01:34:26 +0000 (18:34 -0700)
16 files changed:
bin/findsymlinks.sh
clearadm/clearadmscrub.pl
clearadm/index.cgi
clearadm/lib/Clearadm.pm
clearadm/lib/ClearadmWeb.pm
clearadm/lib/clearadm.sql
clearadm/plot.cgi
clearadm/plotfs.cgi
clearadm/plotloadavg.cgi
clearadm/plotstorage.cgi
clearadm/updateccfs.pl
clearadm/updatefs.pl
clearadm/updatela.pl
clearadm/viewager.cgi
clearadm/viewdetails.cgi
clearadm/vobdetails.cgi

index f5d3a95..56f8043 100755 (executable)
@@ -17,7 +17,10 @@ for component in "${components[@]}"; do
   testpath="${testpath}/$component"
 
   if [ -h "$testpath" ]; then
+    points_to=$(ls -l $testpath | awk '{print $NF}')
+
     echo "$testpath: symbolic link to $(ls -l $testpath | awk '{print $NF}')"
     testpath=$(readlink -n $testpath)
   fi
 done
+
index ba65c08..f8b558e 100755 (executable)
@@ -34,10 +34,10 @@ $Date: 2012/11/09 06:45:36 $
 
  Where:
    -u|sage:     Displays usage
-
    -ve|rbose:   Be verbose
    -deb|ug:     Output debug messages
-
+   
 =head1 DESCRIPTION
 
 This script will scrub all old records in the Clearadm database
@@ -83,16 +83,16 @@ my ($err, $msg);
 
 for my $system ($clearadm->FindSystem ($host)) {
   ($err, $msg) = $clearadm->TrimLoadavg ($$system{name});
-
+  
   if ($msg eq 'Records deleted' or $msg eq '') {
     verbose "Scrub loadavg $$system{name}: $err $msg:";
   } else {
     error "#$err: $msg";
   } # if
-
+  
   for my $filesystem ($clearadm->FindFilesystem ($$system{name}, $fs)) {
     ($err, $msg) = $clearadm->TrimFS ($$system{name}, $$filesystem{filesystem});
-
+    
     if ($msg eq 'Records deleted' or $msg eq '') {
       verbose "Scrub filesystem $$system{name}:$$filesystem{filesystem}: $err $msg";
     } else {
@@ -111,7 +111,7 @@ my %runlog = (
 );
 
 # Scrub old alertlogs
-($runlog{status}, $runlog{message}) =
+($runlog{status}, $runlog{message}) = 
   $clearadm->DeleteAlertlog ("timestamp<='$sixMonthsAgo'");
 
 verbose "$runlog{task} alertlog: $runlog{status} $runlog{message}";
@@ -121,9 +121,9 @@ $clearadm->AddRunlog (%runlog);
 $runlog{started} = Today2SQLDatetime;
 
 # Scrub old runlogs
-($runlog{status}, $runlog{message}) =
+($runlog{status}, $runlog{message}) = 
   $clearadm->DeleteRunlog ("started<='$sixMonthsAgo'");
-
+  
 verbose "$runlog{task} runlog: $runlog{status} $runlog{message}";
 
 $clearadm->AddRunlog (%runlog);
@@ -148,7 +148,7 @@ L<Getopt::Long|Getopt::Long>
 
 =head2 ClearSCM Perl Modules
 
-=begin man
+=begin man 
 
  Clearadm
  DateUtils
index 4fc9cec..76d3724 100755 (executable)
@@ -44,6 +44,7 @@ use Getopt::Long;
 
 use CGI qw (:standard *table start_Tr end_Tr);
 use CGI::Carp 'fatalsToBrowser';
+use Convert::Base64;
 
 use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib";
 
@@ -94,7 +95,7 @@ my @systems = $clearadm->FindSystem;
 
 $perRow = @systems if @systems < $perRow;
 
-foreach (@systems) {
+for (@systems) {
   my %system = %{$_};
   
   if ($i++ % $perRow == 0) {
@@ -106,8 +107,7 @@ foreach (@systems) {
 
   my $data;
   
-  $data = '<strike>'
-    if $system{active} eq 'false';
+  $data = '<strike>' if $system{active} eq 'false';
     
   $data .= a {
     href => "systemdetails.cgi?system=$system{name}"
@@ -115,7 +115,7 @@ foreach (@systems) {
   
   if ($system{notification}) {
     $data .= '&nbsp;' . a {
-      href => "alertlog.cgi?system=$system{name}"}, img {
+      href   => "alertlog.cgi?system=$system{name}"}, img {
       src    => 'alert.png',
       border => 0,
       alt    => 'Alert!',
@@ -123,22 +123,25 @@ foreach (@systems) {
     };
   } # if
   
+  my $image = $system{loadavgsmall}
+    ? "data:image/png;base64,$system{loadavgsmall}"
+    : "plotloadavg.cgi?system=$system{name}&tiny=1";
+
   $data .=  '<br>' .  
     a {href => 
       "plot.cgi?type=loadavg&system=$system{name}&scaling=Hour&points=24"
      }, img {
-       src    => "plotloadavg.cgi?system=$system{name}&tiny=1",
+       src    => $image,
        border => 0,
      };
    
-  $data .= '</strike>'
-    if $system{active} eq 'false';
+  $data .= '</strike>' if $system{active} eq 'false';
     
   $load{uptime} ||= 'Unknown';
 
   display td {class => 'dataCentered'}, "$data ",
     font {class => 'dim' }, "<br>Up: $load{uptime}";
-} # foreach
+} # for
 
 while ($i % $perRow != 0) {
    $i++;
index 4205e44..afda2ae 100644 (file)
@@ -665,51 +665,73 @@ sub AddVob(%) {
   my ($self, %vob) = @_;
 
   my @requiredFields = (
-    'system',
     'tag',
+    'region',
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%vob;
 
-  return -1, "AddVob: $result"
-    if $result;
+  return -1, "AddVob: $result" if $result;
 
   return $self->_addRecord('vob', %vob);
 } # AddVob
 
-sub DeleteVob($) {
-  my ($self, $tag) = @_;
+sub DeleteVob($$) {
+  my ($self, $tag, $region) = @_;
 
-  return $self->_deleteRecord('vob', "tag='$tag'");
+  return $self->_deleteRecord('vob', "tag='$tag' and region='$region'");
 } # DeleteVob
 
-sub GetVob($) {
-  my ($self, $tag) = @_;
+sub GetVob($$) {
+  my ($self, $tag, $region) = @_;
 
-  return
-    unless $tag;
+  return unless $tag;
 
-  my @records = $self->_getRecords('vob', "tag='$tag'");
+  # Windows vob tags begin with "\", which is problematic. The solution is to
+  # escape the "\"
+  $tag =~ s/^\\/\\\\/;
+
+  my @records = $self->_getRecords('vob', "tag='$tag' and region='$region'");
 
   if ($records[0]) {
     return %{$records[0]};
   } else {
-       return;
+    return;
   } # if
 } # GetVob
 
-sub FindVob($) {
-  my ($self, $tag) = @_;
+sub FindVob($;$) {
+  my ($self, $tag, $region) = @_;
+
+  # Windows vob tags begin with "\", which is problematic. The solution is to
+  # escape the "\"
+  $tag =~ s/^\\/\\\\/;
 
-  return $self->_getRecords('vob', "tag like '%$tag%'");
+  my $condition = "tag like '%$tag%'";
+  
+  $condition .= " and region='$region'" if $region;
+
+  return $self->_getRecords('vob', $condition);
 } # FindVob
 
+sub UpdateVob(%) {
+  my ($self, %vob) = @_;
+
+  # Windows vob tags begin with "\", which is problematic. The solution is to
+  # escape the "\"
+  my $vobtag = $vob{tag};
+
+  $vobtag =~ s/^\\/\\\\/;
+
+  return $self->_updateRecord('vob', "tag='$vobtag' and region='$vob{region}'", %vob);
+} # UpdateVob
+
 sub AddView(%) {
   my ($self, %view) = @_;
 
   my @requiredFields = (
-    'system',
     'tag',
+    'region'
   );
 
   my $result = _checkRequiredFields \@requiredFields, \%view;
@@ -720,16 +742,16 @@ sub AddView(%) {
   return $self->_addRecord('view', %view);
 } # AddView
 
-sub DeleteView($) {
-  my ($self, $tag) = @_;
+sub DeleteView($$) {
+  my ($self, $tag, $region) = @_;
 
-  return $self->_deleteRecord('vob', "tag='$tag'");
+  return $self->_deleteRecord('vob', "tag='$tag' and region='$region'");
 } # DeleteView
 
-sub UpdateView($$) {
-  my ($self, $tag, $region, %viewRec) = @_;
+sub UpdateView(%) {
+  my ($self, %view) = @_;
 
-  return $self->_updateRecord('view', "tag='$tag' and region='$region'", %viewRec);
+  return $self->_updateRecord('view', "tag='$view{tag}' and region='$view{region}'", %view);
 } # UpdateView
 
 sub GetView($$) {
@@ -1140,6 +1162,10 @@ sub GetStorage($$$;$$$$$) {
   undef $start if $start and $start =~ /earliest/i;
   undef $end   if $end   and $end   =~ /latest/i;
 
+  # Windows vob tags begin with "\", which is problematic. The solution is to
+  # escape the "\"
+  $tag =~ s/^\\/\\\\/;
+
   my $condition;
   my $table = $type eq 'vob' ? 'vobstorage' : 'viewstorage';
 
index 54f164e..c776c82 100644 (file)
@@ -413,7 +413,7 @@ sub makeStoragePoolDropdown($$) {
 
   my @values;
 
-  my $dropdown = 'Storage pool ';
+  my $dropdown = 'Storage pool  ';
     
   if ($type eq 'vob') {
     push @values, qw(admin db cleartext derivedobj source total);
@@ -633,17 +633,17 @@ sub heading (;$$) {
 
   display header;
   display start_html {
-       -title  => $title,
-       -author => 'Andrew DeFaria <Andrew@ClearSCM.com>',
-       -meta   => {
-         keywords  => 'ClearSCM Clearadm',
+    -title  => $title,
+    -author => 'Andrew DeFaria <Andrew@ClearSCM.com>',
+    -meta   => {
+      keywords  => 'ClearSCM Clearadm',
       copyright => 'Copyright (c) ClearSCM, Inc. 2010, All rights reserved',
-       },
-       -script => [{
-         -language => 'JavaScript',
-         -src      => 'clearadm.js',
-       }],
-       -style   => ['clearadm.css', 'clearmenu.css'],
+  },
+    -script => [{
+      -language => 'JavaScript',
+      -src      => 'clearadm.js',
+    }],
+    -style   => ['clearadm.css', 'clearmenu.css'],
   }, $title;
 
   return if $type;
@@ -1213,13 +1213,17 @@ sub displayFilesystem ($) {
         display td {class => $classRightTop}, "$used ($usedPct%)<br>",
           font {class => 'unknown'}, "$fs{timestamp}";
         display td {class => $classRightTop}, "$filesystem{threshold}%";
+
+       my $image = $filesystem{fssmall}
+         ? "data:image/png;base64,$filesystem{fssmall}"
+         : "plotfs.cgi?system=$system{name}&filesystem=$filesystem{filesystem}&tiny=1";
+
         display td {class => $class},
           a {href =>
             "plot.cgi?type=filesystem&system=$system{name}"
           . "&filesystem=$filesystem{filesystem}&scaling=Day&points=7"
           }, img {
-            src    => "plotfs.cgi?system=$system{name}"
-                    . "&filesystem=$filesystem{filesystem}&tiny=1",
+            src    => $image,
             border => 0,
           };
       display end_Tr;
@@ -1785,7 +1789,7 @@ sub displaySystem ($) {
       a {href =>
         "plot.cgi?type=loadavg&system=$system{name}&scaling=Hour&points=24"
         }, img {
-          src    => "plotloadavg.cgi?system=$system{name}&tiny=1",
+          src    => "data:image/png;base64,$system{loadavgsmall}",
           border => 0,
       };
 
@@ -1850,58 +1854,59 @@ sub displaySystem ($) {
     my $classRight    = $class . 'Right';
 
     display start_Tr;
-        display start_td {class => 'data'};
+      display start_td {class => 'data'};
 
-        my $areYouSure = 'Are you sure you want to delete '
-                       . "$system{name}:$filesystem{filesystem}?" . '\n'
-                       . 'Doing so will remove all records related to this\n'
-                       . 'filesystem and its history.';
+      my $areYouSure = 'Are you sure you want to delete '
+                     . "$system{name}:$filesystem{filesystem}?" . '\n'
+                     . 'Doing so will remove all records related to this\n'
+                     . 'filesystem and its history.';
 
-        display start_form {
-          method => 'post',
-          action => 'processfilesystem.cgi',
-        };
+      display start_form {
+        method => 'post',
+        action => 'processfilesystem.cgi',
+      };
 
-        display input {
-          type  => 'hidden',
-          name  => 'system',
-          value => $system{name},
-        };
-        display input {
-          type  => 'hidden',
-          name  => 'filesystem',
-          value => $filesystem{filesystem},
-        };
+      display input {
+        type  => 'hidden',
+        name  => 'system',
+        value => $system{name},
+      };
+      display input {
+        type  => 'hidden',
+        name  => 'filesystem',
+        value => $filesystem{filesystem},
+      };
 
-        display input {
-          name    => 'delete',
-          type    => 'image',
-          src     => 'delete.png',
-          alt     => 'Delete',
-          value   => 'Delete',
-          title   => 'Delete',
-          onclick => "return AreYouSure ('$areYouSure');"
-        };
-        display input {
-          name    => 'edit',
-          type    => 'image',
-          src     => 'edit.png',
-          alt     => 'Edit',
-          value   => 'Edit',
-          title   => 'Edit',
+      display input {
+        name    => 'delete',
+        type    => 'image',
+        src     => 'delete.png',
+        alt     => 'Delete',
+        value   => 'Delete',
+        title   => 'Delete',
+        onclick => "return AreYouSure ('$areYouSure');"
+      };
+      display input {
+        name    => 'edit',
+        type    => 'image',
+        src     => 'edit.png',
+        alt     => 'Edit',
+        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',
         };
+      } # if
 
-        if ($filesystem{notification}) {
-          display a {
-            href => "alertlog.cgi?system=$filesystem{system}"}, img {
-            src    => 'alert.png',
-            border => 0,
-            alt    => 'Alert!',
-            title  => 'This filesystem has alerts',
-          };
-        } # 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};
@@ -1917,10 +1922,8 @@ sub displaySystem ($) {
         . "&filesystem=$filesystem{filesystem}"
         . "&scaling=Day&points=7"
         }, img {
-           src    => "plotfs.cgi?system=$system{name}&"
-                   . "filesystem=$filesystem{filesystem}"
-                   . '&tiny=1',
-           border => 0,
+          src    => "data:image/png;base64,$filesystem{fssmall}",
+          border => 0,
         };
     display end_Tr;
   } # for
index e722015..8d47e36 100644 (file)
@@ -56,6 +56,8 @@ create table system (
                      '1 year'
                    ) not null default '6 months',
   loadavgThreshold float (4,2) default 5.00,
+  loadavgsmall     blob,
+  loadavg          blob,
 
   primary key (name)
 ) engine=innodb; -- system
@@ -130,6 +132,8 @@ create table filesystem (
                    '11 months',
                    '1 year'
                  ) not null default '6 months',
+  fssmall        blob,
+  fslarge        blob,
   
   key filesystemIndex (filesystem),
   foreign key systemLink (system) references system (name)
@@ -160,18 +164,22 @@ create table fs (
 -- vobstorage: Contains a snapshot of a vob's storage pools at a given date
 -- and time
 create table vobstorage (
-  tag          varchar(255) not null,
-  region        varchar(255) not null,
-  timestamp    datetime     not null,
-  admin                decimal(10,1),
-  db           decimal(10,1),
-  cleartext    decimal(10,1),
-  derivedobj   decimal(10,1),
-  source       decimal(10,1),
-  total                decimal(10,1),
+  tag            varchar(255) not null,
+  region          varchar(255) not null,
+  timestamp      datetime     not null,
+  admin                  decimal(10,1),
+  db             decimal(10,1),
+  cleartext      decimal(10,1),
+  derivedobj     decimal(10,1),
+  source         decimal(10,1),
+  total                  decimal(10,1),
 
   key vobtagIndex (tag),
   primary key  (tag, region, timestamp)
+  foreign key vobLink (tag, region)
+    references vob (tag, region)
+      on delete cascade
+      on update cascade
 ) engine=innodb; -- vobstorage
 
 -- viewstorage: Contains a snapshot of a view's storage pools at a given date
@@ -203,43 +211,55 @@ create table loadavg (
     on update cascade
 ) engine=innodb; -- loadavg
 
--- vobs: Describe a system's vobs
+-- vob: Describe a system's vobs
 create table vob (
-  system varchar (255) not null,
-  tag    varchar (255) not null,
+  tag            varchar (255) not null,
+  region         varchar (255) not null,
+  adminsmall     blob,
+  dbsmall        blob,
+  cleartextsmall  blob,
+  derivedobjsmall blob,
+  sourcesmall     blob,
+  totalsmall      blob,
+  adminlarge             blob,
+  dblarge        blob,
+  cleartextlarge  blob,
+  derivedobjlarge blob,
+  sourcelarge     blob,
+  totallarge      blob,
   
-  key systemIndex (system),
-  foreign key systemLink (system) references system (name)
-    on delete cascade
-    on update cascade,
-  primary key (tag)
+  key vobTagIndex (tag),
+  primary key (tag, region)
 ) engine=innodb; -- vob 
 
 -- view: Describe views
 create table view (
-  system    varchar (255) not null,
-  region    varchar (255) not null,
-  tag       varchar (255) not null,
-  owner     tinytext,
-  ownerName tinytext,
-  email     tinytext,
-  type      enum (
-              'dynamic',
-              'snapshot',
-              'web'
-            ) not null default 'dynamic',
-  gpath     tinytext,
-  modified  datetime,
-  timestamp datetime,
-  age       tinytext,
-  ageSuffix tinytext,
+  tag          varchar (255) not null,
+  region       varchar (255) not null,
+  owner        tinytext,
+  ownerName    tinytext,
+  email        tinytext,
+  type         enum (
+                 'dynamic',
+                 'snapshot',
+                 'web'
+               ) not null default 'dynamic',
+  gpath        tinytext,
+  modified     datetime,
+  timestamp    datetime,
+  age          tinytext,
+  ageSuffix    tinytext,
+  privatesmall blob,
+  dbsmall      blob,
+  adminsmall   blob,
+  totalsmall   blob,
+  privatelarge blob,
+  dblarge      blob,
+  adminlarge   blob,
+  totallarge   blob,
   
-  key systemIndex (system),
-  foreign key systemLink (system) references system (name)
-    on delete cascade
-    on update cascade,
-  key regionIndex (region),
-  primary key (region, tag)
+  key viewTagIndex (tag),
+  primary key (tag, region)
 ) engine=innodb; -- view
 
 create table task (
index 9fada55..310ff7f 100755 (executable)
@@ -66,36 +66,66 @@ sub displayGraph () {
   display '<center>';
   
   if ($opts{type} eq 'loadavg') {
-    unless ($opts{tiny}) {
-      display img {src => "plotloadavg.cgi?$parms", class => 'chart'};
+    my %system = $clearadm->GetSystem($opts{system});
+
+    # We can use the cached version only if the opts are set to default
+    if ($opts{scaling} eq 'Hour' and $opts{points} == 24) {
+      my $data = $opts{tiny} ? $system{loadavgsmall} : $system{loadavg};
+
+      display img {src => "data:image/png;base64,$data"};
     } else {
-      display img {src => "plotloadavg.cgi?$parms", border => 0};
-    } # unless
+      unless ($opts{tiny}) {
+        display img {src => "plotloadavg.cgi?$parms", class => 'chart'};
+      } else {
+        display img {src => "plotloadavg.cgi?$parms", border => 0};
+      } # unless
+    } # if
   } elsif ($opts{type} eq 'filesystem') {
-    unless ($opts{tiny}) {
-      display img {src => "plotfs.cgi?$parms", class => 'chart'};
+    my %filesystem = $clearadm->GetFilesystem($opts{system}, $opts{filesystem});
+
+    # We can use the cached version only if the opts are set to default
+    if ($opts{scaling} eq 'Day' and $opts{points} == 7) {
+      my $data = $opts{tiny} ? $filesystem{fssmall} : $filesystem{fslarge};
+
+      display img {src => "data:image/png;base64,$data"};
     } else {
-      display img {src => "plotfs.cgi?$parms", border => 0};
-    } # unless
+      unless ($opts{tiny}) {
+        display img {src => "plotfs.cgi?$parms", class => 'chart'};
+      } else {
+        display img {src => "plotfs.cgi?$parms", border => 0};
+      } # unless
+    } # if
   } elsif ($opts{type} eq 'vob' or $opts{type} eq 'view') {
-    unless ($opts{tiny}) {
-      display img {src => "plotstorage.cgi?$parms", class => 'chart'};
+    my (%vob, %view);
+
+    %vob  = $clearadm->GetVob($opts{tag}, $opts{region})  if $opts{type} eq 'vob';
+    %view = $clearadm->GetView($opts{tag}, $opts{region}) if $opts{type} eq 'view';
+    # We can use the cached version only if the opts are set to default
+    if ($opts{scaling} eq 'Day' and $opts{points} == 7) {
+      my $storageType = $opts{tiny}          ? "$opts{storage}small" : "$opts{storage}large";
+      my $data        = $opts{type} eq 'vob' ? $vob{$storageType}    : $view{$storageType};
+
+      display img {src => "data:image/png;base64,$data"};
     } else {
-      display img {src => "plotstorage.cgi?$parms", border => 0};
-    } # unless
+      unless ($opts{tiny}) {
+        display img {src => "plotstorage.cgi?$parms", class => 'chart'};
+      } else {
+        display img {src => "plotstorage.cgi?$parms", border => 0};
+      } # unless
+    } # if
   } # if
 
   display '</center>';
   
-  return
+  return;
 } # displayGraph
 
 sub displayFSInfo () {
   if ($opts{filesystem}) {
     display h3 {-align => 'center'}, 'Latest Filesystem Reading';
   } else {
-       display p;
-       return;
+    display p;
+    return;
   } # if
   
   display start_table {width => '800px', cellspacing => 1};
@@ -281,7 +311,8 @@ display start_form {
 };
 
 # Some hidden fields to pass along
-display input {type => 'hidden', name => 'type', value => $opts{type}};
+display input {type => 'hidden', name => 'type',   value => $opts{type}};
+display input {type => 'hidden', name => 'region', value => $opts{region}};
 
 displayGraph;
 displayFSInfo;
index 8617e79..e4a5e6c 100755 (executable)
@@ -61,6 +61,7 @@ use strict;
 use warnings;
 
 use FindBin;
+use Convert::Base64;
 
 use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib";
 
@@ -165,8 +166,12 @@ $graph->set (
 my $image = $graph->plot(\@data)
   or croak $graph->error;
 
-print "Content-type: image/png\n\n";
-print $image->png;
+unless ($opts{generate}) {
+  print "Content-type: image/png\n\n";
+  print $image->png;
+} else {
+  print encode_base64 $image->png;
+} # unless
 
 =pod
 
index c8acbfa..8d51a21 100755 (executable)
@@ -59,6 +59,7 @@ use strict;
 use warnings;
 
 use FindBin;
+use Convert::Base64;
 
 use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib";
 
@@ -100,7 +101,7 @@ my @loads = $clearadm->GetLoadavg (
   $opts{start},
   $opts{end},
   $opts{points},
-  $opts{scaling}
+  $opts{scaling},
 );
 
 graphError "No loadavg data"
@@ -108,7 +109,7 @@ graphError "No loadavg data"
 
 my (@x, @y);
 
-foreach (@loads) {
+for (@loads) {
   my %load = %{$_};
   
   if ($opts{tiny}) {
@@ -118,7 +119,7 @@ foreach (@loads) {
   } # if
 
   push @y, $load{loadavg};
-} # foreach
+} # for
 
 my @data = ([@x], [@y]);
 
@@ -154,8 +155,12 @@ $graph->set (
 my $image = $graph->plot(\@data)
   or croak $graph->error;
 
-print "Content-type: image/png\n\n";
-print $image->png;
+unless ($opts{generate}) {
+  print "Content-type: image/png\n\n";
+  print $image->png;
+} else {
+  print encode_base64 $image->png;
+} # unless
 
 =pod
 
index 22c20ba..f017de6 100755 (executable)
@@ -40,7 +40,7 @@ $Date: 2011/01/14 16:37:04 $
    <storage>: Name of the Clearcase storage pool to plot information for
    <height>:  Height of chart (Default: 480px - tiny: 40)
    <width>:   Width of chart (Default: 800px - tiny: 150)
-   <color>:   A GD::Color color value (Default: lblue)
+   <color>:   A GD::Color color value (Default: purple)
    <scaling>: Currently one of Minute, Hour, Day or Month. Specifies how
               Clearadm::GetFS will scale the data returned (Default: Minute 
               - tiny: Day)
@@ -61,6 +61,7 @@ use strict;
 use warnings;
 
 use FindBin;
+use Convert::Base64;
 
 use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib";
 
@@ -77,7 +78,7 @@ my %opts = Vars;
 my $VERSION  = '$Revision: 1.13 $';
   ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
 
-$opts{color}  ||= 'lblue';
+$opts{color}  ||= $opts{type} eq 'vob' ? 'purple' : 'marine';
 $opts{height} ||= 350;
 $opts{width}  ||= 800;
 
@@ -168,8 +169,12 @@ $graph->set (
 my $image = $graph->plot(\@data)
   or croak $graph->error;
 
-print "Content-type: image/png\n\n";
-print $image->png;
+unless ($opts{generate}) {
+  print "Content-type: image/png\n\n";
+  print $image->png;
+} else {
+  print encode_base64 $image->png;
+} # unless
 
 =pod
 
index ff4dd25..6a82134 100755 (executable)
@@ -66,12 +66,15 @@ use Clearcase::Vob;
 use DateUtils;
 use Display;
 use Utils;
+use TimeUtils;
 
 my $VERSION  = '$Revision: 1.29 $';
   ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
 
 my $clearadm = Clearadm->new;
 
+my %total;
+
 # Given a view tag, snapshot the storage sizes
 sub snapshotViewStorage($$) {
   my ($tag, $region) = @_;
@@ -91,6 +94,12 @@ sub snapshotViewStorage($$) {
   my ($err, $msg) = $clearadm->AddViewStorage(%viewstorage);
 
   error $msg, $err if $err;
+
+  $total{'Views snapshotted'}++;
+
+  updateView($tag, $region);
+
+  return;
 } # snapshotVobStorage
 
 # Given a vob tag, snapshot the storage sizes
@@ -114,11 +123,133 @@ sub snapshotVobStorage($$) {
   my ($err, $msg) = $clearadm->AddVobStorage(%vobstorage);
 
   error $msg, $err, if $err;
+
+  $total{'VOBs snapshotted'}++;
+
+  updateVob($tag, $region);
+
+  return;
 } # snapshotVobStorage
 
+sub updateVob($$) {
+  my ($tag, $region) = @_;
+
+  my ($err, $msg, $error, @output, $graph);
+
+  my %vob = $clearadm->GetVob($tag, $region);
+
+  for my $graphType (qw(admin cleartext db derivedobj source total)) {
+  #for my $graphType (qw(derivedobj)) {
+    # Windows vob tags begin with "\", which is problematic. The solution is to
+    # escape the "\"
+    my $vobtag = $tag;
+    $vobtag =~ s/^\\/\\\\/;
+
+    my $cmd = "plotstorage.cgi generate=1 type=vob storage=$graphType region=$region scaling=Day points=7 tag=$vobtag";
+
+    $graph = "${graphType}small";
+
+    verbose "Generating $graph for VOB $tag (Region: $region)";
+
+    ($error, @output) = Execute("$cmd tiny=1 2>&1");
+
+    error "Unable to generate $graph" . join("\n", @output), $error if $error;
+
+    $vob{$graph} = join '', @output;
+    $total{'VOB Graphs generated'}++;
+
+    $graph = "${graphType}large";
+
+    verbose "Generating $graph for VOB $tag (Region: $region)";
+
+    ($error, @output) = Execute("$cmd 2>&1");
+
+    error "Unable to generate $graph" . join("\n", @output), $error if $error;
+
+    $vob{$graph} = join '', @output;
+    $total{'VOB Graphs generated'}++;
+  } # for
+
+  if ($vob{tag}) {
+    ($err, $msg) = $clearadm->UpdateVob(%vob);
+
+    error "Unable to update VOB $tag (Region: $region) - $msg", $err if $err;
+
+    $total{'VOBs updated'}++;
+  } else {
+    $vob{tag}    = $tag;
+    $vob{region} = $region;
+
+    ($err, $msg) = $clearadm->AddVob(%vob);
+
+    error "Unable to add VOB $tag (Region: $region) - $msg", $err if $err;
+
+    $total{'VOBs added'}++;
+  } # if
+
+  return;
+} # updateVob
+
+sub updateView($$) {
+  my ($tag, $region) = @_;
+
+  my ($err, $msg, $error, @output, $graph);
+
+  my %view = $clearadm->GetView($tag, $region);
+
+  for my $graphType (qw(private db admin total)) {
+    my $cmd = "plotstorage.cgi generate=1 type=view storage=$graphType region=$region scaling=Day points=7 tag=$tag";
+
+    $graph = "${graphType}small";
+
+    verbose "Generating $graph for View $tag (Region: $region)";
+
+    ($error, @output) = Execute("$cmd tiny=1 2>&1");
+
+    error "Unable to generate $graph" . join("\n", @output), $error if $error;
+
+    $total{'View Graphs generated'}++;
+
+    $view{$graph} = join '', @output;
+
+    $graph = "${graphType}large";
+
+    verbose "Generating $graph for View $tag (Region: $region)";
+
+    ($error, @output) = Execute("$cmd 2>&1");
+
+    error "Unable to generate $graph" . join("\n", @output), $error if $error;
+
+    $total{'View Graphs generated'}++;
+
+    $view{$graph} = join '', @output;
+  } # for
+
+  if ($view{tag}) {
+    ($err, $msg) = $clearadm->UpdateView(%view);
+
+    error "Unable to update View $tag (Region: $region) - $msg", $err if $err;
+
+    $total{'Views updated'}++;
+  } else {
+    $view{tag}    = $tag;
+    $view{region} = $region;
+
+    ($err, $msg) = $clearadm->AddView(%view);
+
+    error "Unable to add VOB $tag (Region: $region) - $msg", $err if $err;
+
+    $total{'Views added'}++;
+  } # if
+
+  return;
+} # updateView
+
 my %opts;
 
 # Main
+my $startTime = time;
+
 GetOptions (
   \%opts,
   'usage'   => sub { Usage },
@@ -198,7 +329,7 @@ if ($opts{vob} and $opts{vob} =~ /all/i) {
 } elsif ($opts{vob}) {
   if ($opts{region} =~ /all/i) {
     for my $region ($Clearcase::CC->regions) {
-      verbose "Snapshotting view $opts{vob} in region $region";
+      verbose "Snapshotting vob $opts{vob} in region $region";
 
       snapshotVobStorage $opts{vob}, $region;
     } # for
@@ -209,6 +340,11 @@ if ($opts{vob} and $opts{vob} =~ /all/i) {
   } # if
 } # if
 
+if (get_verbose) {
+  Stats \%total;
+  display_duration $startTime;
+} # if
+
 =pod
 
 =head1 CONFIGURATION AND ENVIRONMENT
index 86df94c..caa7d07 100755 (executable)
@@ -54,6 +54,7 @@ use warnings;
 use Net::Domain qw(hostname);
 use FindBin;
 use Getopt::Long;
+use Convert::Base64;
 
 use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib";
 
@@ -165,22 +166,22 @@ verbose "$FindBin::Script V$VERSION";
 my $exit = 0;
 
 for my $system ($clearadm->FindSystem ($host)) {
-  next if $$system{active} eq 'false';
+  next if $system->{active} eq 'false';
   
   my $status = $clearexec->connectToServer (
-    $$system{name}, 
-    $$system{port}
+    $system->{name}, 
+    $system->{port}
   );
   
   unless ($status) {
-    verbose "Unable to connect to system $$system{name}:$$system{port}";
+    verbose "Unable to connect to system $system->{name}:$system->{port}";
     next;
   } # unless
 
-  for my $filesystem ($clearadm->FindFilesystem ($$system{name}, $fs)) {
-    verbose "Snapshotting $$system{name}:$$filesystem{filesystem}";
+  for my $filesystem ($clearadm->FindFilesystem ($system->{name}, $fs)) {
+    verbose "Snapshotting $system->{name}:$filesystem->{filesystem}";
   
-    my %fs = snapshotFS ($system, $$filesystem{filesystem});
+    my %fs = snapshotFS ($system, $filesystem->{filesystem});
     
     if (%fs) {
       my ($err, $msg) = $clearadm->AddFS (%fs);
@@ -188,24 +189,44 @@ for my $system ($clearadm->FindSystem ($host)) {
       error $msg, $err if $err;
     } # if
     
+    # Generate graphs
+    my $cmd = "plotfs.cgi generate=1 system=$system->{name} filesystem=$filesystem->{filesystem} scaling=Day points=7";
+
+    verbose "Generating fssmall for $system->{name}:$filesystem->{filesystem}";
+    my ($error, @output) = Execute("$cmd tiny=1 2>&1");
+
+    error 'Unable to generate fssmall' . join("\n", @output), $error if $error;
+
+    $filesystem->{fssmall} = join '', @output;
+
+    verbose "Generating fslarge for $system->{name}:$filesystem->{filesystem}";
+    ($error, @output) = Execute("$cmd 2>&1");
+
+    error 'Unable to generate fslarge' . join("\n", @output), $error if $error;
+
+    $filesystem->{fslarge} = join '', @output;
+
+    my ($err, $msg) = $clearadm->UpdateFilesystem($system->{name}, $filesystem->{filesystem}, %$filesystem);
+
+    error "Unable to update filesystem record $msg", $err if $err;
+
     # Check if over threshold
     my %notification = $clearadm->GetNotification ('Filesystem');
 
-    next
-      unless %notification;
+    next unless %notification;
   
     my $usedPct = '0%';
 
     $usedPct = sprintf ('%.2f', (($fs{used} + $fs{reserve}) / $fs{size}) * 100) if $fs{size} != 0;
     
-    if ($usedPct >= $$filesystem{threshold}) {
+    if ($usedPct >= $filesystem->{threshold}) {
       $exit = 2;
       display YMDHMS
-            . " System: $$filesystem{system} "
-            . "Filesystem: $$filesystem{filesystem} Used: $usedPct% " 
-            . "Threshold: $$filesystem{threshold}";    
+            . " System: $filesystem->{system} "
+            . "Filesystem: $filesystem->{filesystem} Used: $usedPct% " 
+            . "Threshold: $filesystem->{threshold}";    
     } else {
-      $clearadm->ClearNotifications ($$system{name}, $$filesystem{filesystem});    
+      $clearadm->ClearNotifications ($system->{name}, $filesystem->{filesystem});    
     } # if
   } # for
   
index e9b4b38..99b935e 100755 (executable)
@@ -160,8 +160,8 @@ verbose "$FindBin::Script V$VERSION";
 
 my $exit = 0;
 
-foreach my $system ($clearadm->FindSystem ($host)) {
-  next if $$system{active} eq 'false';
+for my $system ($clearadm->FindSystem ($host)) {
+  next if $system->{active} eq 'false';
   
   my %load = snapshotLoad $system;
   
@@ -170,24 +170,46 @@ foreach my $system ($clearadm->FindSystem ($host)) {
   
     error $msg, $err if $err;
   } else {
-    error "Unable to get loadavg for system $$system{name}", 1;
+    error "Unable to get loadavg for system $system->{name}", 1;
   } # if
   
   # Check if over threshold
   my %notification = $clearadm->GetNotification ('Loadavg');
 
-  next
-    unless %notification;
+  next unless %notification;
   
-  if ($load{loadavg} >= $$system{loadavgThreshold}) {
+  if ($load{loadavg} >= $system->{loadavgThreshold}) {
     $exit = 2;
-    error YMDHMS . " System: $$system{name} "
+    error YMDHMS . " System: $system->{name} "
         . "Loadavg $load{loadavg} "
-        . "Threshold $$system{loadavgThreshold}";
+        . "Threshold $system->{loadavgThreshold}";
   } else {
-    $clearadm->ClearNotifications ($$system{name});
+    $clearadm->ClearNotifications ($system->{name});
   } # if
-} # foreach
+
+  # Add graphs to system record
+  my ($loadavgsmall, $loadavg);
+
+  my $cmd = "plotloadavg.cgi generate=1 system=$system->{name} scaling=Hour points=24";
+
+  verbose "Generating loadavgsmall for $system->{name}";
+  my ($error, @output) = Execute("$cmd tiny=1 2>&1");
+
+  error 'Unable to generate loadavgsmall' . join("\n", @output), $error if $error;
+
+  $system->{loadavgsmall} = join '', @output;
+
+  verbose "Generating loadavg for $system->{name}";
+  ($error, @output) = Execute("$cmd 2>&1");
+  
+  error 'Unable to generate loadavg' . join("\n", @output), $error if $error;
+
+  $system->{loadavg} = join '', @output;
+
+  my ($err, $msg) = $clearadm->UpdateSystem($system->{name}, %$system);
+
+  error "Unable to udpate system record $msg", $err if $err;
+} # for
 
 exit $exit;
 
index 9ac1b1e..1b978d9 100755 (executable)
@@ -239,8 +239,6 @@ sub GenerateRegion ($) {
       # Compute age
       $age       = Age ($modified_date);
       $ageSuffix = $age != 1 ? 'days' : 'day';
-    #} else {
-    #  $modified_date = 'Unknown';
     } # if
 
     my %oldView = $clearadm->GetView($view->tag, $view->region);
@@ -264,7 +262,7 @@ sub GenerateRegion ($) {
     $viewRec{modified} = $modified_date if $modified_date;
 
     if (%oldView) {
-      ($err, $msg) = $clearadm->UpdateView($view->tag, $view->region, %viewRec);
+      ($err, $msg) = $clearadm->UpdateView(%viewRec);
 
       error "Unable to update view $name in Clearadm\n$msg", $err if $err;
     } else {
index 72b486b..ef9df9b 100755 (executable)
@@ -57,6 +57,7 @@ use CGI::Carp 'fatalsToBrowser';
 
 use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib";
 
+use Clearadm;
 use ClearadmWeb;
 use Clearcase;
 use Clearcase::View;
@@ -94,6 +95,10 @@ sub DisplayTable ($) {
     -class          => 'main',
   };
 
+  my $clearadm = Clearadm->new;
+
+  my %clearadmview = $clearadm->GetView($view->tag, $view->region);
+
   display start_Tr;
     display th {class => 'label'},              'Tag:';
     display td {class => 'data', colspan => 3}, setField $view->tag;
@@ -154,36 +159,54 @@ sub DisplayTable ($) {
     display th {class => 'labelCentered', colspan => 10}, 'View Storage Pools';
   display end_Tr;
 
+  my $image = $clearadmview{dbsmall}
+    ? "data:image/png;base64,$clearadmview{dbsmall}"
+    : "plotstorage.cgi?type=view&storage=db&tiny=1&tag=" . $view->tag;
+
   display start_Tr;
     display th {class => 'label'},                                'Database:';
     display td {class => 'data', colspan => 3, align => 'center'}, a {href =>
-       "plot.cgi?type=view&storage=private&tag=" . $view->tag
+       "plot.cgi?type=view&storage=db&scaling=Day&points=7&region=" . $view->region . '&tag=' . $view->tag
     }, img {
-      src    => "plotstorage.cgi?type=view&storage=private&tiny=1&tag=" . $view->tag,
+      src    => $image,
       border => 0,
     };
+
+    $image = $clearadmview{privatesmall}
+      ? "data:image/png;base64,$clearadmview{privatesmall}"
+      : "plotstorage.cgi?type=view&storage=private&tiny=1&tag=" . $view->tag;
+
     display th {class => 'label'},                                'Private:';
     display td {class => 'data', colspan => 5, align => 'center'}, a {href =>
-       "plot.cgi?type=view&storage=db&tag=" . $view->tag
+       "plot.cgi?type=view&storage=private&scaling=Day&points=7&region=" . $view->region . '&tag=' . $view->tag
     }, img {
-      src    => "plotstorage.cgi?type=view&storage=db&tiny=1&tag=" . $view->tag,
+      src    => $image,
       border => 0,
     };
   display end_Tr;
 
+  $image = $clearadmview{adminsmall}
+    ? "data:image/png;base64,$clearadmview{adminsmall}"
+    : "plotstorage.cgi?type=view&storage=admin&tiny=1&tag=" . $view->tag;
+
   display start_Tr;
     display th {class => 'label'},                                'Admin:';
     display td {class => 'data', colspan => 3, align => 'center'}, a {href =>
-       "plot.cgi?type=view&storage=admin&tag=" . $view->tag
+       "plot.cgi?type=view&storage=admin&scaling=Day&points=7&region=" . $view->region . '&tag=' . $view->tag
     }, img {
-      src    => "plotstorage.cgi?type=view&storage=admin&tiny=1&tag=" . $view->tag,
+      src    => $image,
       border => 0,
     };
+
+    $image = $clearadmview{totalsmall}
+      ? "data:image/png;base64,$clearadmview{totalsmall}"
+      : "plotstorage.cgi?type=view&storage=total&tiny=1&tag=" . $view->tag;
+
     display th {class => 'label'},                                'Total Space:';
     display td {class => 'data', colspan => 5, align => 'center'}, a {href =>
-       "plot.cgi?type=view&storage=total&tag=" . $view->tag
+       "plot.cgi?type=view&storage=total&scaling=Day&points=7&region=" . $view->region . '&tag=' . $view->tag
     }, img {
-      src    => "plotstorage.cgi?type=view&storage=total&tiny=1&tag=" . $view->tag,
+      src    => $image,
       border => 0,
     };
   display end_Tr;
@@ -283,9 +306,7 @@ unless ($opts{tag}) {
   exit;
 } # unless
 
-my $view = Clearcase::View->new ($opts{tag}, $opts{region});
-
-DisplayTable $view;
+DisplayTable(Clearcase::View->new($opts{tag}, $opts{region}));
 
 footing;
 
@@ -315,6 +336,7 @@ L<Getopt::Long|Getopt::Long>
 
 =begin man 
 
+ Clearadm
  ClearadmWeb
  Clearcase
  Clearcase::View
@@ -327,6 +349,7 @@ L<Getopt::Long|Getopt::Long>
 =begin html
 
 <blockquote>
+<a href="http://clearscm.com/php/scm_man.php?file=clearadm/lib/Clearadm.pm">Clearadm</a><br>
 <a href="http://clearscm.com/php/scm_man.php?file=clearadm/lib/ClearadmWeb.pm">ClearadmWeb</a><br>
 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase.pm">Clearcase</a><br>
 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/View.pm">Clearcase::View</a><br>
index 89a38d6..420700c 100755 (executable)
@@ -57,6 +57,7 @@ use CGI::Carp 'fatalsToBrowser';
 
 use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib";
 
+use Clearadm;
 use ClearadmWeb;
 use Clearcase;
 use Clearcase::Vob;
@@ -91,6 +92,10 @@ sub DisplayTable ($) {
     -class          => 'main',
   };
 
+  my $clearadm = Clearadm->new;
+
+  my %clearadmvob = $clearadm->GetVob($vob->tag, $vob->region);
+
   display start_Tr;
     display th {class => 'label'},              'Tag:';
     display td {class => 'data', colspan => 3}, setField $vob->tag;
@@ -199,53 +204,80 @@ sub DisplayTable ($) {
     display th {class => 'labelCentered', colspan => 10}, 'VOB Storage Pools';
   display end_Tr;
 
+  my $image = $clearadmvob{adminsmall}
+    ? "data:image/png;base64,$clearadmvob{adminsmall}"
+    : "plotstorage.cgi?type=vob&storage=admin&tiny=1&tag=" . $vob->tag;
+
   display start_Tr;
     display th {class => 'label'},                                'Admin:';
     display td {class => 'data', colspan => 4, align => 'center'}, a {href =>
-      "plot.cgi?type=vob&storage=admin&scaling=Hour&points=24&tag=" . $vob->tag
+      'plot.cgi?type=vob&storage=admin&scaling=Day&points=7&region=' . $vob->region . '&tag=' . $vob->tag
     }, img {
-      src    => "plotstorage.cgi?type=vob&storage=admin&tiny=1&tag=" . $vob->tag,
+      src    => $image,
       border => 0,
     };
+
+    $image = $clearadmvob{sourcesmall}
+      ? "data:image/png;base64,$clearadmvob{sourcesmall}"
+      : 'plotstorage.cgi?type=vob&storage=source&tiny=1&region=' . $vob->region . '&tag=' . $vob->tag;
+
     display th {class => 'label'},                                'Source Size:';
     display td {class => 'data', colspan => 4, align => 'center'}, a {href =>
-      "plot.cgi?type=vob&storage=source&scaling=Hour&points=24&tag=" . $vob->tag
+      'plot.cgi?type=vob&storage=source&scaling=Day&points=7&region=' . $vob->region . '&tag=' . $vob->tag
     }, img {
-      src    => "plotstorage.cgi?type=vob&storage=source&tiny=1&tag=" . $vob->tag,
+      src    => $image,
       border => 0,
     };
   display end_Tr;
 
   display start_Tr;
+    $image = $clearadmvob{dbsmall}
+      ? "data:image/png;base64,$clearadmvob{dbsmall}"
+      : 'plotstorage.cgi?type=vob&storage=db&tiny=1&region=' . $vob->region . '&tag=' . $vob->tag;
+
     display th {class => 'label'},                                'Database:';
     display td {class => 'data', colspan => 4, align => 'center'}, a {href =>
-      "plot.cgi?type=vob&storage=db&scaling=Hour&points=24&tag=" . $vob->tag
+      'plot.cgi?type=vob&storage=db&scaling=Day&points=7&region=' . $vob->region . '&tag=' . $vob->tag
     }, img {
-      src    => "plotstorage.cgi?type=vob&storage=db&tiny=1&tag=" . $vob->tag,
+      src    => $image,
       border => 0,
     };
+
+    $image = $clearadmvob{derivedobjsmall}
+      ? "data:image/png;base64,$clearadmvob{derivedobjsmall}"
+      : 'plotstorage.cgi?type=vob&storage=derivedobj&tiny=1&region=' . $vob->region . '&tag=' . $vob->tag;
+
     display th {class => 'label'},                                'Derived Obj:';
     display td {class => 'data', colspan => 4, align => 'center'}, a {href =>
-      "plot.cgi?type=vob&storage=derivedobj&scaling=Hour&points=24&tag=" . $vob->tag
+      'plot.cgi?type=vob&storage=derivedobj&scaling=Day&points=7&region=' . $vob->region . '&tag=' . $vob->tag
     }, img {
-      src    => "plotstorage.cgi?type=vob&storage=derivedobj&tiny=1&tag=" . $vob->tag,
+      src    => $image,
       border => 0,
     };
   display end_Tr;
 
   display start_Tr;
+    $image = $clearadmvob{cleartextsmall}
+      ? "data:image/png;base64,$clearadmvob{cleartextsmall}"
+      : 'plotstorage.cgi?type=vob&storage=cleartext&tiny=1&region=' . $vob->retion . '&tag=' . $vob->tag;
+
     display th {class => 'label'},                                'Cleartext:';
     display td {class => 'data', colspan => 4, align => 'center'}, a {href =>
-      "plot.cgi?type=vob&storage=cleartext&scaling=Hour&points=24&tag=" . $vob->tag
+      'plot.cgi?type=vob&storage=cleartext&scaling=Day&points=7&region=' . $vob->region . '&tag=' . $vob->tag
     }, img {
-      src    => "plotstorage.cgi?type=vob&storage=cleartext&tiny=1&tag=" . $vob->tag,
+      src    => $image,
       border => 0,
     };
+
+    $image = $clearadmvob{totalsmall}
+      ? "data:image/png;base64,$clearadmvob{totalsmall}"
+      : 'plotstorage.cgi?type=vob&storage=total&tiny=1&region=' . $vob->region . '&tag=' . $vob->tag;
+
     display th {class => 'label'},                                'Total Size:';
     display td {class => 'data', colspan => 4, align => 'center'}, a {href =>
-      "plot.cgi?type=vob&storage=total&scaling=Hour&points=24&tag=" . $vob->tag
+      'plot.cgi?type=vob&storage=total&scaling=Day&points=7&region=' . $vob->region . '&tag=' . $vob->tag
     }, img {
-      src    => "plotstorage.cgi?type=vob&storage=total&tiny=1&tag=" . $vob->tag,
+      src    => $image,
       border => 0,
     };
   display end_Tr;
@@ -388,6 +420,7 @@ L<Getopt::Long|Getopt::Long>
 =begin html
 
 <blockquote>
+<a href="http://clearscm.com/php/scm_man.php?file=clearadm/lib/Clearadm.pm">Clearadm</a><br>
 <a href="http://clearscm.com/php/scm_man.php?file=clearadm/lib/ClearadmWeb.pm">ClearadmWeb</a><br>
 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase.pm">Clearcase</a><br>
 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/View.pm">Clearcase::View</a><br>