X-Git-Url: https://defaria.com/gitweb/?a=blobdiff_plain;f=clearadm%2Flib%2FClearadm.pm;h=a9bcb364e9f1d67937cfe92d7ca2f597c8fa9919;hb=7ddf095f187ca60d9a70fb83b2bc3c2b6d91f088;hp=fb63079c385888de4b13382a320543ee1c448e02;hpb=ffa5a122584a2218799bfd6dccbee689670fdf75;p=clearscm.git diff --git a/clearadm/lib/Clearadm.pm b/clearadm/lib/Clearadm.pm index fb63079..a9bcb36 100644 --- a/clearadm/lib/Clearadm.pm +++ b/clearadm/lib/Clearadm.pm @@ -36,9 +36,9 @@ specifics about the method you are envoking. # Create new Clearadm object my $clearadm = new Clearadm; - + # Add a new system - my %system = ( + my %system =( name => 'jupiter', alias => 'defaria.com', admin => 'Andrew DeFaria', @@ -46,31 +46,31 @@ specifics about the method you are envoking. type => 'Linux', description => 'Home server', ); - - my ($err, $msg) = $clearadm->AddSystem (%system); - + + my ($err, $msg) = $clearadm->AddSystem(%system); + # Find systems matching 'jup' - my @systems = $clearadm->FindSystem ('jup'); - + my @systems = $clearadm->FindSystem('jup'); + # Get a system by name - my %system = $clearadm->GetSystem ('jupiter'); - + 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'); + my ($err, $msg) = $clearadm->DeleteSystem('jupiter'); =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 @@ -88,6 +88,7 @@ use Carp; use DBI; use File::Basename; use Net::Domain qw(hostdomain); +use Sys::Hostname; use FindBin; @@ -97,27 +98,29 @@ use DateUtils; use Display; use GetConfig; use Mail; +use Clearcase::Vob; +use Clearcase::View; -my $conf = dirname (__FILE__) . '/../etc/clearadm.conf'; +my $conf = dirname(__FILE__) . '/../etc/clearadm.conf'; -our %CLEAROPTS = GetConfig ($conf); +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'; @@ -127,152 +130,149 @@ my $defaultFilesystemHist = '6 months'; my $defaultLoadavgHist = '6 months'; # Internal methods -sub _dberror ($$) { +sub _dberror($$) { my ($self, $msg, $statement) = @_; my $dberr = $self->{db}->err; my $dberrmsg = $self->{db}->errstr; - + $dberr ||= 0; $dberrmsg ||= 'Success'; my $message = ''; - + if ($dberr) { - my $function = (caller (1)) [3]; + my $function = (caller(1)) [3]; $message = "$function: $msg\nError #$dberr: $dberrmsg\n" . "SQL Statement: $statement"; } # if - return $dberr, $message; + return $dberr, $message; } # _dberror -sub _formatValues (@) { +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 (%) { +sub _formatNameValues(%) { my ($self, %rec) = @_; - + my @nameValueStrs; - - push @nameValueStrs, "$_=" . $self->{db}->quote ($rec{$_}) - foreach (keys %rec); - + + push @nameValueStrs, "$_=" . $self->{db}->quote($rec{$_}) for (keys %rec); + return @nameValueStrs; } # _formatNameValues -sub _addRecord ($%) { +sub _addRecord($%) { my ($self, $table, %rec) = @_; - + my $statement = "insert into $table ("; $statement .= join ',', keys %rec; $statement .= ') values ('; - $statement .= join ',', $self->_formatValues (values %rec); + $statement .= join ',', $self->_formatValues(values %rec); $statement .= ')'; - + my ($err, $msg); - - $self->{db}->do ($statement); - - return $self->_dberror ("Unable to add record to $table", $statement); + + $self->{db}->do($statement); + + return $self->_dberror("Unable to add record to $table", $statement); } # _addRecord -sub _deleteRecord ($;$) { +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); - + $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); - + 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; - + + return ($count, 'Records deleted') if $count == 0; + $statement = "delete from $table "; - $statement .= "where $condition" - if $condition; - - $self->{db}->do ($statement); - + $statement .= "where $condition" if $condition; + + $self->{db}->do($statement); + if ($self->{db}->err) { - return $self->_dberror ("Unable to delete record from $table", $statement); + return $self->_dberror("Unable to delete record from $table", $statement); } else { return $count, 'Records deleted'; } # if } # _deleteRecord -sub _updateRecord ($$%) { +sub _updateRecord($$%) { my ($self, $table, $condition, %rec) = @_; my $statement = "update $table set "; - $statement .= join ',', $self->_formatNameValues (%rec); - $statement .= " where $condition" - if $condition; - - $self->{db}->do ($statement); - - return $self->_dberror ("Unable to update record in $table", $statement); + $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 ($$) { +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 - - return "$fieldname is required" - unless $found; - } # foreach - + } # for + + return "$fieldname is required" unless $found; + } # for + return; } # _checkRequiredFields -sub _getRecords ($$) { - my ($self, $table, $condition) = @_; - +sub _getRecords($$;$) { + my ($self, $table, $condition, $additional) = @_; + my ($err, $msg); - - my $statement = "select * from $table where $condition"; - - my $sth = $self->{db}->prepare ($statement); - + + $additional ||= ''; + + my $statement = "select * from $table"; + $statement .= " where $condition" if $condition; + $statement .= $additional; + + my $sth = $self->{db}->prepare($statement); + unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); + croak $msg; } # if @@ -280,224 +280,222 @@ 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; } else { - ($err, $msg) = $self->_dberror ('Unable to execute statement', + ($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" + + $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}); + $self->_connect($self->{dbserver}); sleep $sleepTime; } # while - $self->Error ("After $maxAttempts attempts I could not connect to the database", $err) + $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 +} # _getRecords -sub _aliasSystem ($) { +sub _aliasSystem($) { my ($self, $system) = @_; - - my %system = $self->GetSystem ($system); - + + my %system = $self->GetSystem($system); + if ($system{name}) { return $system{name}; } else { - return; + return; } # if } # _aliasSystem -sub _getLastID () { +sub _getLastID() { my ($self) = @_; - + my $statement = 'select last_insert_id()'; - - my $sth = $self->{db}->prepare ($statement); - + + my $sth = $self->{db}->prepare($statement); + my ($err, $msg); - + unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + ($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); - + ($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 (;$) { +sub _connect(;$) { my ($self, $dbserver) = @_; - + $dbserver ||= $CLEAROPTS{CLEARADM_SERVER}; - + my $dbname = 'clearadm'; my $dbdriver = 'mysql'; - $self->{db} = DBI->connect ( - "DBI:$dbdriver:$dbname:$dbserver", + $self->{db} = DBI->connect( + "DBI:$dbdriver:$dbname:$dbserver", $CLEAROPTS{CLEARADM_USERNAME}, $CLEAROPTS{CLEARADM_PASSWORD}, {PrintError => 0}, - ) or croak ( - "Couldn't connect to $dbname database " + ) or croak( + "Couldn't connect to $dbname database " . "as $CLEAROPTS{CLEARADM_USERNAME}\@$CLEAROPTS{CLEARADM_SERVER}" ); - + $self->{dbserver} = $dbserver; - + return; } # _connect -sub new (;$) { +sub new(;$) { my ($class, $dbserver) = @_; my $self = bless {}, $class; - $self->_connect ($dbserver); + $self->_connect($dbserver); return $self; } # new -sub SetNotify () { +sub SetNotify() { my ($self) = @_; - + $self->{NOTIFY} = $CLEAROPTS{CLEARADM_NOTIFY}; - + return; } # SetNotify -sub Error ($;$) { +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 ( + mail( to => $self->{NOTIFY}, subject => 'Internal error occurred in Clearadm', data => "

An unexpected, internal error occurred in Clearadm:

$msg

", mode => 'html', ); - + exit $errno if $errno > 0; } # if } # if - + return; } # Error -sub AddSystem (%) { +sub AddSystem(%) { my ($self, %system) = @_; - + my @requiredFields = ( 'name', ); my $result = _checkRequiredFields \@requiredFields, \%system; - - return -1, "AddSystem: $result" - if $result; - + + return -1, "AddSystem: $result" if $result; + $system{loadavgHist} ||= $defaultLoadavgHist; - - return $self->_addRecord ('system', %system); + + return $self->_addRecord('system', %system); } # AddSystem -sub DeleteSystem ($) { +sub DeleteSystem($) { my ($self, $name) = @_; - return $self->_deleteRecord ('system', "name='$name'"); + return $self->_deleteRecord('system', "name='$name'"); } # DeleteSystem sub UpdateSystem ($%) { my ($self, $name, %update) = @_; - return $self->_updateRecord ('system', "name='$name'", %update); + return $self->_updateRecord('system', "name='$name'", %update); } # UpdateSystem -sub GetSystem ($) { +sub GetSystem($) { my ($self, $system) = @_; - - return - unless $system; - - my @records = $self->_getRecords ( - 'system', + + return unless $system; + + my @records = $self->_getRecords( + 'system', "name='$system' or alias like '%$system%'" ); - + if ($records[0]) { return %{$records[0]}; } else { - return; + return; } # if } # GetSystem -sub FindSystem (;$) { +sub FindSystem(;$) { my ($self, $system) = @_; $system ||= ''; - + my $condition = "name like '%$system%' or alias like '%$system%'"; - - return $self->_getRecords ('system', $condition); + + return $self->_getRecords('system', $condition); } # FindSystem -sub SearchSystem (;$) { +sub SearchSystem(;$) { my ($self, $condition) = @_; - + $condition = "name like '%'" unless $condition; - - return $self->_getRecords ('system', $condition); + + return $self->_getRecords('system', $condition); } # SearchSystem -sub AddPackage (%) { +sub AddPackage(%) { my ($self, %package) = @_; - + my @requiredFields = ( 'system', 'name', @@ -505,73 +503,67 @@ sub AddPackage (%) { ); my $result = _checkRequiredFields \@requiredFields, \%package; - - return -1, "AddPackage: $result" - if $result; - - return $self->_addRecord ('package', %package); + + return -1, "AddPackage: $result" if $result; + + return $self->_addRecord('package', %package); } # AddPackage -sub DeletePackage ($$) { +sub DeletePackage($$) { my ($self, $system, $name) = @_; - - return $self->_deleteRecord ( - 'package', + + return $self->_deleteRecord( + 'package', "(system='$system' or alias='$system') and name='$name'"); } # DeletePackage -sub UpdatePackage ($$%) { +sub UpdatePackage($$%) { my ($self, $system, $name, %update) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - - return $self->_updateRecord ('package', "system='$system'", %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', + + $system = $self->_aliasSystem($system); + + return unless $system; + return unless $name; + + my @records = $self->_getRecords( + 'package', "system='$system' and name='$name'" ); - + if ($records[0]) { return %{$records[0]}; } else { - return; + return; } # if } # GetPackage -sub FindPackage ($;$) { +sub FindPackage($;$) { my ($self, $system, $name) = @_; $name ||= ''; - $system = $self->_aliasSystem ($system); - - return - unless $system; - + $system = $self->_aliasSystem($system); + + return unless $system; + my $condition = "system='$system' and name like '%$name%'"; - - return $self->_getRecords ('package', $condition); + + return $self->_getRecords('package', $condition); } # FindPackage -sub AddFilesystem (%) { +sub AddFilesystem(%) { my ($self, %filesystem) = @_; - + my @requiredFields = ( 'system', 'filesystem', @@ -579,61 +571,55 @@ sub AddFilesystem (%) { ); my $result = _checkRequiredFields \@requiredFields, \%filesystem; - - return -1, "AddFilesystem: $result" - if $result; - + + return -1, "AddFilesystem: $result" if $result; + # Default filesystem threshold $filesystem{threshold} ||= $defaultFilesystemThreshold; - - return $self->_addRecord ('filesystem', %filesystem); + + return $self->_addRecord('filesystem', %filesystem); } # AddFilesystem -sub DeleteFilesystem ($$) { +sub DeleteFilesystem($$) { my ($self, $system, $filesystem) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - - return $self->_deleteRecord ( - 'filesystem', + + $system = $self->_aliasSystem($system); + + return unless $system; + + return $self->_deleteRecord( + 'filesystem', "system='$system' and filesystem='$filesystem'" ); } # DeleteFilesystem -sub UpdateFilesystem ($$%) { +sub UpdateFilesystem($$%) { my ($self, $system, $filesystem, %update) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - - return $self->_updateRecord ( + + $system = $self->_aliasSystem($system); + + return unless $system; + + return $self->_updateRecord( 'filesystem', "system='$system' and filesystem='$filesystem'", %update ); } # UpdateFilesystem -sub GetFilesystem ($$) { +sub GetFilesystem($$) { my ($self, $system, $filesystem) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - - return - unless $filesystem; - - my @records = $self->_getRecords ( - 'filesystem', + + $system = $self->_aliasSystem($system); + + return unless $system; + return unless $filesystem; + + my @records = $self->_getRecords( + 'filesystem', "system='$system' and filesystem='$filesystem'" ); - + if ($records[0]) { return %{$records[0]}; } else { @@ -641,156 +627,199 @@ sub GetFilesystem ($$) { } # if } # GetFilesystem -sub FindFilesystem ($;$) { +sub FindFilesystem($;$) { my ($self, $system, $filesystem) = @_; - + $filesystem ||= ''; - $system = $self->_aliasSystem ($system); - - return - unless $system; + $system = $self->_aliasSystem($system); + + return unless $system; - my $condition = "system='$system' and filesystem like '%$filesystem%'"; - - return $self->_getRecords ('filesystem', $condition); + my $condition = "system='$system' and filesystem like '%$filesystem%'"; + + return $self->_getRecords('filesystem', $condition); } # FindFilesystem -sub AddVob (%) { +sub AddVob(%) { my ($self, %vob) = @_; - + my @requiredFields = ( - 'system', 'tag', + 'region', ); my $result = _checkRequiredFields \@requiredFields, \%vob; - - return -1, "AddVob: $result" - if $result; - - return $self->_addRecord ('vob', %vob); + + return -1, "AddVob: $result" if $result; + + return $self->_addRecord('vob', %vob); } # AddVob -sub DeleteVob ($) { - my ($self, $tag) = @_; - - return $self->_deleteRecord ('vob', "tag='$tag'"); +sub DeleteVob($$) { + my ($self, $tag, $region) = @_; + + return $self->_deleteRecord('vob', "tag='$tag' and region='$region'"); } # DeleteVob -sub GetVob ($) { - my ($self, $tag) = @_; - - return - unless $tag; - - my @records = $self->_getRecords ('vob', "tag='$tag'"); - +sub GetVob($$) { + my ($self, $tag, $region) = @_; + + return unless $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) = @_; +<<<<<<< HEAD +sub FindVobStorage(;$$) { + my ($self, $tag, $region) = @_; + + $tag ||= ''; + $region ||= ''; + +======= +sub FindVob($;$) { + my ($self, $tag, $region) = @_; + + # Windows vob tags begin with "\", which is problematic. The solution is to + # escape the "\" + $tag =~ s/^\\/\\\\/; + + my $condition = "tag like '%$tag%'"; + + $condition .= " and region='$region'" if $region; + + return $self->_getRecords('vobstorage', $condition); +} # FindVobStorage + +sub FindVob(;$$) { + my ($self, $tag, $region) = @_; + + $tag ||= ''; + $region ||= ''; + + # Windows vob tags begin with "\", which is problematic. The solution is to + # escape the "\" + $tag =~ s/^\\/\\\\/; + + my $condition = "tag like '%$tag%'"; - return $self->_getRecords ('vob', "tag like '%$tag%'"); + $condition .= " and region='$region'" if $region; + + return $self->_getRecords('vob', $condition); } # FindVob -sub AddView (%) { +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; - - return -1, "AddView: $result" - if $result; - - return $self->_addRecord ('view', %view); + + return -1, "AddView: $result" if $result; + + return $self->_addRecord('view', %view); } # AddView -sub DeleteView ($) { - my ($self, $tag) = @_; - - return $self->_deleteRecord ('vob', "tag='$tag'"); +sub DeleteView($$) { + my ($self, $tag, $region) = @_; + + return $self->_deleteRecord('vob', "tag='$tag' and region='$region'"); } # DeleteView -sub GetView ($) { - my ($self, $tag) = @_; - - return - unless $tag; - - my @records = $self->_getRecords ('view', "tag='$tag'"); - +sub UpdateView(%) { + my ($self, %view) = @_; + + return $self->_updateRecord('view', "tag='$view{tag}' and region='$view{region}'", %view); +} # UpdateView + +sub GetView($$) { + my ($self, $tag, $region) = @_; + + return unless $tag; + + my @records = $self->_getRecords('view', "tag='$tag' and region='$region'"); + if ($records[0]) { return %{$records[0]}; } else { - return; + return; } # if } # GetView -sub FindView (;$$$$) { - my ($self, $system, $region, $tag, $ownerName) = @_; +sub FindView(;$$$$) { + my ($self, $tag, $region, $ownerName) = @_; - $system ||= ''; - $region ||= ''; - $tag ||= ''; - $ownerName ||= ''; - my $condition; - - $condition = "system like '%$system%'"; - $condition .= ' and '; - $condition = "region like '%$region%'"; - $condition .= ' and '; - $condition .= "tag like '%$tag'"; - $condition .= ' and '; - $condition .= "ownerName like '%$ownerName'"; - - return $self->_getRecords ('view', $condition); + my @conditions; + + push @conditions, "tag like '%$tag%'" if $tag; + push @conditions, "region = '$region'" if $region; + push @conditions, "ownerName like '$ownerName'" if $ownerName; + + $condition = join " and ", @conditions if @conditions; + + return $self->_getRecords('view', $condition); } # FindView -sub AddFS (%) { +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); + + return $self->_addRecord('fs', %fs); } # AddFS -sub TrimFS ($$) { +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 %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 +829,42 @@ sub TrimFS ($$) { } # if my $oldage = SubtractDays $today, $days; - - my ($dberr, $dbmsg) = $self->_deleteRecord ( + + 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; - + 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; + + 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 ($) { +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 %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,45 +877,139 @@ sub TrimLoadavg ($) { } # if my $oldage = SubtractDays $today, $days; - - my ($dberr, $dbmsg) = $self->_deleteRecord ( + + my ($dberr, $dbmsg) = $self->_deleteRecord( 'loadavg', "system='$system' and timestamp<='$oldage'" ); - + if ($dbmsg eq 'Records deleted') { - return (0, $dbmsg) - if $dberr == 0; - + 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; + my ($err, $msg) = $self->AddRunlog(%runlog); + + $self->Error("Unable to add runload (Error: $err)\n$msg") if $err; } # if return ($dberr, $dbmsg); } # TrimLoadavg -sub GetFS ($$;$$$$) { +sub TrimStorage($$$) { + my ($self, $type, $tag, $region) = @_; + + my $today = Today2SQLDatetime; + + my $oldage = SubtractDays $today, $Clearadm::CLEAROPTS{CLEARADM_SCRUBDAYS}; + + my $table = $type =~ /vob/i + ? 'vobstorage' + : 'viewstorage'; + + my ($dberr, $dbmsg) = $self->_deleteRecord( + $table, + "tag='$tag' and region='$region' and timestamp<='$oldage'" + ); + + if ($dbmsg eq 'Records deleted') { + return (0, $dbmsg) if $dberr == 0; + + my %runlog; + + $runlog{task} = 'Scrub'; + $runlog{started} = $today; + $runlog{status} = 0; + $runlog{message} = + "Scrubbed $dberr ${type}storage records"; + + my ($err, $msg) = $self->AddRunlog(%runlog); + + $self->Error("Unable to add runload (Error: $err)\n$msg") if $err; + } # if + + return ($dberr, $dbmsg); +} # TrimStorage + +sub ValidateCCObjects() { + my ($self) = @_; + + my $vobRecordsDeleted = 0; + my $viewRecordsDeleted = 0; + + for my $region ($Clearcase::CC->regions) { + for my $type (qw(vob view)) { + my @ccobjs; + verbose "Processing ${type}s in $region"; + + if ($type eq 'vob') { + verbose "Finding all vobs in region $region"; + @ccobjs = $self->FindVob(undef, $region); + verbose 'Found ' . scalar @ccobjs . ' vobs to process'; + } elsif ($type eq 'view') { + verbose "Finding all views in region $region"; + @ccobjs = $self->FindView(undef, $region); + verbose 'Found ' . scalar @ccobjs . ' views to process'; + } # if + + for my $object (@ccobjs) { + my %ccobjrec = %$object; + + verbose "Processing $ccobjrec{tag}:$ccobjrec{region}"; + + my $ccobj; + + if ($type eq 'vob') { + $ccobj = Clearcase::Vob->new($ccobjrec{tag}, $ccobjrec{region}); + } else { + $ccobj = Clearcase::View->new($ccobjrec{tag}, $ccobjrec{region}); + } # if + + verbose_nolf 'Checking if ' . $ccobj->{tag} . ':' . $ccobj->{region} . ' exists anymore...'; + + if ($ccobj->exists) { + verbose ' it does! Skipping...'; + next; + } else { + verbose ' it doesn\'t!'; + } # if + + #next if $ccobj->exists; + + verbose "Deleting $type $ccobjrec{tag}:$ccobjrec{region}"; + + my ($recordsDeleted, $msg) = $self->_deleteRecord($type, + "tag='$ccobjrec{tag}' and region='$ccobjrec{region}'"); + + if ($msg ne 'Records deleted') { + return ($recordsDeleted, $msg); + } else { + $viewRecordsDeleted += $recordsDeleted if $type eq 'view'; + $vobRecordsDeleted += $recordsDeleted if $type eq 'vob'; + } # if + } # for + } # for + } # for + + return ($viewRecordsDeleted, $vobRecordsDeleted); +} # ValidateCCObjects + +sub GetFS($$;$$$$) { my ($self, $system, $filesystem, $start, $end, $count, $interval) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - - return - unless $filesystem; - + + $system = $self->_aliasSystem($system); + + return unless $system; + return unless $filesystem; + $interval ||= 'Minute'; - + my $size = $interval =~ /month/i ? 7 : $interval =~ /day/i @@ -896,32 +1017,32 @@ 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 # returns 40 rows we'll see only rows 1-10, not rows 31-40). We need limit # $offset, $count where $offset = the number of qualifying records minus # $count - my $nbrRecs = $self->Count ('fs', $condition); + 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,84 +1059,79 @@ from END my ($err, $msg); - - my $sth = $self->{db}->prepare ($statement); - + + my $sth = $self->{db}->prepare($statement); + unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + ($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); - + ($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 ($$) { +sub GetLatestFS($$) { my ($self, $system, $filesystem) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - - return - unless $filesystem; - - my @records = $self->_getRecords ( + + $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]}; + return %{$records[0]}; } else { - return; + return; } # if } # GetLatestFS -sub AddLoadavg () { +sub AddLoadavg() { my ($self, %loadavg) = @_; - + my @requiredFields = ( 'system', ); my $result = _checkRequiredFields \@requiredFields, \%loadavg; - - return -1, "AddLoadavg: $result" - if $result; - + + return -1, "AddLoadavg: $result" if $result; + # Timestamp record $loadavg{timestamp} = Today2SQLDatetime; - - return $self->_addRecord ('loadavg', %loadavg); + + return $self->_addRecord('loadavg', %loadavg); } # AddLoadavg -sub GetLoadavg ($;$$$$) { +sub GetLoadavg($;$$$$) { my ($self, $system, $start, $end, $count, $interval) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - + + $system = $self->_aliasSystem($system); + + return unless $system; + $interval ||= 'Minute'; - + my $size = $interval =~ /month/i ? 7 : $interval =~ /day/i @@ -1023,16 +1139,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) { @@ -1041,16 +1157,15 @@ sub GetLoadavg ($;$$$$) { # returns 40 rows we'll see only rows 1-10, not rows 31-40). We need limit # $offset, $count where $offset = the number of qualifying records minus # $count - my $nbrRecs = $self->Count ('loadavg', $condition); + my $nbrRecs = $self->Count('loadavg', $condition); my $offset = $nbrRecs - $count; - + # Offsets of < 0 are not allowed. - $offset = 0 - if $offset < 0; + $offset = 0 if $offset < 0; $condition .= " limit $offset, $count"; } # if - + my $statement = <<"END"; select system, @@ -1064,46 +1179,45 @@ from END my ($err, $msg); - - my $sth = $self->{db}->prepare ($statement); - + + my $sth = $self->{db}->prepare($statement); + unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + ($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); - + ($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 ($) { +sub GetLatestLoadavg($) { my ($self, $system) = @_; - - $system = $self->_aliasSystem ($system); - - return - unless $system; - - my @records = $self->_getRecords ( + + $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 { @@ -1111,226 +1225,310 @@ sub GetLatestLoadavg ($) { } # if } # GetLatestLoadavg -sub AddTask (%) { +sub GetStoragePool($$$;$$$$$) { + my ($self, $type, $tag, $storage, $region, $start, $end, $count, $interval) = @_; + + $interval ||= 'Day'; + $region ||= $Clearcase::CC->region; + + return unless $type =~ /vob/i or $type =~ /view/; + + my $size = $interval =~ /month/i + ? 7 + : $interval =~ /day/i + ? 10 + : $interval =~ /hour/i + ? 13 + : 16; + + 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'; + + $condition = "tag='$tag' and region='$region'"; + $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 + # returns 40 rows we'll see only rows 1-10, not rows 31-40). We need limit + # $offset, $count where $offset = the number of qualifying records minus + # $count + my $nbrRecs = $self->Count($table, $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 + tag, + region, + left(timestamp,$size) as timestamp, + avg($storage) as size +from + $table + where $condition +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; +} # GetStoragePool + +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 -1, "AddTask: $result" if $result; + + return $self->_addRecord('task', %task); } # AddTask -sub DeleteTask ($) { +sub DeleteTask($) { my ($self, $name) = @_; - - return $self->_deleteRecord ('task', "name='$name'"); + + return $self->_deleteRecord('task', "name='$name'"); } # DeleteTask -sub FindTask ($) { +sub FindTask($) { my ($self, $name) = @_; - + $name ||= ''; - + my $condition = "name like '%$name%'"; - - return $self->_getRecords ('task', $condition); + + return $self->_getRecords('task', $condition); } # FindTask -sub GetTask ($) { +sub GetTask($) { my ($self, $name) = @_; - - return - unless $name; - - my @records = $self->_getRecords ('task', "name='$name'"); + + return unless $name; + + my @records = $self->_getRecords('task', "name='$name'"); if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetTask -sub UpdateTask ($%) { +sub UpdateTask($%) { my ($self, $name, %update) = @_; - - return $self->_updateRecord ('task', "name='$name'", %update); + + return $self->_updateRecord('task', "name='$name'", %update); } # Update -sub AddSchedule (%) { +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 -1, "AddSchedule: $result" if $result; + + return $self->_addRecord('schedule', %schedule); } # AddSchedule -sub DeleteSchedule ($) { +sub DeleteSchedule($) { my ($self, $name) = @_; - - return $self->_deleteRecord ('schedule', "name='$name'"); + + return $self->_deleteRecord('schedule', "name='$name'"); } # DeleteSchedule -sub FindSchedule (;$$) { +sub FindSchedule(;$$) { my ($self, $name, $task) = @_; - + $name ||= ''; - $task||= ''; - + $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 ($) { +sub GetSchedule($) { my ($self, $name) = @_; - - my @records = $self->_getRecords ('schedule', "name='$name'"); - + + my @records = $self->_getRecords('schedule', "name='$name'"); + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetSchedule -sub UpdateSchedule ($%) { +sub UpdateSchedule($%) { my ($self, $name, %update) = @_; - - return $self->_updateRecord ('schedule', "name='$name'", %update); + + return $self->_updateRecord('schedule', "name='$name'", %update); } # UpdateSchedule -sub AddRunlog (%) { +sub AddRunlog(%) { my ($self, %runlog) = @_; - + my @requiredFields = ( 'task', ); - + my $result = _checkRequiredFields \@requiredFields, \%runlog; - - return -1, "AddRunlog: $result" - if $result; - + + return -1, "AddRunlog: $result" if $result; + $runlog{ended} = Today2SQLDatetime; - - my ($err, $msg) = $self->_addRecord ('runlog', %runlog); + + $runlog{system} = hostname if $runlog{system} =~ /localhost/i; + + my ($err, $msg) = $self->_addRecord('runlog', %runlog); return ($err, $msg, $self->_getLastID); } # AddRunlog -sub DeleteRunlog ($) { +sub DeleteRunlog($) { my ($self, $condition) = @_; - - return $self->_deleteRecord ('runlog', $condition); + + return $self->_deleteRecord('runlog', $condition); } # DeleteRunlog -sub FindRunlog (;$$$$$$) { +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; - + my ($condition, $conditions); + my $limit = ''; + 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 ($task !~ /all/i) { + $conditions++; + $condition = "task like '%$task%'"; + } # if + + if ($system !~ /all/i) { + $condition .= ' and ' if $conditions; + $condition .= "system like '%$system%'"; + $conditions++; + } # if + + if ($status) { + $condition .= ' and ' if $conditions; + if ($status =~ /!(-*\d+)/) { - $condition .= " and status<>$1"; + $condition .= "status<>$1"; } else { - $condition .= " and status=$status" + $condition .= "status=$status" } # if } # if - - $condition .= " order by started desc"; - + + # Need defined here as $start may be 0! if (defined $start) { $page ||= 10; - $condition .= " limit $start, $page"; + $limit = "limit $start, $page"; } # unless } else { $condition = "id=$id"; } # unless - - return $self->_getRecords ('runlog', $condition); + + return $self->_getRecords('runlog', $condition, " order by started desc $limit"); } # FindRunlog -sub GetRunlog ($) { - my ($self, $id) = @_; - - return - unless $id; - - my @records = $self->_getRecords ('runlog', "id=$id"); - +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 ($%) { +sub UpdateRunlog($%) { my ($self, $id, %update) = @_; - - return $self->_updateRecord ('runlog', "id=$id", %update); + + return $self->_updateRecord('runlog', "id=$id", %update); } # UpdateRunlog -sub Count ($;$) { +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); - + + my $sth = $self->{db}->prepare($statement); + unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + ($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); - + ($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 +1541,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]; @@ -1363,11 +1561,11 @@ sub Count ($;$) { # execute the work to be done, timing it, and subtracting it from the $sleep # time returned. If the caller exhausts the $sleep time then they should call # us again. -sub GetWork () { +sub GetWork() { my ($self) = @_; - + my ($err, $msg); - + my $statement = <<"END"; select schedule.name as schedulename, @@ -1385,43 +1583,43 @@ where and schedule.active='true' order by lastrun END - - my $sth = $self->{db}->prepare ($statement); - + + my $sth = $self->{db}->prepare($statement); + unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + ($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); - + ($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}); - + 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 +1632,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); - + 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,94 +1656,93 @@ END if (@records == 0 and not $sleep) { $sleep = 60; } # if - - return ($sleep, @records); + + return ($sleep, @records); } # GetWork -sub GetUniqueList ($$) { +sub GetUniqueList($$) { my ($self, $table, $field) = @_; - + my ($err, $msg); - + my $statement = "select $field from $table group by $field"; - - my $sth = $self->{db}->prepare ($statement); - + + my $sth = $self->{db}->prepare($statement); + unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + ($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); - + ($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, ''; } # 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 -1, "AddAlert: $result" if $result; + + return $self->_addRecord('alert', %alert); } # AddAlert -sub DeleteAlert ($) { +sub DeleteAlert($) { my ($self, $name) = @_; - - return $self->_deleteRecord ('alert', "name='$name'"); + + return $self->_deleteRecord('alert', "name='$name'"); } # DeleteAlert -sub FindAlert (;$) { +sub FindAlert(;$) { my ($self, $alert) = @_; - + $alert ||= ''; - + my $condition = "name like '%$alert%'"; - - return $self->_getRecords ('alert', $condition); + + return $self->_getRecords('alert', $condition); } # FindAlert -sub GetAlert ($) { +sub GetAlert($) { my ($self, $name) = @_; - + return unless $name; - - my @records = $self->_getRecords ('alert', "name='$name'"); - + + my @records = $self->_getRecords('alert', "name='$name'"); + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetAlert -sub SendAlert ($$$$$$$) { +sub SendAlert($$$$$$$) { my ( $self, $alert, @@ -1556,28 +1753,28 @@ sub SendAlert ($$$$$$$) { $to, $runlogID, ) = @_; - + my $footing = '

'; $footing .= ''; my $year = (localtime)[5] + 1900; - $footing .= "Clearadm
"; + $footing .= "Clearadm
"; $footing .= "Copyright © $year, ClearSCM, Inc. - All rights reserved"; - - my %alert = $self->GetAlert ($alert); - + + my %alert = $self->GetAlert($alert); + if ($alert{type} eq 'email') { my $from = 'Clearadm@' . hostdomain; - - mail ( + + 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" + $self->Error("Don't know how to send $alert{type} alerts\n" . "Subject: $subject\n" . "Message: $message", 1); } # if @@ -1589,40 +1786,40 @@ sub SendAlert ($$$$$$$) { notification => $notification, runlog => $runlogID, timestamp => Today2SQLDatetime, - message => $subject, - ); - - return $self->AddAlertlog (%alertlog); + message => $subject, + ); + + return $self->AddAlertlog(%alertlog); } # SendAlert -sub GetLastAlert ($$) { +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); - + + 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); - + or return $self->_dberror('Unable to execute statement', $statement); + my $alertlog= $sth->fetchrow_hashref; - + $sth->finish; - + if ($alertlog) { return %$alertlog; } else { @@ -1630,40 +1827,40 @@ END } # if } # GetLastAlert -sub GetLastTaskFailure ($$) { +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); - + + 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); - + 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,30 +1873,30 @@ where status <> 0 and task='$task' and system='$system' -order by +order by ended desc limit 0, 1 END - $sth = $self->{db}->prepare ($statement) - or return $self->_dberror ('Unable to prepare statement', $statement); - + $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); - + 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 ($$$$$$) { +sub Notify($$$$$$) { my ( $self, $notification, @@ -1713,65 +1910,64 @@ sub Notify ($$$$$$) { $runlogID = $self->_getLastID unless $runlogID; - + my ($err, $msg); - + # Update filesystem, if $filesystem was specified if ($filesystem) { - ($err, $msg) = $self->UpdateFilesystem ( + ($err, $msg) = $self->UpdateFilesystem( $system, $filesystem, ( notification => $notification, ), ); - - $self->Error ("Unable to set notification for filesystem $system:$filesystem " + + $self->Error("Unable to set notification for filesystem $system:$filesystem " . "(Status: $err)\n$msg", $err) if $err; } # if - + # Update system - ($err, $msg) = $self->UpdateSystem ( + ($err, $msg) = $self->UpdateSystem( $system, ( notification => $notification, ), ); - - my %notification = $self->GetNotification ($notification); - - my %lastnotified = $self->GetLastAlert ($notification, $system); - + + 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)); + $lastnotified = Add($lastnotified, (hours => 1)); } elsif ($notification{nomorethan} =~ /day/i) { - $lastnotified = Add ($lastnotified, (days => 1)); + $lastnotified = Add($lastnotified, (days => 1)); } elsif ($notification{nomorethan} =~ /week/i) { - $lastnotified = Add ($lastnotified, (days => 7)); + $lastnotified = Add($lastnotified, (days => 7)); } elsif ($notification{nomorethan} =~ /month/i) { - $lastnotified = Add ($lastnotified, (month => 1)); + $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 + my $diff = Compare($today, $lastnotified); + + return if $diff <= 0; + } # if my $when = Today2SQLDatetime; my $nomorethan = lc $notification{nomorethan}; - my %alert = $self->GetAlert ($notification{alert}); + my %alert = $self->GetAlert($notification{alert}); my $to = $alert{who}; # If $to is null then this means to send the alert to the admin for the # machine. unless ($to) { if ($system) { - my %system = $self->GetSystem ($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,14 +1976,14 @@ sub Notify ($$$$$$) { $to = $self->{NOTIFY}; } # if } # unless - + unless ($to) { Error "To undefined"; } # unless - + $message .= "

You will receive this alert no more than $nomorethan.

"; - - ($err, $msg) = $self->SendAlert ( + + ($err, $msg) = $self->SendAlert( $notification{alert}, $system, $notification{name}, @@ -1796,104 +1992,101 @@ sub Notify ($$$$$$) { $to, $runlogID, ); - - $self->Error ("Unable to send alert (Status: $err)\n$msg", $err) if $err; + + $self->Error("Unable to send alert (Status: $err)\n$msg", $err) if $err; verbose "Sent alert to $to"; # Update runlog to indicate we notified the user for this execution - ($err, $msg) = $self->UpdateRunlog ( + ($err, $msg) = $self->UpdateRunlog( $runlogID, ( alerted => 'true', ), ); - - $self->Error ("Unable to update runlog (Status: $err)\n$msg", $err) if $err; - return; + $self->Error("Unable to update runlog (Status: $err)\n$msg", $err) if $err; + + return; } # Notify -sub ClearNotifications ($$;$) { +sub ClearNotifications($$;$) { my ($self, $system, $filesystem) = @_; - + my ($err, $msg); - + if ($filesystem) { - ($err, $msg) = $self->UpdateFilesystem ( + ($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 - - my %system = $self->GetSystem ($system); - - return - unless $system; - - if ($system{notification} and + } # for + + my %system = $self->GetSystem($system); + + return unless $system; + + if ($system{notification} and $system{notification} eq 'Filesystem' and $filesystemsAlerted == 0) { - ($err, $msg) = $self->UpdateSystem ($system, (notification => undef)); + ($err, $msg) = $self->UpdateSystem($system, (notification => undef)); - $self->Error ("Unable to clear notification for system $system " + $self->Error("Unable to clear notification for system $system " . "(Status: $err)\n$msg", $err) if $err; } # if } else { - ($err, $msg) = $self->UpdateSystem ($system, (notification => undef)); - - $self->Error ("Unable to clear notification for system $system " + ($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 -sub SystemAlive (%) { +sub SystemAlive(%) { my ($self, %system) = @_; # 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! - return 1 - unless $system{lastheardfrom}; - + # 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'; - + 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)) { - $self->UpdateSystem ( + $lastheardfrom = Add($lastheardfrom, (seconds => $tenMinutes)); + + if (DateToEpoch($lastheardfrom) < DateToEpoch($today)) { + $self->UpdateSystem( $system{name}, ( notification => 'Heartbeat' ), ); - + return; } else { if ($system{notification}) { - $self->UpdateSystem ( + $self->UpdateSystem( $system{name}, ( notification => undef ), @@ -1903,155 +2096,185 @@ sub SystemAlive (%) { } # if } # SystemAlive -sub UpdateAlert ($%) { +sub UpdateAlert($%) { my ($self, $name, %update) = @_; - - return $self->_updateRecord ( + + return $self->_updateRecord( 'alert', "name='$name'", %update ); } # UpdateAlert -sub AddAlertlog (%) { +sub AddAlertlog(%) { my ($self, %alertlog) = @_; - + my @requiredFields = ( 'alert', 'notification', ); - + my $result = _checkRequiredFields \@requiredFields, \%alertlog; - - return -1, "AddAlertlog: $result" - if $result; - + + return -1, "AddAlertlog: $result" if $result; + # Timestamp record $alertlog{timestamp} = Today2SQLDatetime; - - return $self->_addRecord ('alertlog', %alertlog); + + return $self->_addRecord('alertlog', %alertlog); } # AddAlertlog -sub DeleteAlertlog ($) { +sub DeleteAlertlog($) { my ($self, $condition) = @_; - + return unless $condition; - + if ($condition =~ /all/i) { - return $self->_deleteRecord ('alertlog'); + return $self->_deleteRecord('alertlog'); } else { - return $self->_deleteRecord ('alertlog', $condition); + return $self->_deleteRecord('alertlog', $condition); } # if } # DeleteAlertlog -sub FindAlertlog (;$$$$$) { +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"; - } # unless - return $self->_getRecords ('alertlog', $condition); + if (defined $start) { + $page ||= 10; + $condition .= " limit $start, $page"; + } # unless + + return $self->_getRecords('alertlog', $condition); } # FindAlertLog -sub GetAlertlog ($) { +sub GetAlertlog($) { my ($self, $alert) = @_; - - return - unless $alert; - - my @records = $self->_getRecords ('alertlog', "alert='$alert'"); - + + return unless $alert; + + my @records = $self->_getRecords('alertlog', "alert='$alert'"); + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetAlertlog -sub UpdateAlertlog ($%) { +sub UpdateAlertlog($%) { my ($self, $alert, %update) = @_; - - return $self->_updateRecord ( + + return $self->_updateRecord( 'alertlog', "alert='$alert'", %update ); } # UpdateAlertlog -sub AddNotification (%) { +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 -1, "AddNotification: $result" if $result; + + return $self->_addRecord('notification', %notification); } # AddNotification -sub DeleteNotification ($) { +sub DeleteNotification($) { my ($self, $name) = @_; - - return $self->_deleteRecord ('notification', "name='$name'"); + + return $self->_deleteRecord('notification', "name='$name'"); } # DeletePackage -sub FindNotification (;$$) { +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 ($) { +sub GetNotification($) { my ($self, $name) = @_; - - return - unless $name; - - my @records = $self->_getRecords ('notification', "name='$name'"); - + + return unless $name; + + my @records = $self->_getRecords('notification', "name='$name'"); + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetNotification -sub UpdateNotification ($%) { +sub UpdateNotification($%) { my ($self, $name, %update) = @_; - - return $self->_updateRecord ( + + return $self->_updateRecord( 'notification', "name='$name'", %update ); } # UpdateNotification +sub AddVobStorage(%) { + my ($self, %vobstorage) = @_; + + my @requiredFields = ( + 'tag', + ); + + my $result = _checkRequiredFields \@requiredFields, \%vobstorage; + + return -1, "AddVobStorage: $result" if $result; + + # Timestamp record + $vobstorage{timestamp} = Today2SQLDatetime; + + return $self->_addRecord('vobstorage', %vobstorage); +} # AddVobStorage + +sub AddViewStorage(%) { + my ($self, %viewstorage) = @_; + + my @requiredFields = ( + 'tag', + ); + + my $result = _checkRequiredFields \@requiredFields, \%viewstorage; + + return -1, "AddViewStorage: $result" if $result; + + # Timestamp record + $viewstorage{timestamp} = Today2SQLDatetime; + + return $self->_addRecord('viewstorage', %viewstorage); +} # AddViewStorage + 1; =pod @@ -2078,7 +2301,7 @@ L =head2 ClearSCM Perl Modules -=begin man +=begin man DateUtils Display