From: Mike Meffie Date: Thu, 24 Jan 2008 23:50:37 +0000 (+0000) Subject: DEVEL15-tests-update-20080124 X-Git-Tag: openafs-devel-1_5_31~68 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=bb3d12809ce35900c06de2beabb138a727c3fa18;p=packages%2Fo%2Fopenafs.git DEVEL15-tests-update-20080124 LICENSE IPL10 update test scripting (cherry picked from commit 80f7294490e1d1423a5f7482ed924dda8bab1ba8) --- diff --git a/src/tests/OpenAFS/Auth.pm b/src/tests/OpenAFS/Auth.pm new file mode 100644 index 000000000..252343381 --- /dev/null +++ b/src/tests/OpenAFS/Auth.pm @@ -0,0 +1,343 @@ +# This is -*- perl -*- + +package OpenAFS::Auth; +use strict; +use warnings; +use OpenAFS::Dirpath; +use OpenAFS::ConfigUtils; + +my $path = $OpenAFS::Dirpath::openafsdirpath; + +# +# Create an auth type for the specified Kerberos implementation. +# +# parameters: +# type -- Kerberos implementation: mit, heimdal, kaserver +# keytab -- path and name of the keytab file for mit and heimdal +# cell -- cell name. if not specified, attempts to find the +# cell name in the ThisCell configuration file. +# realm -- realm name. if not specified, assume the realm name +# is the same as the cell name, in uppercase. +# +# example: +# my $auth = OpenAFS::Auth::create( +# 'type'=>'mit', +# 'keytab'=>'/path/to/file/krb5.keytab'); +# +# $auth->authorize('admin'); +# +sub create { + my $self = { + # default values + 'type' => 'MIT', + 'keytab' => "$path->{'afsconfdir'}/krb5.keytab", + 'cell' => '', + 'realm' => '', + 'debug' => '0', + # user specified values + @_, + }; + + # check for supported kerberos type. + my $type = $self->{'type'}; + $self->{'type'} = _check_kerberos_type($type) or + die "Unsupported kerberos type: $type\n"; + + # create the sub-class for the kerberos type. + my $class = "OpenAFS::Auth::$self->{'type'}"; + $self = bless($self, $class); + + # attempt get default values. + unless ($self->{'cell'}) { + eval { + $self->{'cell'} = $self->_lookup_cell_name(); + } + } + unless ($self->{'realm'}) { + if ($self->{'cell'}) { + my $cell = $self->{'cell'}; + ($self->{'realm'} = $cell) =~ tr[a-z][A-Z]; + } + } + unless ($self->{'keytab'}) { + $self->{'keytab'} = "$path->{'afsconfdir'}/krb5.keytab"; + } + + # kerberos type specific sanity checks. + $self->_sanity_check(); + + if ($self->debug) { + print "debug: Auth::create()\n"; + foreach my $k (sort keys(%$self)) { + print "debug: $k => $self->{$k}\n"; + } + } + return $self; +} + +# +# Check for supported kerberos type, and allow for case insensitivity. +# +sub _check_kerberos_type { + my $type = shift; + foreach my $supported ('MIT', 'Heimdal', 'Kaserver') { + if ($type =~ /^$supported$/i) { + return $supported; + } + } + return undef; +} + +# +# Returns the cell name from the ThisCell configuration file. +# +sub _lookup_cell_name { + my $self = shift; + my $cell; + open(CELL, "$path->{'afsconfdir'}/ThisCell") + or die "error: Cannot open $path->{'afsconfdir'}/ThisCell: $!\n"; + $cell = ; + chomp $cell; + close CELL; + return $cell; +} + +# +# Placeholder for make_keyfile. Sub-classes should override. +# +sub make_keyfile { + my $self = shift; + return; +} + +# +# Make the krb.conf file if the realm name is different +# than the cell name. The syntax is something like, +# +# UMICH.EDU +# UMICH.EDU fear.ifs.umich.edu admin server +# UMICH.EDU surprise.ifs.umich.edu +# UMICH.EDU ruthless.ifs.umich.edu +# +sub make_krb_config { + my $self = shift; + my $cell = $self->{'cell'}; + my $realm = $self->{'realm'}; + + if ($realm && $realm ne $cell) { + unless ( -d $path->{'afsconfdir'} ) { + die "error: OpenAFS configuration directory '$path->{'afsconfdir'}' is missing.\n"; + } + unless ( -w $path->{'afsconfdir'} ) { + die "error: Write access to the configuration directory '$path->{'afsconfdir'}' is required.\n"; + } + print "debug: Making $path->{'afsconfdir'}/krb.conf file for realm $realm\n" if $self->{'debug'}; + open(KRB, "> $path->{'afsconfdir'}/krb.conf") or die "error: Failed to open $path->{'afsconfdir'}/krb.conf, $!\n"; + print KRB "$realm\n"; + close KRB; + } +} + +# +# Enable/disable debug messages. +# +sub debug { + my $self = shift; + if (@_) { + $self->{'debug'} = shift; + } + return $self->{'debug'}; +} + + +#------------------------------------------------------------------------------------ +# MIT Kerberos authorization commands. +# +package OpenAFS::Auth::MIT; +use strict; +use OpenAFS::Dirpath; +use OpenAFS::ConfigUtils; +our @ISA = ("OpenAFS::Auth"); + +# +# Sanity checks before we get started. +# +sub _sanity_check { + my $self = shift; + unless (defined $path->{'afssrvbindir'}) { + die "error: \$path->{'afssrvbindir'} is not defined.\n"; + } + unless (-f "$path->{'afssrvbindir'}/aklog") { + die "error: $path->{'afssrvbindir'}/aklog not found.\n"; + } + unless (-x "$path->{'afssrvbindir'}/aklog") { + die "error: $path->{'afssrvbindir'}/aklog not executable.\n"; + } + unless ($self->{'realm'}) { + die "error: Missing realm parameter Auth::create().\n"; + } + unless ($self->{'keytab'}) { + die "error: Missing keytab parameter Auth::create().\n"; + } + unless ( -f $self->{'keytab'} ) { + die "error: Kerberos keytab file not found: $self->{'keytab'}\n"; + } + unless ( -f $self->{'keytab'} ) { + die "error: Keytab file not found: $self->{'keytab'}\n"; + } +} + +# +# Create the KeyFile from the Kerberos keytab file. The keytab file +# should be created using the Kerberos kadmin command (or with the kadmin.local command +# as root on the KDC). See the OpenAFS asetkey man page for details. +# +sub make_keyfile { + my $self = shift; + + # asetkey annoyance. The current asetkey implementation requires the ThisCell and CellServDB files + # to be present but they really are not needed to create the KeyFile. This check is done here + # rather than in the _sanity_checks() because the ThisCell/CellServerDB are created later in + # the process of creating the new cell. + unless ( -f "$path->{'afsconfdir'}/ThisCell" ) { + die "error: OpenAFS configuration file is required, $path->{'afsconfdir'}/ThisCell\n"; + } + unless ( -f "$path->{'afsconfdir'}/CellServDB" ) { + die "error: OpenAFS configuration file is required, $path->{'afsconfdir'}/CellServDB\n"; + } + + unless ( -f "$path->{'afssrvbindir'}/asetkey" ) { + die "error: $path->{'afssrvbindir'}/asetkey is missing.\nWas OpenAFS built with Kerberos support?\n"; + } + unless ( -x "$path->{'afssrvbindir'}/asetkey" ) { + die "error: Do not have execute permissions on $path->{'afssrvbindir'}/asetkey\n"; + } + unless ( -d $path->{'afsconfdir'} ) { + die "error: OpenAFS configuration directory '$path->{'afsconfdir'}' is missing.\n"; + } + unless ( -w $path->{'afsconfdir'} ) { + die "error: Write access to the OpenAFS configuration directory '$path->{'afsconfdir'}' is required.\n"; + } + + + # Run klist to get the kvno of the afs key. Search for afs/cellname@REALM + # then afs@REALM. klist must be in the path. + my %keys = (); + my $kvno; + my $principal; + my $afs_kvno; + my $afs_principal; + if ($self->debug) { + print "debug: reading $self->{'keytab'} to find afs kvno\n"; + } + open(KLIST, "klist -k $self->{'keytab'} |") or die "make_keyfile: Failed to run klist."; + while () { + chomp; + next if /^Keytab/; # skip headers + next if /^KVNO/; + next if /^----/; + ($kvno, $principal) = split; + if ($self->debug) { + print "debug: kvno=$kvno principal=$principal\n"; + } + $keys{$principal} = $kvno; + } + close KLIST; + my $cell = $self->{'cell'}; + my $realm = $self->{'realm'}; + foreach my $principal ("afs/$cell\@$realm", "afs\@$realm") { + if ($self->debug) { + print "debug: searching for $principal\n"; + } + if (defined $keys{$principal}) { + $afs_principal = $principal; + $afs_kvno = $keys{$afs_principal}; + if ($self->debug) { + print "debug: found principal=$afs_principal kvno=$afs_kvno\n"; + } + last; + } + } + unless ($afs_kvno) { + die "error: Could not find an afs key matching 'afs/$cell\@$realm' or ". + "'afs/$cell' in keytab $self->{'keytab'}\n"; + } + + # Run asetkey on the keytab to create the KeyFile. asetkey must be in the PATH. + run("$path->{'afssrvbindir'}/asetkey add $afs_kvno $self->{'keytab'} $afs_principal"); +} + +# +# Get kerberos ticket and AFS token for the user. +# +sub authorize { + my $self = shift; + my $principal = shift || 'admin'; + my $opt_aklog = ""; + $opt_aklog .= " -d" if $self->debug; + + run("kinit -k -t $self->{'keytab'} $principal"); + run("$path->{'afssrvbindir'}/aklog $opt_aklog"); + run("$path->{'afssrvbindir'}/tokens"); +} + + +#------------------------------------------------------------------------------------ +package OpenAFS::Auth::Heimdal; +use strict; +use OpenAFS::Dirpath; +use OpenAFS::ConfigUtils; +our @ISA = ("OpenAFS::Auth"); + +# +# Various checks during initialization. +# +sub _sanity_check { + my $self = shift; + unless ($self->{'realm'}) { + die "Missing realm parameter Auth::create().\n"; + } + unless ($self->{'keytab'}) { + die "Missing keytab parameter Auth::create().\n"; + } + unless ( -f $self->{'keytab'} ) { + die "keytab file not found: $self->{'keytab'}\n"; + } +} + +# +# Get kerberos ticket and AFS token for the user. +# +sub authorize { + my $self = shift; + my $principal = shift || 'admin'; + run("kinit -k -t $self->{'keytab'} $principal\@$self->{'realm'} && afslog"); +} + +#------------------------------------------------------------------------------------ +package OpenAFS::Auth::Kaserver; +use strict; +use OpenAFS::Dirpath; +use OpenAFS::ConfigUtils; +our @ISA = ("OpenAFS::Auth"); + +# +# Various checks during initialization. +# +sub _sanity_check { + my $self = shift; + unless ($self->{'realm'}) { + die "Missing realm parameter Auth::create().\n"; + } +} + +# +# Get kerberos ticket and AFS token for the user. +# +sub authorize { + my $self = shift; + my $principal = shift || 'admin'; + run("echo \"Proceeding w/o authentication\"|klog -pipe ${principal}\@$self->{'realm'}"); +} + +1; diff --git a/src/tests/OpenAFS/OS.pm b/src/tests/OpenAFS/OS.pm new file mode 100644 index 000000000..d30afd03d --- /dev/null +++ b/src/tests/OpenAFS/OS.pm @@ -0,0 +1,312 @@ +# This is -*- perl -*- + +package OpenAFS::OS; +use warnings; +use strict; +use OpenAFS::Dirpath; +use OpenAFS::ConfigUtils; + +my $path = $OpenAFS::Dirpath::openafsdirpath; + +# +# Create the named system object for OS specific init scripts +# and commands. +# +sub create { + my $self = { + 'debug'=>0, + 'ostype'=>$path->{'ostype'}, + @_, + }; + + my $class = _get_class($self->{'ostype'}); + $self = bless($self, $class); + $self->{'commands'} = $self->get_commands(); + + # Put the paths to the cache and afsd into the path + # table. Assume legacy paths if the the viceetcdir is set to + # the Transarc path. + if ($path->{'viceetcdir'} eq '/usr/vice/etc') { + # set in the makefile dest targets + $path->{'cachedir'} = "/usr/vice" unless $path->{'cachedir'}; + $path->{'afsddir'} = "/usr/vice/etc" unless $path->{'afsddir'}; + } + else { + # set in the makefile install targets + $path->{'cachedir'} = "$path->{'localstatedir'}/openafs" unless $path->{'cachedir'}; + $path->{'afsddir'} = "$path->{'afssrvsbindir'}" unless $path->{'afsddir'}; + } + + return $self; +} + +# +# _get_class(name) - Return the package name for the ostype +# +sub _get_class { + my $type = shift; + if ($type=~/linux/i) { + return "OpenAFS::OS::Linux"; + } + die "error: Unknow system type. Valid types are: linux\n"; +} + +# +# command(name [,params...]) - Return the command string or code reference. +# +sub command { + my $self = shift; + my $name = shift; + my $cmd = $self->{'commands'}->{$name}; + unless (defined $cmd) { + die "error: Unsupported command name $name for OS type $self->{'ostype'}\n"; + } + # add parameters if present. + if (scalar @_) { + if (ref($cmd) eq 'CODE') { + $cmd = sub { &$cmd(@_) }; + } + else { + $cmd = join(' ', ($cmd, @_)); + } + } + return $cmd; +} + +#-------------------------------------------------------------- +# Common unix style os commands. +package OpenAFS::OS::Unix; +use warnings; +use strict; +use OpenAFS::ConfigUtils; +use OpenAFS::Dirpath; +our @ISA = qw(OpenAFS::OS); + +# +# remove(target) - recursive remove +# +sub remove { + my $self = shift; + my $target = shift; + run("rm -rf $target"); +} + +# +# Start the server. +# +sub fileserver_start { + my $self = shift; + run("$path->{'afssrvsbindir'}/bosserver"); +} + +# +# Stop the server. +# +sub fileserver_stop { + my $self = shift; + my @bosserver_pids = $self->find_pids("bosserver"); + if (scalar @bosserver_pids) { + # bosserver is running, try to shutdown with bos. + eval { + run("$path->{'afssrvbindir'}/bos shutdown localhost -localauth"); + }; + if ($@) { + warn "WARNING: Shutdown command failed.\n"; + } + # Now shutdown bosserver process itself. Kill all of them + # in case there are remants. + foreach my $pid (@bosserver_pids) { + eval { run("kill $pid") }; + } + } +} + +# +# Restart the server. +# +sub fileserver_restart { + my $self = shift; + fileserver_stop(); + fileserver_start(); +} + +# +# Return a list of pids. +# +sub find_pids { + my $self = shift; + my $process = shift; + my @pids = (); + my $ps = "ps -e -o pid,cmd"; + if ($self->{'debug'}) { + print("debug: searching for process $process\n"); + } + open(PS, "$ps |") or die "Cannot run command: $ps: $!"; + while () { + chomp; + my ($pid,$cmd) = split; + if ($cmd=~/$process/) { + if ($self->{'debug'}) { + print("debug: found $pid $cmd\n"); + } + push(@pids, $pid); + } + } + close PS; + return @pids; +} + +#-------------------------------------------------------------- +package OpenAFS::OS::Linux; +use warnings; +use strict; +use OpenAFS::ConfigUtils; +use OpenAFS::Dirpath; +our @ISA = qw(OpenAFS::OS::Unix); + +# +# OS-specific commands. Defer to init scripts where possible. +# +sub get_commands { + my $self = shift; + my $syscnf = "$path->{'initdir'}/testclient.conf"; + + my $commands = { + 'client-start' => "SYSCNF=$syscnf $path->{'initdir'}/afs.rc start", + 'client-stop' => "SYSCNF=$syscnf $path->{'initdir'}/afs.rc stop", + 'client-restart' => "SYSCNF=$syscnf $path->{'initdir'}/afs.rc restart", + 'client-forcestop' => sub { $self->client_forcestop() }, + 'fileserver-start' => sub { $self->fileserver_start() }, + 'fileserver-stop' => sub { $self->fileserver_stop() }, + 'fileserver-restart' => sub { $self->fileserver_restart() }, + 'remove' => 'rm -rf', + }; + return $commands; +} + +# +# Setup the init script configuration, including the install paths. +# Create the required directories for the client, /afs and the +# cache directory. +# +# N.B.The cacheinfo file is created by the init script. +# +sub configure_client { + my $self = shift; + my $config = { + # defaults + 'cachesize' => '50000', + # custom + @_, + }; + + my $debug = $self->{'debug'}; + my $syscnf = "$path->{'initdir'}/testclient.conf"; + + open (SYSCNF, "> $syscnf") or + die "error: Cannot open afs.rc configuration file $syscnf, $!\n"; + + print "debug: creating afs.rc configuration file $syscnf\n" if $debug; + print SYSCNF <<"_SYSCNF_"; +AFS_CLIENT=on +AFS_SERVER=off +ENABLE_AFSDB=off +ENABLE_DYNROOT=off +CACHESIZE=$config->{'cachesize'} +OPTIONS="-confdir $path->{'viceetcdir'}" +WAIT_FOR_SALVAGE=no +AFSDIR=/afs +CACHEDIR=$path->{'cachedir'}/cache +CACHEINFO=$path->{'viceetcdir'}/cacheinfo +VERBOSE= +AFS_POST_INIT= +AFSD=$path->{'afsddir'}/afsd +BOSSERVER=$path->{'afssrvsbindir'}/bosserver +BOS=$path->{'afssrvbindir'}/bos +KILLAFS=$path->{'viceetcdir'}/killafs +MODLOADDIR=$path->{'afskerneldir'} +_SYSCNF_ + close SYSCNF; + if ($debug) { + if (open(SYSCNF, "< $syscnf")) { + while () { + chomp; print "debug: $_\n"; + } + close SYSCNF; + } + } + + # Create a cache directory if none. + unless ( -d "$path->{'cachedir'}/cache" ) { + print "debug: making cache directory: $path->{'cachedir'}/cache\n" if $debug; + system("mkdir -p $path->{'cachedir'}/cache"); + system("chmod 0700 $path->{'cachedir'}/cache"); + } + + # Create the local /afs directory on which the afs filespace will be mounted. + if ( ! -d "/afs" ) { + print "debug: making the local /afs directory.\n" if $debug; + system("mkdir /afs"); + system("chmod 0777 /afs"); + } +} + +# +# Force the client to stop. The sequence is: +# umount /afs +# /usr/vice/etc/afsd -shutdown +# rmmod openafs (or rmmod libafs) +# +sub client_forcestop { + my $self = shift; + print "debug: client forcestop\n" if $self->{'debug'}; + + eval { + run("umount /afs"); + sleep 1; + }; + eval { + run("$path->{'afsddir'}/afsd -shutdown"); + sleep 1; + }; + + # Remove openafs modules still loaded. + my $mods = $self->list_modules(); + if ($mods->{'openafs'}) { + eval { run("/sbin/rmmod openafs") }; + } + if ($mods->{'libafs'}) { + eval { run("/sbin/rmmod libafs") }; + } + + # Check. + $mods = $self->list_modules(); + if ($mods->{'openafs'}) { + print "warning: kernel module still loaded: openafs\n"; + } + if ($mods->{'libafs'}) { + print "warning: kernel module still loaded: libafs\n"; + } + + # remove stale lock set by init script. + run("rm -f /var/lock/subsys/afs"); +} + +# +# list_modules() - Returns a table of loaded module names. +# +sub list_modules { + my $self = shift; + my $mods = {}; + if (open(LSMOD, "/sbin/lsmod |")) { + while() { + chomp; + my ($mod) = split; + $mods->{$mod} = 1; + } + close LSMOD; + } + return $mods; +} + +1; diff --git a/src/tests/afs-rmcell.pl b/src/tests/afs-rmcell.pl new file mode 100644 index 000000000..7e0550fae --- /dev/null +++ b/src/tests/afs-rmcell.pl @@ -0,0 +1,101 @@ +#!/usr/bin/env perl +# +# Remove cell files from this machine. Use with caution! +# + +use warnings; +use strict; +use OpenAFS::Dirpath; +use OpenAFS::OS; +use OpenAFS::ConfigUtils; +use Term::ReadLine; +use Getopt::Long; +use Pod::Usage; + +=head1 NAME + + afs-rmcell - Delete AFS cell files from this machine. + +=head1 SYNOPSIS + +B [B<--batch>] [B<--partition-id>=letter] [B<--help>] [B<--debug>] + +=head1 DESCRIPTION + +This script destroys the AFS database and volume files on this machine. +Use with caution! + +=cut + +my $debug = 0; +my $help = 0; +my $batch = 0; +my $partition_id = 'a'; +my $path = $OpenAFS::Dirpath::openafsdirpath; +my $ostype = $path->{'ostype'}; + +#----------------------------------------------------------------------------------- +# main script + +GetOptions( + "debug" => \$debug, + "help" => \$help, + "batch" => \$batch, + "partition-id=s" => \$partition_id, + "ostype=s" => \$ostype, +); + +$OpenAFS::ConfigUtils::debug = $debug; + +if ($help) { + pod2usage(1); + exit 0; +} + +if ($> != 0) { + die "error: This script should run as root.\n"; +} + +# To be on the safe side, we do no accept the full partition name, just the letter id. +# You'll have to manually delete volume files for unconventional partition names. +unless ($partition_id=~/^(([a-z])|([a-h][a-z])|([i][a-v]))$/) { + die "error: Invalid partition id specified.\n". + "info: Please specify a valid partition abbreviation, for example --partition-id='a' for /vicepa\n"; +} + +unless ($batch) { + my $rl = new Term::ReadLine('afs-rmcell'); + print "\n*** WARNING!! WARNING!! WARNING!! *** \n"; + print "You are about to permanently DESTROY the OpenAFS configuration, database, and volumes on this machine!\n\n"; + my $answer = $rl->readline("Do you really want to destroy the AFS cell data? (y/n) [n] "); + unless ($answer=~/^y/i ) { + print "info: Aborted.\n"; + exit 0; + } +} + +my $os = OpenAFS::OS::create('ostype'=>$ostype, 'debug'=>$debug); + +# make sure the client init script has the correct paths. +$os->configure_client(); + +run($os->command('client-stop')); +run($os->command('fileserver-stop')); +run($os->command('client-forcestop')); + +$os->remove("$path->{'afsdbdir'}/prdb.DB0"); +$os->remove("$path->{'afsdbdir'}/prdb.DBSYS1"); +$os->remove("$path->{'afsdbdir'}/vldb.DB0"); +$os->remove("$path->{'afsdbdir'}/vldb.DBSYS1"); +$os->remove("$path->{'afsbosconfigdir'}/BosConfig"); +$os->remove("$path->{'afslogsdir'}/*"); +$os->remove("$path->{'afslocaldir'}/*"); +$os->remove("$path->{'afsconfdir'}/UserList"); +$os->remove("$path->{'afsconfdir'}/ThisCell"); +$os->remove("$path->{'afsconfdir'}/CellServDB"); +$os->remove("$path->{'afsconfdir'}/KeyFile"); +$os->remove("$path->{'afsconfdir'}/krb.conf"); +$os->remove("/vicep$partition_id/AFSIDat "); +$os->remove("/vicep$partition_id/V*.vol"); +$os->remove("/vicep$partition_id/Lock"); +