X-Git-Url: https://defaria.com/gitweb/?a=blobdiff_plain;f=clearadm%2Flib%2FClearadm.pm;h=719b7722974215d8c60ea04d61da1f75e8ee7aee;hb=559f9045ae05e457c7eb4b6c684aa9651b98971a;hp=7e571090d12637c3e77c439fdc82aceeb0547a13;hpb=81cbd130706633b1c19ff59371c2ef61d80c562b;p=clearscm.git diff --git a/clearadm/lib/Clearadm.pm b/clearadm/lib/Clearadm.pm index 7e57109..719b772 100644 --- a/clearadm/lib/Clearadm.pm +++ b/clearadm/lib/Clearadm.pm @@ -36,7 +36,7 @@ specifics about the method you are envoking. # Create new Clearadm object my $clearadm = new Clearadm; - + # Add a new system my %system = ( name => 'jupiter', @@ -46,22 +46,22 @@ specifics about the method you are envoking. type => 'Linux', description => 'Home server', ); - + my ($err, $msg) = $clearadm->AddSystem (%system); - + # Find systems matching 'jup' my @systems = $clearadm->FindSystem ('jup'); - + # Get a system by name my %system = $clearadm->GetSystem ('jupiter'); - + # Update system my %update = ( 'region' => 'East Coast', ); my ($err, $msg) = $clearadm->UpdateSystem ('jupiter', %update); - + # Delete system (Warning: will delete all related records regarding this # system). my ($err, $msg) = $clearadm->DeleteSystem ('jupiter'); @@ -69,8 +69,8 @@ specifics about the method you are envoking. =head1 DESCRIPTION This package provides and object oriented interface to the Clearadm database. -Methods are provided to manipulate records by adding, updating and deleting -them. In general you need to specify a hash which contains keys and values +Methods are provided to manipulate records by adding, updating and deleting +them. In general you need to specify a hash which contains keys and values corresponding to the database field names and values. =head1 ROUTINES @@ -86,6 +86,7 @@ use warnings; use Carp; use DBI; +use File::Basename; use Net::Domain qw(hostdomain); use FindBin; @@ -97,24 +98,26 @@ use Display; use GetConfig; use Mail; -our %CLEAROPTS = GetConfig ("$FindBin::Bin/etc/clearadm.conf"); +my $conf = dirname (__FILE__) . '/../etc/clearadm.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'; @@ -129,12 +132,12 @@ sub _dberror ($$) { my $dberr = $self->{db}->err; my $dberrmsg = $self->{db}->errstr; - + $dberr ||= 0; $dberrmsg ||= 'Success'; my $message = ''; - + if ($dberr) { my $function = (caller (1)) [3]; @@ -142,82 +145,82 @@ sub _dberror ($$) { . "SQL Statement: $statement"; } # if - return $dberr, $message; + return $dberr, $message; } # _dberror sub _formatValues (@) { my ($self, @values) = @_; - + my @returnValues; - + # Quote data values - push @returnValues, $_ eq '' ? 'null' : $self->{db}->quote ($_) - foreach (@values); - + push @returnValues, $_ eq '' ? 'null' : $self->{db}->quote ($_) + for (@values); + return @returnValues; } # _formatValues sub _formatNameValues (%) { my ($self, %rec) = @_; - + my @nameValueStrs; - + push @nameValueStrs, "$_=" . $self->{db}->quote ($rec{$_}) - foreach (keys %rec); - + for (keys %rec); + return @nameValueStrs; } # _formatNameValues sub _addRecord ($%) { my ($self, $table, %rec) = @_; - + my $statement = "insert into $table ("; $statement .= join ',', keys %rec; $statement .= ') values ('; $statement .= join ',', $self->_formatValues (values %rec); $statement .= ')'; - + my ($err, $msg); - + $self->{db}->do ($statement); - + return $self->_dberror ("Unable to add record to $table", $statement); } # _addRecord sub _deleteRecord ($;$) { my ($self, $table, $condition) = @_; - + my $count; - + my $statement = "select count(*) from $table "; $statement .= "where $condition" if $condition; - + my $sth = $self->{db}->prepare ($statement) or return $self->_dberror ('Unable to prepare statement', $statement); - + $sth->execute or return $self->_dberror ('Unable to execute statement', $statement); - + my @row = $sth->fetchrow_array; - + $sth->finish; - + if ($row[0]) { $count = $row[0]; } else { $count = 0; } # if - + return ($count, 'Records deleted') if $count == 0; - + $statement = "delete from $table "; $statement .= "where $condition" if $condition; - + $self->{db}->do ($statement); - + if ($self->{db}->err) { return $self->_dberror ("Unable to delete record from $table", $statement); } else { @@ -232,44 +235,44 @@ sub _updateRecord ($$%) { $statement .= join ',', $self->_formatNameValues (%rec); $statement .= " where $condition" if $condition; - + $self->{db}->do ($statement); - + return $self->_dberror ("Unable to update record in $table", $statement); } # _updateRecord sub _checkRequiredFields ($$) { my ($fields, $rec) = @_; - - foreach my $fieldname (@$fields) { + + for my $fieldname (@$fields) { my $found = 0; - - foreach (keys %$rec) { + + for (keys %$rec) { if ($fieldname eq $_) { $found = 1; last; } # if - } # foreach - + } # for + return "$fieldname is required" unless $found; - } # foreach - + } # for + return; } # _checkRequiredFields sub _getRecords ($$) { my ($self, $table, $condition) = @_; - + my ($err, $msg); - + my $statement = "select * from $table where $condition"; - + my $sth = $self->{db}->prepare ($statement); - + unless ($sth) { ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + croak $msg; } # if @@ -277,15 +280,15 @@ sub _getRecords ($$) { my $maxAttempts = 3; my $sleepTime = 30; my $status; - + # We've been having the server going away. Supposedly it should reconnect so - # here we simply retry up to $maxAttempts times to re-execute the statement. + # here we simply retry up to $maxAttempts times to re-execute the statement. # (Are there other places where we need to do this?) $err = 2006; - + while ($err == 2006 and $attempts++ < $maxAttempts) { $status = $sth->execute; - + if ($status) { $err = 0; last; @@ -293,16 +296,16 @@ sub _getRecords ($$) { ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); } # if - + last if $err == 0; - + croak $msg unless $err == 2006; my $timestamp = YMDHMS; - + $self->Error ("$timestamp: Unable to talk to DB server.\n\n$msg\n\n" . "Will try again in $sleepTime seconds", -1); - + # Try to reconnect $self->_connect ($self->{dbserver}); @@ -311,21 +314,21 @@ sub _getRecords ($$) { $self->Error ("After $maxAttempts attempts I could not connect to the database", $err) if ($err == 2006 and $attempts > $maxAttempts); - + my @records; - + while (my $row = $sth->fetchrow_hashref) { push @records, $row; } # while - + return @records; } # _getRecord sub _aliasSystem ($) { my ($self, $system) = @_; - + my %system = $self->GetSystem ($system); - + if ($system{name}) { return $system{name}; } else { @@ -335,54 +338,54 @@ sub _aliasSystem ($) { sub _getLastID () { my ($self) = @_; - + my $statement = 'select last_insert_id()'; - + my $sth = $self->{db}->prepare ($statement); - + my ($err, $msg); - + unless ($sth) { ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + croak $msg; } # if - + my $status = $sth->execute; - + unless ($status) { ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); - + croak $msg; } # if - + my @records; my @row = $sth->fetchrow_array; - + return $row[0]; } # _getLastID sub _connect (;$) { my ($self, $dbserver) = @_; - + $dbserver ||= $CLEAROPTS{CLEARADM_SERVER}; - + my $dbname = 'clearadm'; my $dbdriver = 'mysql'; $self->{db} = DBI->connect ( - "DBI:$dbdriver:$dbname:$dbserver", + "DBI:$dbdriver:$dbname:$dbserver", $CLEAROPTS{CLEARADM_USERNAME}, $CLEAROPTS{CLEARADM_PASSWORD}, {PrintError => 0}, ) or croak ( - "Couldn't connect to $dbname database " + "Couldn't connect to $dbname database " . "as $CLEAROPTS{CLEARADM_USERNAME}\@$CLEAROPTS{CLEARADM_SERVER}" ); - + $self->{dbserver} = $dbserver; - + return; } # _connect @@ -398,9 +401,9 @@ sub new (;$) { sub SetNotify () { my ($self) = @_; - + $self->{NOTIFY} = $CLEAROPTS{CLEARADM_NOTIFY}; - + return; } # SetNotify @@ -408,9 +411,9 @@ sub Error ($;$) { my ($self, $msg, $errno) = @_; # If $errno is specified we need to stop. However we need to notify somebody - # that cleartasks is no longer running. + # that cleartasks is no longer running. error $msg; - + if ($errno) { if ($self->{NOTIFY}) { mail ( @@ -419,35 +422,35 @@ sub Error ($;$) { data => "

An unexpected, internal error occurred in Clearadm:

$msg

", mode => 'html', ); - + exit $errno if $errno > 0; } # if } # if - + return; } # Error sub AddSystem (%) { my ($self, %system) = @_; - + my @requiredFields = ( 'name', ); my $result = _checkRequiredFields \@requiredFields, \%system; - + return -1, "AddSystem: $result" if $result; - + $system{loadavgHist} ||= $defaultLoadavgHist; - + return $self->_addRecord ('system', %system); } # AddSystem sub DeleteSystem ($) { my ($self, $name) = @_; - return $self->_deleteRecord ('system', "name='$name'"); + return $self->_deleteRecord ('system', "name='$name'"); } # DeleteSystem sub UpdateSystem ($%) { @@ -458,15 +461,15 @@ sub UpdateSystem ($%) { sub GetSystem ($) { my ($self, $system) = @_; - + return unless $system; - + my @records = $self->_getRecords ( - 'system', + 'system', "name='$system' or alias like '%$system%'" ); - + if ($records[0]) { return %{$records[0]}; } else { @@ -478,15 +481,23 @@ sub FindSystem (;$) { my ($self, $system) = @_; $system ||= ''; - + my $condition = "name like '%$system%' or alias like '%$system%'"; - + return $self->_getRecords ('system', $condition); } # FindSystem +sub SearchSystem (;$) { + my ($self, $condition) = @_; + + $condition = "name like '%'" unless $condition; + + return $self->_getRecords ('system', $condition); +} # SearchSystem + sub AddPackage (%) { my ($self, %package) = @_; - + my @requiredFields = ( 'system', 'name', @@ -494,48 +505,48 @@ sub AddPackage (%) { ); my $result = _checkRequiredFields \@requiredFields, \%package; - + return -1, "AddPackage: $result" if $result; - + return $self->_addRecord ('package', %package); } # AddPackage sub DeletePackage ($$) { my ($self, $system, $name) = @_; - + return $self->_deleteRecord ( - 'package', + 'package', "(system='$system' or alias='$system') and name='$name'"); } # DeletePackage sub UpdatePackage ($$%) { my ($self, $system, $name, %update) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + return $self->_updateRecord ('package', "system='$system'", %update); } # UpdatePackage sub GetPackage($$) { my ($self, $system, $name) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + return unless $name; - + my @records = $self->_getRecords ( - 'package', + 'package', "system='$system' and name='$name'" ); - + if ($records[0]) { return %{$records[0]}; } else { @@ -549,18 +560,18 @@ sub FindPackage ($;$) { $name ||= ''; $system = $self->_aliasSystem ($system); - + return unless $system; - + my $condition = "system='$system' and name like '%$name%'"; - + return $self->_getRecords ('package', $condition); } # FindPackage sub AddFilesystem (%) { my ($self, %filesystem) = @_; - + my @requiredFields = ( 'system', 'filesystem', @@ -568,38 +579,38 @@ sub AddFilesystem (%) { ); my $result = _checkRequiredFields \@requiredFields, \%filesystem; - + return -1, "AddFilesystem: $result" if $result; - + # Default filesystem threshold $filesystem{threshold} ||= $defaultFilesystemThreshold; - + return $self->_addRecord ('filesystem', %filesystem); } # AddFilesystem sub DeleteFilesystem ($$) { my ($self, $system, $filesystem) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + return $self->_deleteRecord ( - 'filesystem', + 'filesystem', "system='$system' and filesystem='$filesystem'" ); } # DeleteFilesystem sub UpdateFilesystem ($$%) { my ($self, $system, $filesystem, %update) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + return $self->_updateRecord ( 'filesystem', "system='$system' and filesystem='$filesystem'", @@ -609,20 +620,20 @@ sub UpdateFilesystem ($$%) { sub GetFilesystem ($$) { my ($self, $system, $filesystem) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + return unless $filesystem; - + my @records = $self->_getRecords ( - 'filesystem', + 'filesystem', "system='$system' and filesystem='$filesystem'" ); - + if ($records[0]) { return %{$records[0]}; } else { @@ -632,49 +643,49 @@ sub GetFilesystem ($$) { sub FindFilesystem ($;$) { my ($self, $system, $filesystem) = @_; - + $filesystem ||= ''; $system = $self->_aliasSystem ($system); - + return unless $system; - my $condition = "system='$system' and filesystem like '%$filesystem%'"; - + my $condition = "system='$system' and filesystem like '%$filesystem%'"; + return $self->_getRecords ('filesystem', $condition); } # FindFilesystem sub AddVob (%) { my ($self, %vob) = @_; - + my @requiredFields = ( 'system', 'tag', ); my $result = _checkRequiredFields \@requiredFields, \%vob; - + return -1, "AddVob: $result" if $result; - + return $self->_addRecord ('vob', %vob); } # AddVob sub DeleteVob ($) { my ($self, $tag) = @_; - + return $self->_deleteRecord ('vob', "tag='$tag'"); } # DeleteVob sub GetVob ($) { my ($self, $tag) = @_; - - return + + return unless $tag; - + my @records = $self->_getRecords ('vob', "tag='$tag'"); - + if ($records[0]) { return %{$records[0]}; } else { @@ -684,40 +695,40 @@ sub GetVob ($) { sub FindVob ($) { my ($self, $tag) = @_; - + return $self->_getRecords ('vob', "tag like '%$tag%'"); } # FindVob sub AddView (%) { my ($self, %view) = @_; - + my @requiredFields = ( 'system', 'tag', ); my $result = _checkRequiredFields \@requiredFields, \%view; - + return -1, "AddView: $result" if $result; - + return $self->_addRecord ('view', %view); } # AddView sub DeleteView ($) { my ($self, $tag) = @_; - + return $self->_deleteRecord ('vob', "tag='$tag'"); } # DeleteView sub GetView ($) { my ($self, $tag) = @_; - + return unless $tag; - + my @records = $self->_getRecords ('view', "tag='$tag'"); - + if ($records[0]) { return %{$records[0]}; } else { @@ -732,9 +743,9 @@ sub FindView (;$$$$) { $region ||= ''; $tag ||= ''; $ownerName ||= ''; - + my $condition; - + $condition = "system like '%$system%'"; $condition .= ' and '; $condition = "region like '%$region%'"; @@ -742,44 +753,44 @@ sub FindView (;$$$$) { $condition .= "tag like '%$tag'"; $condition .= ' and '; $condition .= "ownerName like '%$ownerName'"; - + return $self->_getRecords ('view', $condition); } # FindView sub AddFS (%) { my ($self, %fs) = @_; - + my @requiredFields = ( 'system', 'filesystem', ); my $result = _checkRequiredFields \@requiredFields, \%fs; - + return -1, "AddFS: $result" if $result; - + # Timestamp record $fs{timestamp} = Today2SQLDatetime; - + return $self->_addRecord ('fs', %fs); } # AddFS sub TrimFS ($$) { my ($self, $system, $filesystem) = @_; - + my %filesystem = $self->GetFilesystem ($system, $filesystem); - + return unless %filesystem; - + my %task = $self->GetTask ('scrub'); - + $self->Error ("Unable to find scrub task!", 1) unless %task; - + my $days; my $today = Today2SQLDatetime; - + # TODO: SubtractDays uses just an approximation (i.e. subtracting 30 days when # in February is not right. if ($filesystem{filesystemHist} =~ /(\d+) month/i) { @@ -789,44 +800,44 @@ sub TrimFS ($$) { } # if my $oldage = SubtractDays $today, $days; - + my ($dberr, $dbmsg) = $self->_deleteRecord ( 'fs', "system='$system' and filesystem='$filesystem' and timestamp<='$oldage'" ); - + if ($dbmsg eq 'Records deleted') { return (0, $dbmsg) if $dberr == 0; - + my %runlog; - + $runlog{task} = $task{name}; $runlog{started} = $today; $runlog{status} = 0; - $runlog{message} = + $runlog{message} = "Scrubbed $dberr fs records for filesystem $system:$filesystem"; - + my ($err, $msg) = $self->AddRunlog (%runlog); - + $self->Error ("Unable to add runlog - (Error: $err)\n$msg") if $err; } # if - + return ($dberr, $dbmsg); } # TrimFS sub TrimLoadavg ($) { my ($self, $system) = @_; - + my %system = $self->GetSystem ($system); - + return unless %system; - + my %task = $self->GetTask ('loadavg'); - + $self->Error ("Unable to find loadavg task!", 1) unless %task; - + my $days; my $today = Today2SQLDatetime; @@ -839,26 +850,26 @@ sub TrimLoadavg ($) { } # if my $oldage = SubtractDays $today, $days; - + my ($dberr, $dbmsg) = $self->_deleteRecord ( 'loadavg', "system='$system' and timestamp<='$oldage'" ); - + if ($dbmsg eq 'Records deleted') { return (0, $dbmsg) if $dberr == 0; - + my %runlog; - + $runlog{task} = $task{name}; $runlog{started} = $today; $runlog{status} = 0; - $runlog{message} = + $runlog{message} = "Scrubbed $dberr loadavg records for system $system"; my ($err, $msg) = $self->AddRunlog (%runlog); - + $self->Error ("Unable to add runload (Error: $err)\n$msg") if $err; } # if @@ -867,17 +878,17 @@ sub TrimLoadavg ($) { sub GetFS ($$;$$$$) { my ($self, $system, $filesystem, $start, $end, $count, $interval) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + return unless $filesystem; - + $interval ||= 'Minute'; - + my $size = $interval =~ /month/i ? 7 : $interval =~ /day/i @@ -885,16 +896,16 @@ sub GetFS ($$;$$$$) { : $interval =~ /hour/i ? 13 : 16; - + undef $start if $start and $start =~ /earliest/i; undef $end if $end and $end =~ /latest/i; - + my $condition = "system='$system' and filesystem='$filesystem'"; $condition .= " and timestamp>='$start'" if $start; $condition .= " and timestamp<='$end'" if $end; - + $condition .= " group by left(timestamp,$size)"; - + if ($count) { # We can't simply do a "limit 0, $count" as that just gets the front end of # the records return (i.e. if $count = say 10 and the timestamp range @@ -903,14 +914,14 @@ sub GetFS ($$;$$$$) { # $count my $nbrRecs = $self->Count ('fs', $condition); my $offset = $nbrRecs - $count; - + # Offsets of < 0 are not allowed. $offset = 0 if $offset < 0; $condition .= " limit $offset, $count"; } # if - + my $statement = <<"END"; select system, @@ -927,49 +938,49 @@ from END my ($err, $msg); - + my $sth = $self->{db}->prepare ($statement); - + unless ($sth) { ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + croak $msg; } # if - + my $status = $sth->execute; - + unless ($status) { ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); - + croak $msg; } # if - + my @records; - + while (my $row = $sth->fetchrow_hashref) { push @records, $row; } # while - + return @records; } # GetFS sub GetLatestFS ($$) { my ($self, $system, $filesystem) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + return unless $filesystem; - + my @records = $self->_getRecords ( 'fs', "system='$system' and filesystem='$filesystem'" . " order by timestamp desc limit 0, 1", ); - + if ($records[0]) { return %{$records[0]}; } else { @@ -979,32 +990,32 @@ sub GetLatestFS ($$) { sub AddLoadavg () { my ($self, %loadavg) = @_; - + my @requiredFields = ( 'system', ); my $result = _checkRequiredFields \@requiredFields, \%loadavg; - + return -1, "AddLoadavg: $result" if $result; - + # Timestamp record $loadavg{timestamp} = Today2SQLDatetime; - + return $self->_addRecord ('loadavg', %loadavg); } # AddLoadavg sub GetLoadavg ($;$$$$) { my ($self, $system, $start, $end, $count, $interval) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + $interval ||= 'Minute'; - + my $size = $interval =~ /month/i ? 7 : $interval =~ /day/i @@ -1012,16 +1023,16 @@ sub GetLoadavg ($;$$$$) { : $interval =~ /hour/i ? 13 : 16; - + my $condition; - + undef $start if $start and $start =~ /earliest/i; undef $end if $end and $end =~ /latest/i; - + $condition .= " system='$system'" if $system; $condition .= " and timestamp>='$start'" if $start; $condition .= " and timestamp<='$end'" if $end; - + $condition .= " group by left(timestamp,$size)"; if ($count) { @@ -1032,14 +1043,14 @@ sub GetLoadavg ($;$$$$) { # $count my $nbrRecs = $self->Count ('loadavg', $condition); my $offset = $nbrRecs - $count; - + # Offsets of < 0 are not allowed. $offset = 0 if $offset < 0; $condition .= " limit $offset, $count"; } # if - + my $statement = <<"END"; select system, @@ -1053,46 +1064,46 @@ from END my ($err, $msg); - + my $sth = $self->{db}->prepare ($statement); - + unless ($sth) { ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + croak $msg; } # if - + my $status = $sth->execute; - + unless ($status) { ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); - + croak $msg; } # if - + my @records; - + while (my $row = $sth->fetchrow_hashref) { push @records, $row; } # while - + return @records; } # GetLoadvg sub GetLatestLoadavg ($) { my ($self, $system) = @_; - + $system = $self->_aliasSystem ($system); - + return unless $system; - + my @records = $self->_getRecords ( 'loadavg', "system='$system'" . " order by timestamp desc limit 0, 1", ); - + if ($records[0]) { return %{$records[0]}; } else { @@ -1102,123 +1113,123 @@ sub GetLatestLoadavg ($) { sub AddTask (%) { my ($self, %task) = @_; - + my @requiredFields = ( 'name', 'command' ); - + my $result = _checkRequiredFields \@requiredFields, \%task; - + return -1, "AddTask: $result" if $result; - - return $self->_addRecord ('task', %task); + + return $self->_addRecord ('task', %task); } # AddTask sub DeleteTask ($) { my ($self, $name) = @_; - + return $self->_deleteRecord ('task', "name='$name'"); } # DeleteTask sub FindTask ($) { my ($self, $name) = @_; - + $name ||= ''; - + my $condition = "name like '%$name%'"; - + return $self->_getRecords ('task', $condition); } # FindTask sub GetTask ($) { my ($self, $name) = @_; - + return unless $name; - + my @records = $self->_getRecords ('task', "name='$name'"); if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetTask sub UpdateTask ($%) { my ($self, $name, %update) = @_; - + return $self->_updateRecord ('task', "name='$name'", %update); } # Update sub AddSchedule (%) { my ($self, %schedule) = @_; - + my @requiredFields = ( 'task', ); - + my $result = _checkRequiredFields \@requiredFields, \%schedule; - + return -1, "AddSchedule: $result" if $result; - - return $self->_addRecord ('schedule', %schedule); + + return $self->_addRecord ('schedule', %schedule); } # AddSchedule sub DeleteSchedule ($) { my ($self, $name) = @_; - + return $self->_deleteRecord ('schedule', "name='$name'"); } # DeleteSchedule sub FindSchedule (;$$) { my ($self, $name, $task) = @_; - + $name ||= ''; $task||= ''; - + my $condition = "name like '%$name%'"; $condition .= ' and '; $condition .= "task like '%$task%'"; - return $self->_getRecords ('schedule', $condition); + return $self->_getRecords ('schedule', $condition); } # FindSchedule sub GetSchedule ($) { my ($self, $name) = @_; - + my @records = $self->_getRecords ('schedule', "name='$name'"); - + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetSchedule sub UpdateSchedule ($%) { my ($self, $name, %update) = @_; - + return $self->_updateRecord ('schedule', "name='$name'", %update); } # UpdateSchedule sub AddRunlog (%) { my ($self, %runlog) = @_; - + my @requiredFields = ( 'task', ); - + my $result = _checkRequiredFields \@requiredFields, \%runlog; - + return -1, "AddRunlog: $result" if $result; - + $runlog{ended} = Today2SQLDatetime; - + my ($err, $msg) = $self->_addRecord ('runlog', %runlog); return ($err, $msg, $self->_getLastID); @@ -1226,29 +1237,29 @@ sub AddRunlog (%) { sub DeleteRunlog ($) { my ($self, $condition) = @_; - + return $self->_deleteRecord ('runlog', $condition); } # DeleteRunlog sub FindRunlog (;$$$$$$) { my ($self, $task, $system, $status, $id, $start, $page) = @_; - + $task ||= ''; - + # If ID is specified then that's all that really matters as it uniquely # identifies a runlog entry; my $condition; - + unless ($id) { $condition = "task like '%$task%'"; - + if ($system) { $condition .= " and system like '%$system%'" unless $system eq 'All'; } else { $condition .= ' and system is null'; } # unless - + if (defined $status) { if ($status =~ /!(-*\d+)/) { $condition .= " and status<>$1"; @@ -1256,9 +1267,9 @@ sub FindRunlog (;$$$$$$) { $condition .= " and status=$status" } # if } # if - - $condition .= " order by started desc"; - + + $condition .= " order by started desc"; + if (defined $start) { $page ||= 10; $condition .= " limit $start, $page"; @@ -1266,60 +1277,60 @@ sub FindRunlog (;$$$$$$) { } else { $condition = "id=$id"; } # unless - + return $self->_getRecords ('runlog', $condition); } # FindRunlog sub GetRunlog ($) { my ($self, $id) = @_; - + return unless $id; - + my @records = $self->_getRecords ('runlog', "id=$id"); - + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetRunlog sub UpdateRunlog ($%) { my ($self, $id, %update) = @_; - + return $self->_updateRecord ('runlog', "id=$id", %update); } # UpdateRunlog sub Count ($;$) { my ($self, $table, $condition) = @_; - + $condition = $condition ? 'where ' . $condition : ''; - + my ($err, $msg); - + my $statement = "select count(*) from $table $condition"; - + my $sth = $self->{db}->prepare ($statement); - + unless ($sth) { ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + croak $msg; } # if - + my $status = $sth->execute; - + unless ($status) { ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); - + croak $msg; } # if - + # Hack! Statements such as the following: # # select count(*) from fs where system='jupiter' and filesystem='/dev/sdb5' - # > group by left(timestamp,10); + # > group by left(timestamp,10); # +----------+ # | count(*) | # +----------+ @@ -1332,7 +1343,7 @@ sub Count ($;$) { # | 190 | # +----------+ # 7 rows in set (0.00 sec) - # + # # Here we want 7 but what we see in $records[0] is 49. So the hack is that if # statement contains "group by" then we assume we have the above and return # scalar @records, otherwise we return $records[0]; @@ -1354,9 +1365,9 @@ sub Count ($;$) { # us again. sub GetWork () { my ($self) = @_; - + my ($err, $msg); - + my $statement = <<"END"; select schedule.name as schedulename, @@ -1374,43 +1385,43 @@ where and schedule.active='true' order by lastrun END - + my $sth = $self->{db}->prepare ($statement); - + unless ($sth) { ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + croak $msg; } # if - + my $status = $sth->execute; - + unless ($status) { ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); - + croak $msg; } # if - - my $sleep; + + my $sleep; my @records; - + while (my $row = $sth->fetchrow_hashref) { if ($$row{system} !~ /localhost/i) { my %system = $self->GetSystem ($$row{system}); - + # Skip inactive systems next if $system{active} eq 'false'; } # if - + # If started is not defined then this task was never run so run it now. unless ($$row{lastrun}) { push @records, $row; next; } # unless - + # TODO: Handle frequencies better. my $seconds; - + if ($$row{frequency} =~ /(\d+) seconds/i) { $seconds = $1; } elsif ($$row{frequency} =~ /(\d+) minute/i) { @@ -1423,23 +1434,23 @@ END warning "Don't know how to handle frequencies like $$row{frequency}"; next; } # if - + my $today = Today2SQLDatetime; my $lastrun = Add ($$row{lastrun}, (seconds => $seconds)); my $waitTime = DateToEpoch ($lastrun) - DateToEpoch ($today); - + if ($waitTime < 0) { # We're late - push this onto records and move on push @records, $row; } # if - + $sleep ||= $waitTime; - + if ($sleep > $waitTime) { $sleep = $waitTime; } # if } # while - + # Even if there is nothing to do the caller should sleep a bit and come back # to us. So if it ends up there's nothing past due, and nothing upcoming, then # sleep for a minute and return here. Somebody may have added a new task next @@ -1447,91 +1458,91 @@ END if (@records == 0 and not $sleep) { $sleep = 60; } # if - - return ($sleep, @records); + + return ($sleep, @records); } # GetWork sub GetUniqueList ($$) { my ($self, $table, $field) = @_; - + my ($err, $msg); - + my $statement = "select $field from $table group by $field"; - + my $sth = $self->{db}->prepare ($statement); - + unless ($sth) { ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); - + croak $msg; } # if - + my $status = $sth->execute; - + unless ($status) { ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); - + croak $msg; } # if my @values; - + while (my @row = $sth->fetchrow_array) { if ($row[0]) { push @values, $row[0]; } else { push @values, ''; } # if - } # foreach + } # for return @values; } # GetUniqueList sub AddAlert(%) { my ($self, %alert) = @_; - + my @requiredFields = ( 'name', 'type', ); - + my $result = _checkRequiredFields \@requiredFields, \%alert; - + return -1, "AddAlert: $result" if $result; - - return $self->_addRecord ('alert', %alert); + + return $self->_addRecord ('alert', %alert); } # AddAlert sub DeleteAlert ($) { my ($self, $name) = @_; - + return $self->_deleteRecord ('alert', "name='$name'"); } # DeleteAlert sub FindAlert (;$) { my ($self, $alert) = @_; - + $alert ||= ''; - + my $condition = "name like '%$alert%'"; - - return $self->_getRecords ('alert', $condition); + + return $self->_getRecords ('alert', $condition); } # FindAlert sub GetAlert ($) { my ($self, $name) = @_; - + return unless $name; - + my @records = $self->_getRecords ('alert', "name='$name'"); - + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetAlert sub SendAlert ($$$$$$$) { @@ -1545,25 +1556,25 @@ 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); - + if ($alert{type} eq 'email') { my $from = 'Clearadm@' . hostdomain; - + mail ( from => $from, to => $to, subject => "Clearadm Alert: $system: $subject", mode => 'html', - data => $message, - footing => $footing, + data => $message, + footing => $footing, ); } else { $self->Error ("Don't know how to send $alert{type} alerts\n" @@ -1578,40 +1589,40 @@ sub SendAlert ($$$$$$$) { notification => $notification, runlog => $runlogID, timestamp => Today2SQLDatetime, - message => $subject, - ); - + message => $subject, + ); + return $self->AddAlertlog (%alertlog); } # SendAlert sub GetLastAlert ($$) { my ($self, $notification, $system) = @_; - + my $statement = <<"END"; select runlog, timestamp -from +from alertlog where notification='$notification' and system='$system' order by timestamp desc -limit +limit 0, 1 END - + my $sth = $self->{db}->prepare ($statement) or return $self->_dberror ('Unable to prepare statement', $statement); - + $sth->execute or return $self->_dberror ('Unable to execute statement', $statement); - + my $alertlog= $sth->fetchrow_hashref; - + $sth->finish; - + if ($alertlog) { return %$alertlog; } else { @@ -1621,38 +1632,38 @@ END sub GetLastTaskFailure ($$) { my ($self, $task, $system) = @_; - + my $statement = <<"END"; select id, ended -from +from runlog where - status <> 0 + status <> 0 and task='$task' and system='$system' and alerted='true' order by ended desc -limit +limit 0, 1 END - + my $sth = $self->{db}->prepare ($statement) or return $self->_dberror ('Unable to prepare statement', $statement); - + $sth->execute or return $self->_dberror ('Unable to execute statement', $statement); - + my $runlog= $sth->fetchrow_hashref; - + $sth->finish; - + if ($$runlog{ended}) { return %$runlog; } # if - + # If we didn't get any ended in the last call then there's nothing that # qualified. Still let's return a record (%runlog) that has a valid id so # that the caller can update that runlog with alerted = 'true'. @@ -1665,7 +1676,7 @@ where status <> 0 and task='$task' and system='$system' -order by +order by ended desc limit 0, 1 @@ -1673,20 +1684,20 @@ END $sth = $self->{db}->prepare ($statement) or return $self->_dberror ('Unable to prepare statement', $statement); - + $sth->execute or return $self->_dberror ('Unable to execute statement', $statement); - + $runlog = $sth->fetchrow_hashref; - + $sth->finish; - + if ($runlog) { return %$runlog; } else { return } # if -} # GetLastTaskFailure +} # GetLastTaskFailure sub Notify ($$$$$$) { my ( @@ -1702,9 +1713,9 @@ sub Notify ($$$$$$) { $runlogID = $self->_getLastID unless $runlogID; - + my ($err, $msg); - + # Update filesystem, if $filesystem was specified if ($filesystem) { ($err, $msg) = $self->UpdateFilesystem ( @@ -1713,26 +1724,26 @@ sub Notify ($$$$$$) { notification => $notification, ), ); - + $self->Error ("Unable to set notification for filesystem $system:$filesystem " . "(Status: $err)\n$msg", $err) if $err; } # if - + # Update system ($err, $msg) = $self->UpdateSystem ( $system, ( notification => $notification, ), ); - + my %notification = $self->GetNotification ($notification); - + my %lastnotified = $self->GetLastAlert ($notification, $system); - + if (%lastnotified and $lastnotified{timestamp}) { my $today = Today2SQLDatetime; my $lastnotified = $lastnotified{timestamp}; - + if ($notification{nomorethan} =~ /hour/i) { $lastnotified = Add ($lastnotified, (hours => 1)); } elsif ($notification{nomorethan} =~ /day/i) { @@ -1742,13 +1753,13 @@ sub Notify ($$$$$$) { } elsif ($notification{nomorethan} =~ /month/i) { $lastnotified = Add ($lastnotified, (month => 1)); } # if - + # If you want to fake an alert in the debugger just change $diff accordingly my $diff = Compare ($today, $lastnotified); - + return if $diff <= 0; - } # if + } # if my $when = Today2SQLDatetime; my $nomorethan = lc $notification{nomorethan}; @@ -1760,7 +1771,7 @@ sub Notify ($$$$$$) { unless ($to) { if ($system) { my %system = $self->GetSystem ($system); - + $to = $system{email}; } else { # If we don't know what system this error occurred on we'll have to notify @@ -1769,13 +1780,13 @@ 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 ( $notification{alert}, $system, @@ -1785,7 +1796,7 @@ sub Notify ($$$$$$) { $to, $runlogID, ); - + $self->Error ("Unable to send alert (Status: $err)\n$msg", $err) if $err; verbose "Sent alert to $to"; @@ -1796,44 +1807,44 @@ sub Notify ($$$$$$) { alerted => 'true', ), ); - + $self->Error ("Unable to update runlog (Status: $err)\n$msg", $err) if $err; - return; + return; } # Notify sub ClearNotifications ($$;$) { my ($self, $system, $filesystem) = @_; - + my ($err, $msg); - + if ($filesystem) { ($err, $msg) = $self->UpdateFilesystem ( $system, $filesystem, (notification => undef), ); - + error "Unable to clear notification for filesystem $system:$filesystem " . "(Status: $err)\n$msg", $err if $err; - + # Check to see any of this system's filesystems have notifications. If none - # then it's save to say we've turned off the last notification for a + # then it's save to say we've turned off the last notification for a # filesystem involved with this system and if $system{notification} was # 'Filesystem' then we can toggle off the notification on the system too my $filesystemsAlerted = 0; - - foreach ($self->FindFilesystem ($system)) { - $filesystemsAlerted++ + + for ($self->FindFilesystem ($system)) { + $filesystemsAlerted++ if $$_{notification}; - } # foreach - + } # for + my %system = $self->GetSystem ($system); - + return unless $system; - - if ($system{notification} and + + if ($system{notification} and $system{notification} eq 'Filesystem' and $filesystemsAlerted == 0) { ($err, $msg) = $self->UpdateSystem ($system, (notification => undef)); @@ -1843,11 +1854,11 @@ sub ClearNotifications ($$;$) { } # if } else { ($err, $msg) = $self->UpdateSystem ($system, (notification => undef)); - + $self->Error ("Unable to clear notification for system $system " . "(Status: $err)\n$msg", $err) if $err; } # if - + return; } # ClearNotifications @@ -1856,20 +1867,20 @@ sub SystemAlive (%) { # If we've never heard from this system then we will assume that the system # has not been set up to run clearagent and has never checked in. In any event - # we cannot say the system died because we've never known it to be alive! + # we cannot say the system died because we've never known it to be alive! return 1 unless $system{lastheardfrom}; - + # If a system is not active (may have been temporarily been deactivated) then # we don't want to turn on the bells and whistles alerting people it's down. return 1 if $system{active} eq 'false'; - + my $today = Today2SQLDatetime; my $lastheardfrom = $system{lastheardfrom}; - + my $tenMinutes = 10 * 60; - + $lastheardfrom = Add ($lastheardfrom, (seconds => $tenMinutes)); if (DateToEpoch ($lastheardfrom) < DateToEpoch ($today)) { @@ -1878,7 +1889,7 @@ sub SystemAlive (%) { notification => 'Heartbeat' ), ); - + return; } else { if ($system{notification}) { @@ -1894,7 +1905,7 @@ sub SystemAlive (%) { sub UpdateAlert ($%) { my ($self, $name, %update) = @_; - + return $self->_updateRecord ( 'alert', "name='$name'", @@ -1904,29 +1915,29 @@ sub UpdateAlert ($%) { sub AddAlertlog (%) { my ($self, %alertlog) = @_; - + my @requiredFields = ( 'alert', 'notification', ); - + my $result = _checkRequiredFields \@requiredFields, \%alertlog; - + return -1, "AddAlertlog: $result" if $result; - + # Timestamp record $alertlog{timestamp} = Today2SQLDatetime; - - return $self->_addRecord ('alertlog', %alertlog); + + return $self->_addRecord ('alertlog', %alertlog); } # AddAlertlog sub DeleteAlertlog ($) { my ($self, $condition) = @_; - + return unless $condition; - + if ($condition =~ /all/i) { return $self->_deleteRecord ('alertlog'); } else { @@ -1936,18 +1947,18 @@ sub DeleteAlertlog ($) { sub FindAlertlog (;$$$$$) { my ($self, $alert, $system, $notification, $start, $page) = @_; - + $alert ||= ''; $system ||= ''; $notification ||= ''; - + my $condition = "alert like '%$alert%'"; $condition .= ' and '; $condition .= "system like '%$system%'"; $condition .= ' and '; $condition .= "notification like '%$notification%'"; $condition .= " order by timestamp desc"; - + if (defined $start) { $page ||= 10; $condition .= " limit $start, $page"; @@ -1958,22 +1969,22 @@ sub FindAlertlog (;$$$$$) { sub GetAlertlog ($) { my ($self, $alert) = @_; - + return unless $alert; - + my @records = $self->_getRecords ('alertlog', "alert='$alert'"); - + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetAlertlog sub UpdateAlertlog ($%) { my ($self, $alert, %update) = @_; - + return $self->_updateRecord ( 'alertlog', "alert='$alert'", @@ -1983,57 +1994,57 @@ sub UpdateAlertlog ($%) { sub AddNotification (%) { my ($self, %notification) = @_; - + my @requiredFields = ( 'name', 'alert', 'cond' ); - + my $result = _checkRequiredFields \@requiredFields, \%notification; - + return -1, "AddNotification: $result" if $result; - - return $self->_addRecord ('notification', %notification); + + return $self->_addRecord ('notification', %notification); } # AddNotification sub DeleteNotification ($) { my ($self, $name) = @_; - + return $self->_deleteRecord ('notification', "name='$name'"); } # DeletePackage sub FindNotification (;$$) { my ($self, $name, $cond, $ordering) = @_; - + $name ||= ''; - + my $condition = "name like '%$name%'"; $condition .= " and $cond" if $cond; - - return $self->_getRecords ('notification', $condition); + + return $self->_getRecords ('notification', $condition); } # FindNotification sub GetNotification ($) { my ($self, $name) = @_; - + return unless $name; - + my @records = $self->_getRecords ('notification', "name='$name'"); - + if ($records[0]) { return %{$records[0]}; } else { return; - } # if + } # if } # GetNotification sub UpdateNotification ($%) { my ($self, $name, %update) = @_; - + return $self->_updateRecord ( 'notification', "name='$name'", @@ -2067,7 +2078,7 @@ L =head2 ClearSCM Perl Modules -=begin man +=begin man DateUtils Display