Commit 62b31b3e authored by Leigh Stoller's avatar Leigh Stoller

Utility to show info about log files, clean up stale logfiles, and prune

ones we do not need anymore (reduce size of some big tables).
parent c72b3f85
......@@ -54,18 +54,45 @@ sub Lookup($$)
{
my ($class, $logid) = @_;
my $logfile;
my $query_result;
#
# Argument must be alphanumeric.
#
if ($logid =~ /^([\w]*)$/) {
if ($logid =~ /^([\d]*)$/) {
$query_result =
DBQueryWarn("select logid from logfiles where logidx='$logid'");
return undef
if (!$query_result || !$query_result->numrows);
if ($query_result->numrows > 1) {
print STDERR "*** More then one entry for $logid\n";
return undef;
}
($logid) = $query_result->fetchrow_array();
}
elsif ($logid =~ /^([\w]*)$/) {
$logid = $1;
}
elsif ($logid =~ /^\/[\w\/\.]*$/) {
$query_result =
DBQueryWarn("select logid from logfiles where filename='$logid'");
return undef
if (!$query_result || !$query_result->numrows);
if ($query_result->numrows > 1) {
print STDERR "*** More then one entry for $logid\n";
return undef;
}
($logid) = $query_result->fetchrow_array();
}
else {
return undef;
}
my $query_result =
$query_result =
DBQueryWarn("select * from logfiles where logid='$logid'");
return undef
......@@ -304,6 +331,21 @@ sub Close($)
return $self->Refresh();
}
#
# Clean up a logfile.
#
sub Clean($)
{
my ($self) = @_;
my $logid = $self->logid();
DBQueryWarn("update logfiles set isopen=0,filename=NULL ".
"where logid='$logid'")
or return -1;
return $self->Refresh();
}
#
# Is file empty?
#
......@@ -506,5 +548,27 @@ sub ReadFile($$)
return $cc;
}
#
# Lock and unlock the tables we use.
#
sub LockTables($)
{
my ($class) = @_;
DBQueryWarn("lock tables logfiles write, logfile_metadata write")
or return -1;
return 0;
}
sub UnlockTables($)
{
my ($class) = @_;
DBQueryWarn("unlock tables")
or return -1;
return 0;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
#!/usr/bin/perl -w
#
# Copyright (c) 2003-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;
use Date::Parse;
use Time::Local;
#
# Show some logfile table stuff.
#
sub usage()
{
print STDERR "Usage: logfile <logid | logidx | filename>";
print STDERR "Options:\n";
print STDERR " -d - Turn on debugging\n";
print STDERR " -o - List all open logfiles.\n";
print STDERR " -n - Impotent mode; just say what will happen.\n";
print STDERR " -C - Clean up (close/store) stale logfiles.\n";
print STDERR " -P - Prune some logs (sliverstatus,deletesliver).\n";
exit(-1);
}
my $optlist = "oCndP";
my $debug = 0;
my $impotent = 0;
my $open = 0;
my $clean = 0;
my $prune = 0;
# Protos
sub ShowOpen();
sub CleanOpenLogfiles(@);
sub ShowLogfiles(@);
sub PruneLogfiles();
sub fatal($);
#
# Configure variables
#
my $TB = "@prefix@";
my $SUDO = "/usr/local/bin/sudo";
my $FSTAT = "/usr/bin/fstat";
my $CHMOD = "/bin/chmod";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use emdb;
use emutil;
use Logfile;
use GeniHRN;
use Group;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/local/bin";
#
# Parse command arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{'h'})) {
usage();
}
if (defined($options{'d'})) {
$debug = 1;
}
if (defined($options{'n'})) {
$impotent = 1;
}
if (defined($options{'o'})) {
$open = 1;
}
if (defined($options{'C'})) {
$clean = 1;
}
if (defined($options{'P'})) {
$prune = 1;
}
if ($open) {
exit(ShowOpen());
}
elsif ($clean) {
exit(CleanOpenLogfiles(@ARGV));
}
elsif ($prune) {
exit(PruneLogfiles());
}
elsif (@ARGV) {
exit(ShowLogfiles(@ARGV));
}
exit(0);
#
# List all open files.
#
sub ShowOpen()
{
my $query_result =
DBQueryWarn("select logid from logfiles where isopen!=0 ".
"order by date_created desc");
while (my ($logid) = $query_result->fetchrow_array()) {
my $logfile = Logfile->Lookup($logid);
next
if (!defined($logfile));
next
if (! -e $logfile->filename());
my $filename = $logfile->filename();
print "$logid: $filename\n";
}
return 0;
}
#
# Clean up open logfiles.
#
sub CleanOpenLogfile($)
{
my ($logid) = @_;
Logfile->LockTables();
my $logfile = Logfile->Lookup($logid);
if (!defined($logfile)) {
Logfile->UnlockTables();
return 0;
}
# Closed before we locked.
if (! $logfile->isopen()) {
Logfile->UnlockTables();
return 0;
}
# Anything younger then 48 hours, leave for debugging.
my $created = str2time($logfile->date_created());
if (defined($created) && $created > (time() - (3600 * 48))) {
print "Skipping newish $logfile\n" if ($debug);
Logfile->UnlockTables();
return 0;
}
#
# No actual file, just mark it closed and clear the filename.
#
if (! -e $logfile->filename()) {
if ($impotent) {
print "Would clean $logfile - " .
$logfile->date_created() . "\n";
}
else {
$logfile->Clean();
}
Logfile->UnlockTables();
return 0;
}
my $filename = $logfile->filename();
my $fstat = emutil::ExecQuiet("$SUDO $FSTAT $filename");
if ($?) {
print $fstat;
Logfile->UnlockTables();
return 0;
}
my $skip = 0;
foreach my $line (split(/\n/, $fstat)) {
# Some kind of warning from fstat, skip to be safe.
if ($line =~ /^fstat:/) {
$skip = 1;
last;
}
# In use.
if ($line =~ /${filename}$/) {
print "$line\n" if ($debug);
$skip = 1;
last;
}
}
if ($skip) {
Logfile->UnlockTables();
return 0;
}
#
# Zero size file, just clean it up.
#
print "Stale: $logfile, " . $logfile->date_created() . ", $filename\n";
if (! -s $filename) {
if ($impotent) {
print "Would clean zero length logfile\n";
}
else {
$logfile->Clean();
}
}
else {
#
# Store it. Safest thing to do. But need to make sure we
# can read the file.
#
if ($impotent) {
print "Would close/store logfile\n";
}
else {
if (system("$SUDO $CHMOD 666 $filename") == 0) {
if ($logfile->Store() == 0) {
# We probably did not have access to delete original
# file, so do that with super powers
system("$SUDO /bin/rm -f $filename");
}
else {
print STDERR "*** Could not store $logfile\n";
}
}
}
}
Logfile->UnlockTables();
return 0;
}
sub CleanOpenLogfiles(@)
{
if (@_) {
my @logids = @_;
while (@logids) {
my $logid = pop(@logids);
CleanOpenLogfile($logid);
}
}
else {
my $query_result =
DBQueryWarn("select logid from logfiles where isopen!=0 ".
"order by date_created desc");
while (my ($logid) = $query_result->fetchrow_array()) {
CleanOpenLogfile($logid);
}
}
}
#
# Display one or more logfiles.
#
sub ShowLogfiles(@)
{
my @ids = @_;
while (@ids) {
my $id = pop(@ids);
my $logfile = Logfile->Lookup($id);
if (!defined($logfile)) {
print STDERR "No such logfile $id\n";
next;
}
my $group = Group->Lookup($logfile->gid_idx());
my $pid = $group->pid();
my $gid = $group->gid();
print "ID: " . $logfile->logid() . "\n";
print "IDX: " . $logfile->logidx() . "\n";
print "Created: " . $logfile->date_created() . "\n";
print "Filename: " . $logfile->filename() . "\n";
print "Open?: " . $logfile->isopen() . "\n";
print "Pid/Gid: " . "$pid/$gid" . "\n";
print "Stored?: " . $logfile->stored() . "\n";
print "Zipped?: " . $logfile->compressed() . "\n";
if ($logfile->Metadata()) {
print "Metadata:\n";
foreach my $el (@{$logfile->MetadataList()}) {
my ($key,$val) = @{$el};
print "$key => $val\n";
}
}
}
}
#
# Prune logfiles we do not care about; for now these are deletesliver
# logs where the slice was busy, and sliverstatus calls.
#
sub PruneLogfiles()
{
my $query_result =
DBQueryFatal("select m.logidx,l.logid from logfile_metadata as m ".
"left join logfiles as l on m.logidx=l.logidx ".
"where metakey='Method' and metaval='SliverStatus' and ".
" l.filename is null");
while (my ($logidx,$logid) = $query_result->fetchrow_array()) {
my $logfile = Logfile->Lookup($logid);
next
if (!defined($logfile));
if ($impotent) {
print "Would delete $logfile\n";
}
else {
$logfile->Delete();
}
}
$query_result =
DBQueryFatal("select m.logidx,l.logid from logfile_metadata as m ".
"left join logfiles as l on m.logidx=l.logidx ".
"where metakey='Method' and metaval='DeleteSliver' and ".
" l.filename is null");
while (my ($logidx,$logid) = $query_result->fetchrow_array()) {
my $logfile = Logfile->Lookup($logid);
next
if (!defined($logfile));
# Only kill busy and no such slice logs.
if (!exists($logfile->Metadata()->{"Error"}) ||
($logfile->Metadata()->{"Error"} ne "14" &&
$logfile->Metadata()->{"Error"} ne "12")) {
print "Skipping $logfile\n";
next
}
if ($impotent) {
print "Would delete $logfile\n";
}
else {
$logfile->Delete();
}
}
}
sub fatal($)
{
my ($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
#!/usr/bin/perl -w
#
# Copyright (c) 2003-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Date::Parse;
#
# Clear logfile/metadata for SliverStatus() calls.
#
sub usage()
{
print STDERR "Usage: prunelogfiles\n";
exit(-10);
}
my $optlist = "dn";
my $impotent = 0;
my $debug = 0;
# Protos
sub fatal($);
#
# Configure variables
#
my $TB = "@prefix@";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use emdb;
use Logfile;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"n"})) {
$impotent = 1;
}
#
# Grab the list of all SliverStatus calls and kill them.
#
my $query_result =
DBQueryFatal("select m.logidx,l.logid from logfile_metadata as m ".
"left join logfiles as l on m.logidx=l.logidx ".
"where metakey='Method' and metaval='SliverStatus' and ".
" l.filename is null");
while (my ($logidx,$logid) = $query_result->fetchrow_array()) {
my $logfile = Logfile->Lookup($logid);
next
if (!defined($logfile));
$logfile->Delete();
}
exit(0);
sub fatal($)
{
my ($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment