AFS-Command

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

output when it is collected into the $vos->errors().  This is useful
for profiling the performance of operations such as vos release:

    my $result = $vos->release
      (
       id		=> 'somevol',
       cell		=> 'somecell',
      ) || die $vos->errors();

When this works, the $vos->errors() will have the verbose output,
which can be logged even in the successful case, for diagnostics.
Here's an example for a failure:

    [2004-11-18 17:20:36] Could not lock the VLDB entry for the volume 536998569.
    [2004-11-18 17:20:36] VLDB: no permission access for call
    [2004-11-18 17:20:36] Error in vos release command.
    [2004-11-18 17:20:36] VLDB: no permission access for call

=head1 Changes in 1.8

=head1 Bug Fixes

Changes.html  view on Meta::CPAN

<PRE>    my $result = $vos-&gt;release
      (
       id               =&gt; 'somevol',
       cell             =&gt; 'somecell',
      ) || die $vos-&gt;errors();
</PRE>

<P>

When this works, the $vos-&gt;errors() will have the verbose output, which
can be logged even in the successful case, for diagnostics. Here's an
example for a failure:


<P>

<PRE>    [2004-11-18 17:20:36] Could not lock the VLDB entry for the volume 536998569.
    [2004-11-18 17:20:36] VLDB: no permission access for call
    [2004-11-18 17:20:36] Error in vos release command.
    [2004-11-18 17:20:36] VLDB: no permission access for call
</PRE>

lib/AFS/Command/BOS.pm  view on Meta::CPAN

    }

    $errors++ unless $self->_reap_cmds();
    $errors++ unless $self->_restore_stderr();

    return if $errors;
    return $result;

}

sub getlog {

    my $self = shift;
    my (%args) = @_;

    my $result = AFS::Object::BosServer->new();

    $self->{operation} = "getlog";

    my $redirect = undef;
    my $redirectname = undef;

    if ( $args{redirect} ) {
	$redirectname = delete $args{redirect};
	$redirect = IO::File->new(">$redirectname") || do {
	    $self->_Carp("Unable to write to $redirectname: $ERRNO");
	    return;
	};
    }

    return unless $self->_parse_arguments(%args);

    return unless $self->_save_stderr();

    my $errors = 0;

    $errors++ unless $self->_exec_cmds();

    my $log = "";

    while ( defined($_ = $self->{handle}->getline()) ) {
	next if /^Fetching log file/;
	if ( $redirect ) {
	    $redirect->print($_);
	} else {
	    $log .= $_;
	}
    }

    if ( $redirect ) {
	$redirect->close()|| do {
	    $self->_Carp("Unable to close $redirectname: $ERRNO");
	    $errors++
	};
	$result->_setAttribute( log => $redirectname );
    } else {
	$result->_setAttribute( log => $log );
    }

    $errors++ unless $self->_reap_cmds();
    $errors++ unless $self->_restore_stderr();

    return if $errors;
    return $result;

}

lib/AFS/Command/BOS.pod  view on Meta::CPAN

The following attributes may be present, if there are .BAK or .OLD
versions of the file.

    Attributes			Values
    ----------			------
    bak				last modified timestamp on the .BAK file
    old				last modified timestamp on the .OLD file

=back

=head2 getlog

=over

=item Arguments

The bos help string is:

    bos getlog: examine log file
    Usage: bos getlog -server <machine name> -file <log file to examine>
		      [-cell <cell name>] [-noauth] [-localauth]

The corresponding method invocation looks like:

    my $result = $bos->getlog
      (
       # Required arguments
       server			=> $server,
       file			=> $file,
       # Optional arguments
       cell			=> $cell,
       noauth			=> 1,
       localauth		=> 1,
       # Enhanced arguments
       redirect			=> $redirect,
      );

The 'redirect' argument is the name of a file to "redirect" the log
file to.  By default, 'bos getlog' dumps the contents of the requested
file to stdout, which is not what you normally want in an application.
The value of this argument is passed directly to IO::File->open().

If this argument is not specified, then the contents of the logfile
are stashed in an attribute of the returned object.

=item Return Values

This method returns an AFS::Object::BosServer object, which
contains one attribute.

    my $result = $bos->getlog
      (
       server			=> $server,
       file			=> "/usr/afs/logs/VolserLog",
       redirect			=> "/var/tmp/VolserLog.$$",
      ) || die $bos->errors();

    my $logfile = IO::File->new("</var/tmp/VolserLog.$$") ||
      die "Unable to open logfile: $ERRNO\n";

    while ( defined($_ = $logfile->getline()) ) {
	....
    }

    # Alternately, the memory pig way:

    my $result = $bos->getlog
      (
       server			=> $server,
       file			=> "/usr/afs/logs/VolserLog",
      );

    foreach ( split(/\n+/,$result->log()) ) {
	....
    }

The object has the following attribute:

B<AFS::Object::BosServer>

    Attributes			Values
    ----------			------
    log				Contents of the logfile, or the redirect pathname

If redirect was given, then this attribute is simply same pathname.
If redirect was not given, then the value of this attribute is the
contents of the requested logfile, as a single (potentially huge)
string.

NOTE: Since this method is usually invoked to retrieve one of the AFS
logfiles, which can be enormous on heavily loaded servers that have
not been restarted in a while, use of the redirect option is strongly
encouraged.  If not used, the memory allocated to store the logfile
may be prohibitively large.  Developer beware.

=back

=head2 getrestart

=over

=item Arguments

lib/AFS/Command/BOS.pod  view on Meta::CPAN

       localauth		=> 1,
      );

=head2 salvage

The bos help string is:

    bos salvage: salvage partition or volumes
    Usage: bos salvage -server <machine name> [-partition <salvage partition>]
		       [-volume <salvage volume number or volume name>]
		       [-file <salvage log output file>] [-all] [-showlog]
		       [-parallel <# of max parallel partition salvaging>]
		       [-tmpdir <directory to place tmp files>]
		       [-orphans <ignore | remove | attach>] [-debug] [-nowrite]
		       [-force] [-oktozap] [-rootfiles] [-salvagedirs] [-blockreads]
		       [-ListResidencies] [-SalvageRemote] [-SalvageArchival]
		       [-IgnoreCheck] [-ForceOnLine] [-UseRootDirACL]
		       [-TraceBadLinkCounts] [-DontAskFS] [-LogLevel <(MR-AFS) log level>]
		       [-rxdebug] [-cell <cell name>] [-noauth] [-localauth]
    Where: -all                 salvage whole server
	   -showlog             display salvage log
	   -debug               (MR-AFS) Run in Debugging mode
	   -nowrite             (MR-AFS) Run readonly/test mode
	   -force               (MR-AFS) Force full salvaging
	   -oktozap             (MR-AFS) Give permission to destroy bogus file residencies/volumes - debugging flag
	   -rootfiles           (MR-AFS) Show files owned by root - debugging flag
	   -salvagedirs         (MR-AFS) Force rebuild/salvage of all directories
	   -blockreads          (MR-AFS) Read smaller blocks to handle IO/bad blocks
	   -ListResidencies     (MR-AFS) Just list affected file residencies - debugging flag
	   -SalvageRemote       (MR-AFS) Salvage storage systems that are not directly attached
	   -SalvageArchival     (MR-AFS) Salvage HSM storage systems

lib/AFS/Command/BOS.pod  view on Meta::CPAN


    my $result = $bos->salvage
      (
       # Required arguments
       server			=> $server,
       # Optional arguments
       partition		=> $partition,
       volume			=> $volume,
       file			=> $file,
       all			=> 1,
       showlog			=> 1,
       parallel			=> $parallel,
       tmpdir			=> $tmpdir,
       orphans			=> $orphans,
       debug			=> 1,
       nowrite			=> 1,
       force			=> 1,
       oktozap			=> 1,
       rootfiles		=> 1,
       salvagedirs		=> 1,
       blockreads		=> 1,
       ListResidencies		=> 1,
       SalvageRemote		=> 1,
       SalvageArchival		=> 1,
       IgnoreCheck		=> 1,
       ForceOnLine		=> 1,
       UseRootDirACL		=> 1,
       TraceBadLinkCounts	=> 1,
       DontAskFS		=> 1,
       LogLevel			=> $loglevel,
       rxdebug			=> 1,
       cell			=> $cell,
       noauth			=> 1,
       localauth		=> 1,
      );

=head2 setauth

The bos help string is:

lib/AFS/Command/Base.pod  view on Meta::CPAN

The AFS::Command suite provides an programmatic API to several of the
key AFS command line utilities, namely: vos, bos, pts and fs.  This
module is <NOT> a replacement for the AFS::* modules, which are an XS
interface to the lower level AFS C programming APIs.

This module attempts to fill a huge void in the APIs available for
developing AFS systems management applications in perl.  Norbert
Gruener's AFS module implements wrapper classes for the various C
programming APIs available for AFS, however most of the systems
management for AFS is implemented in the command line utilities
themselves, not in any of the C libraries.  Far too much of the logic
in vos, by far the most important utility, is in the application
itself, not the underlying libraries.  This makes it very difficult
for an XS-only approach to support the vos functionality.

These classes take an entirely different approach, since they are
simply wrappers around the command line executables themselves, and
implemented entirely in pure perl (no XS code at all).  This has some
advantages and disadvantages, of course.  The primary advantage is
that we are not forced to re-implement the complex logic in the vos
command using the low level primitive C API calls.  The primary
disadvantage is that we are tightly coupled with the format of the
text output of each of these commands, but this is a problem space
that perl excels in.

This document covers general programming with the API, and the details
of the specific wrapper classes are documented separately
(eg. AFS::Command::VOS).

=head1 CLASS METHODS

lib/AFS/Command/Base.pod  view on Meta::CPAN


=head2 setCarp

This class method configures the carp and/or croak subroutines used
throughout the API.  By default, the obviously sensible thing is done:
the carp an croak subroutines exported by the Carp module are used.
These normally print output to stderr, and this method provides a
mechanism for trapping these errors and redirecting them elsewhere.

For example, stderr in a system daemon may be entirely ignored, and
syslog may be a more appropriate destination.  In this case, the
setCarp method may be used to configure this, globally, for the entire
API.

    AFS::Command->setCarp
      (

       carp => sub {
	   my ($lines) = @_;
	   foreach my $line ( split(/\n+/,$lines) ) {
	       syslog('warning',$line);
	   }
       },

       croak => sub {
	   my ($lines) = @_;
	   foreach my $line ( split(/\n+/,$lines) ) {
	       syslog('error',$line);
	   }
	   die $lines; # If we're dying, whine at stderr, too.
       },

      );

This method takes a list of key/value pairs, with only two supported
keys (anything else will be quietly ignored): carp an croak.  The
values are CODE references (anonymous subroutines, or references to
existing subroutines).  The carp CODE should not be fatal, however the

lib/AFS/Command/VOS.pod  view on Meta::CPAN


Note that the default behavior creates the condition where the
Creation time is newer than the LastUpdate time, and when this is
true, "vos examine" (or any command that display the timestamps in the
volume header, really) will show the Creation time as the LastUpdate
time, presumably because it would be confusing to show the volume as
having been updated before it was created.

Similar to 'vos dump', the 'file' argument is optional to 'vos
restore', but required in this API.  There are also three new
arguments: gunzip, bunzip2, and filterin.  The analogy with 'vos dump'
is by design entirely symmetrical.

=over

=item file

This argument specifies the file from which the vos restore input
should be read.  If the file ends in '.gz' or '.bz2', then gunzip or
bunzip2 will be used to uncompress the input before it is read by vos
restore.  This is accomplished using a pipe, so there is no

lib/AFS/Command/VOS.pod  view on Meta::CPAN

    -------			-------
    getVolumeNames()		list of volume names in the results
    getVolumeIds()		list of numeric volume IDs
    getVLDBEntry(name => $name)	the AFS::Object::VLDBEntry for name $name
    getVLDBEntry(id => $id)	the AFS::Object::VLDBEntry for id $id
    getVLDBEntries()		list of AFS::Object::VLDBEntry objects
    getVLDBEntryByName($name)   the AFS::Object::VLDBEntry for $name
    getVLDBEntryById($id)   	the AFS::Object::VLDBEntry for $id

NOTE: name to volume mappings are one to one, but id to volume
mappings are many to one, since a single logical VLDB entry can have
several IDs associated with it (RW, RO, BK, and/or RC).

B<AFS::Object::VLDBEntry>

This object also has a few attributes, and a few methods.  The 'name'
attribute is always present, but the others vary, depending on the
volume (again, see the 'examine' documentation for more verbosity).

    Attributes			Values
    ----------			------

t/10bos_basic.t  view on Meta::CPAN


} else {
    print "not ok $TestCounter\n";
    $TestCounter++;
    print "not ok $TestCounter\n";
    $TestCounter++;
    warn("Didn't find 'bosserver' in results from bos->getdate()");
}

#
# bos getlog
#
$result = $bos->getlog
  (
   server		=> $dbserver,
   cell			=> $cell,
   file			=> '/usr/afs/logs/BosLog',
  );
if ( ref $result && $result->isa("AFS::Object::BosServer") ) {
    print "ok $TestCounter\n";
    $TestCounter++;
} else {
    print "not ok $TestCounter..$TestTotal\n";
    die("Unable to getlog for bosserver:\n" . $bos->errors());
}

my $log = $result->log();
if ( $log ) {
    print "ok $TestCounter\n";
    $TestCounter++;
} else {
    print "not ok $TestCounter..$TestTotal\n";
    die("Unable to getlog for bosserver:\n" . $bos->errors());
}

my ($firstline) = split(/\n+/,$log);

my $tmpfile = "/var/tmp/.bos.getlog.results.$$";

$result = $bos->getlog
  (
   server		=> $dbserver,
   cell			=> $cell,
   file			=> '/usr/afs/logs/BosLog',
   redirect		=> $tmpfile,
  );
if ( ref $result && $result->isa("AFS::Object::BosServer") ) {
    print "ok $TestCounter\n";
    $TestCounter++;
} else {
    print "not ok $TestCounter..$TestTotal\n";
    die("Unable to getlog for bosserver:\n" . $bos->errors());
}

$log = $result->log();
if ( $log eq $tmpfile ) {
    print "ok $TestCounter\n";
    $TestCounter++;
} else {
    print "not ok $TestCounter..$TestTotal\n";
    die("Unable to getlog for bosserver:\n" . $bos->errors());
}

$file = IO::File->new($tmpfile) || do {
    print "not ok $TestCounter..$TestTotal\n";
    die "Unable to read $tmpfile: $ERRNO\n";
};

if ( $file->getline() eq "$firstline\n" ) {
    print "ok $TestCounter\n";
} else {
    print "not ok $TestCounter..$TestTotal\n";
    warn("Contents of bos->getlog() do not match when fetched\n" .
	 "with and without 'redirect' option\n");
}
$TestCounter++;

#
# bos getrestart
#
$result = $bos->getrestart
  (
   server		=> $dbserver,



( run in 0.853 second using v1.01-cache-2.11-cpan-49f99fa48dc )