Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > d236c5da97a239a1b6991cfba2865b66 > files > 85

cman-2.0.115-68.el5_6.1.src.rpm

From 636d2bc385af29f3f773eb0cdc8fed8992f367fd Mon Sep 17 00:00:00 2001
From: Ryan O'Hara <rohara@redhat.com>
Date: Mon, 27 Sep 2010 10:50:12 -0500
Subject: [PATCH] fence_scsi_test: rewrite to more accurately test

The old fence_scsi_test tool was far too simple to adequately
test it a devices was capable of being used with fence_scsi.
This rewrite should adequately test all requirements, such as
support for "preempt-and-abort" subcommand. This script will
also verify that each command worked as expected.

Resolves: rhbz#603838

Signed-off-by: Ryan O'Hara <rohara@redhat.com>
---
 fence/agents/scsi/fence_scsi_test.pl |  748 ++++++++++++++++++++++++++--------
 fence/man/fence_scsi_test.8          |   68 +++
 2 files changed, 653 insertions(+), 163 deletions(-)
 create mode 100644 fence/man/fence_scsi_test.8

diff --git a/fence/agents/scsi/fence_scsi_test.pl b/fence/agents/scsi/fence_scsi_test.pl
index e24ef61..25db6ba 100755
--- a/fence/agents/scsi/fence_scsi_test.pl
+++ b/fence/agents/scsi/fence_scsi_test.pl
@@ -1,272 +1,694 @@
 #!/usr/bin/perl
 
-use POSIX;
-use IPC::Open3;
-use XML::LibXML;
-use Getopt::Std;
-
-my @devices;
-my %results;
-
 #BEGIN_VERSION_GENERATION
 $FENCE_RELEASE_NAME="";
 $REDHAT_COPYRIGHT="";
 $BUILD_DATE="";
 #END_VERSION_GENERATION
 
-sub get_scsi_block_devices
+################################################################################
+
+use File::Basename;
+use Term::ANSIColor;
+use Getopt::Long;
+use XML::LibXML;
+
+################################################################################
+
+my @devices = ();
+my %devices_name = ();
+my %devices_path = ();
+my %options = ();
+my %results = ();
+
+################################################################################
+
+sub do_action_on (\@$$)
 {
-    print "[debug] get_scsi_block_devices\n" if ($opt_d);
+    my @devices = @{(shift)};
+    my ($dev, $node_key) = @_;
+    my $err = 0;
 
-    my $block_dir = "/sys/block";
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev node_key=$node_key)\n";
+    }
 
-    opendir(DIR, $block_dir) or die "$!\n";
+    foreach (@devices) {
+	if (do_reset ($_) != 0) {
+	}
+	if (do_register_ignore ($_, $node_key) != 0) {
+	    $err++;
+	}
+    }
 
-    my @block_devices = grep { /^sd*/ } readdir(DIR);
+    if (scalar (get_keys_reserve ($dev)) == 0) {
+	if (do_reserve ($dev, $node_key) != 0) {
+	    $err = 0;
+	}
+    }
 
-    closedir(DIR);
+    return ($err);
+}
 
-    for $block_dev (@block_devices)
-    {
-	print "[debug] \t device = $block_dev\n" if ($opt_d);
+sub do_action_off ($$$)
+{
+    my ($dev, $node_key, $host_key) = @_;
+    my $err = 0;
 
-	push(@devices, "/dev/" . $block_dev);
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev node_key=$node_key host_key=$host_key)\n";
     }
+
+    if (do_preempt_abort ($dev, $host_key, $node_key) != 0) {
+	$err++;
+    }
+
+    return ($err);
 }
 
-sub get_cluster_vol_devices
+sub do_verify_on (\@$$)
 {
-    print "[debug] get_cluster_vol_devices\n" if ($opt_d);
+    my @devices = @{(shift)};
+    my ($dev, $node_key) = @_;
+    my $err = 0;
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev node_key=$node_key)\n";
+    }
+
+    @keys = grep { /^$node_key$/ } get_keys_register ($dev);
 
-    my ($in, $out, $err);
+    if (scalar (@keys) != scalar (@devices)) {
+	$err++;
+    }
 
-    my $cmd = "vgs --config 'global { locking_type = 0 }'" .
-              "    --noheadings --separator : -o vg_attr,pv_name";
+    @keys = get_keys_reserve ($dev);
 
-    my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+    if (scalar (@keys) == 0) {
+	$err++;
+    }
 
-    waitpid($pid, 0);
+    return ($err);
+}
 
-    die "[error] unable to execute vgs command.\n" if WEXITSTATUS($?);
+sub do_verify_off ($$$)
+{
+    my ($dev, $node_key, $host_key) = @_;
+    my $err = 0;
 
-    while (<$out>)
-    {
-	chomp;
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev node_key=$node_key host_key=$host_key)\n";
+    }
 
-	my ($vg_attr, $pv_name) = split(/:/, $_);
+    @keys = grep { /^$node_key$/ } get_keys_register ($dev);
 
-	if ($vg_attr =~ /.*c$/)
-	{
-	    print "[debug] \t device = $pv_name\n" if ($opt_d);
+    if (scalar (@keys) != 0) {
+	$err++;
+    }
 
-	    push(@devices, $pv_name);
-	}
+    @keys = grep { /^$host_key$/ } get_keys_reserve ($dev);
+
+    if (scalar (@keys) == 0) {
+	$err++;
     }
 
-    close($in);
-    close($out);
-    close($err);
+    return ($err);
 }
 
-sub register_device
+sub do_key_write ($)
 {
-    my ($dev, $key) = @_;
-    my ($in, $out, $err);
+    my $key = shift;
 
-    print "[debug] register_device (device=$dev, key=$key)\n" if ($opt_d);
+    open (\*FILE, ">/tmp/.fence_scsi_test") or die "$!\n";
+    print (FILE "$key\n");
+    close (FILE);
 
-    my $cmd = "sg_persist -n -d $dev -o -G -S $key";
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (key=$key)\n";
+    }
 
-    print "[debug] \t cmd = $cmd\n" if ($opt_d);
+    return;
+}
 
-    my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+sub do_key_read ($)
+{
+    my $key = shift;
 
-    waitpid($pid, 0);
+    open (\*FILE, "</tmp/.fence_scsi_test") or die "$!\n";
+    chomp ($$key = <FILE>);
+    close (FILE);
 
-    $results{$dev}[0] = WEXITSTATUS($?);
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (key=$$key)\n";
+    }
 
-    close($in);
-    close($out);
-    close($err);
+    return;
 }
 
-sub unregister_device
+sub do_register ($$)
 {
-    my ($dev, $key) = @_;
-    my ($in, $out, $err);
+    my ($dev, $sark) = @_;
 
-    print "[debug] unregister_device (device=$dev, key=$key)\n" if ($opt_d);
+    my $cmd = "sg_persist -n -o -G -S $sark -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
 
-    my $cmd = "sg_persist -n -d $dev -o -G -K $key -S 0";
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev sark=$sark)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
+    }
 
-    print "[debug] \t cmd = $cmd\n" if ($opt_d);
+    return ($err);
+}
 
-    my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+sub do_register_ignore ($$)
+{
+    my ($dev, $sark) = @_;
 
-    waitpid($pid, 0);
+    my $cmd = "sg_persist -n -o -I -S $sark -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
 
-    $results{$dev}[1] = WEXITSTATUS($?);
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev sark=$sark)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
+    }
 
-    close($in);
-    close($out);
-    close($err);
+    return ($err);
 }
 
-sub test_devices
+sub do_reserve ($$)
 {
-    my $key = "0x1";
+    my ($dev, $rk) = @_;
+
+    my $cmd = "sg_persist -n -o -R -T 5 -K $rk -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
 
-    foreach $dev (@devices)
-    {
-	register_device($dev, $key);
-	unregister_device($dev, $key);
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev rk=$rk)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
     }
+
+    return ($err);
 }
 
-sub check_config_fence
+sub do_release ($$)
 {
-    my $xml = XML::LibXML->new();
-    my $tree = $xml->parse_file("/etc/cluster/cluster.conf");
-    my $root = "//cluster/fencedevices/fencedevice";
+    my ($dev, $rk) = @_;
 
-    my $xpath_fence = "count(${root}[\@agent='fence_scsi'])";
+    my $cmd = "sg_persist -n -o -L -T 5 -K $rk -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev rk=$rk)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
+    }
 
-    return ( ! $tree->findvalue($xpath_fence));
+    return ($err);
 }
 
-sub check_config_nodes
+sub do_preempt ($$$)
 {
-    my $xml = XML::LibXML->new();
-    my $tree = $xml->parse_file("/etc/cluster/cluster.conf");
-    my $root = "//cluster/clusternodes/clusternode";
+    my ($dev, $rk, $sark) = @_;
 
-    my $xpath_name = "count(${root}/\@name)";
-    my $xpath_nodeid = "count(${root}/\@nodeid)";
+    my $cmd = "sg_persist -n -o -P -T 5 -K $rk -S $sark -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev rk=$rk sark=$sark)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
+    }
 
-    return ($tree->findvalue($xpath_name) != $tree->findvalue($xpath_nodeid));
+    return ($err);
 }
 
-sub print_results
+sub do_preempt_abort ($$$)
 {
-    my $device_count = scalar(@devices);
+    my ($dev, $rk, $sark) = @_;
 
-    my $failure_count = 0;
-    my $success_count = 0;
+    my $cmd = "sg_persist -n -o -A -T 5 -K $rk -S $sark -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
 
-    print "\nAttempted to register with devices:\n";
-    print "-------------------------------------\n";
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev rk=$rk sark=$sark)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
+    }
 
-    for $dev (@devices)
-    {
-	print "\t$dev\t";
-	if ($results{$dev}[0] == 0)
-	{
-	    $success_count++;
-	    print "Success\n";
-	}
-	else
-	{
-	    $failure_count++;
-	    print "Failure\n";
-	}
+    return ($err);
+}
+
+sub do_clear ($$)
+{
+    my ($dev, $rk) = @_;
+
+    my $cmd = "sg_persist -n -o -C -K $rk -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev rk=$rk)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
     }
 
-    print "-------------------------------------\n";
-    print "Number of devices tested: $device_count\n";
-    print "Number of devices passed: $success_count\n";
-    print "Number of devices failed: $failure_count\n\n";
+    return ($err);
+}
+
+sub do_reset ($)
+{
+    my ($dev) = @_;
+
+    my $cmd = "sg_turs $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
 
-    if ($failure_count != 0)
-    {
-	exit(1);
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
     }
+
+    return ($err);
 }
 
-sub print_usage
+sub get_options ()
 {
-    print "\nUsage: fence_scsi_test [-c|-s] [-d] [-h]\n\n";
+    my @opts = ("d|device=s",
+		"h|help",
+		"k|key=s",
+		"o|action=s",
+		"t|test=s",
+		"v|verbose");
 
-    print "Options:\n\n";
+    Getopt::Long::Configure ("no_auto_abbrev") or exit (1);
+    Getopt::Long::GetOptions (\%options, @opts) or exit (1);
 
-    print "  -c     Cluster mode. This mode is intended to test\n";
-    print "         SCSI persistent reservation capabilties for\n";
-    print "         devices that are part of existing clustered\n";
-    print "         volumes. Only devices in LVM cluster volumes\n";
-    print "         will be tested.\n\n";
-    print "  -s     SCSI mode. This mode is intended to test SCSI\n";
-    print "         persistent reservation capabilities for all SCSI\n";
-    print "         devices visible on a node.\n\n";
-    print "  -d     Debug flag. This will print debugging information\n";
-    print "         such as the actual commands being run to register\n";
-    print "         and unregister a device.\n\n";
-    print "  -h     Help. Prints out this usage information.\n\n";
+    return;
 }
 
-sub test_tools_path
+sub get_devices ()
 {
-    my $tool_name = "sg_persist";
-    
-    for my $path ( split /:/, $ENV{PATH} ) {
-        if ( -f "$path/$tool_name" && -x _ ) {
-          return;
-        }
+    my @devices = split (/,/, $options{'d'});
+
+    map { s/^\s+// } @devices;
+    map { s/\s+$// } @devices;
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self\n";
+    }
+
+    return (@devices);
+}
+
+sub get_devices_clvm ()
+{
+    my @devices = ();
+
+    my $cmd = "vgs" .
+              " --noheadings" .
+              " --sort pv_uuid" .
+              " --options pv_name,vg_attr" .
+              " --config 'global { locking_type=0 }'";
+
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
+
+    @devices = map { (split)[0] } grep { /c$/ } @out;
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self\n";
+    }
+
+    return (@devices);
+}
+
+sub get_devices_scsi ()
+{
+    my @devices = ();
+
+    open (\*DIR, "/sys/block/") or die "$!\n";
+    @devices = grep { /^sd/ } readdir (DIR);
+    close (DIR);
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self\n";
+    }
+
+    return (@devices);
+}
+
+sub get_devices_name ($)
+{
+    my $dev = shift;
+    my $name = basename ($dev);
+
+    if (-l "/dev/mpath/$name") {
+	$name = basename (readlink "/dev/mpath/$name");
+    }
+
+    $name = "/dev/$name";
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev)\n";
+	print "    name=$name\n";
     }
-    
-    die "No $tool_name command available, please install the sg3_utils package.\n"
+
+    return ($name);
 }
 
-### MAIN #######################################################################
+sub get_devices_path ($)
+{
+    my $dev = shift;
+    my $name = basename ($dev);
+    my @path = ();
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev)\n";
+    }
+
+    if (-d "/sys/block/$name/slaves/") {
+	opendir (\*DIR, "/sys/block/$name/slaves/");
+	@path = grep { !/^\./ } readdir (DIR);
+	closedir (DIR);
+    }
+
+    if (scalar (@path) == 0) {
+	push (@path, $name);
+    }
 
-test_tools_path;
+    if ($path[0] =~ /^dm/) {
+	@path = get_devices_path ("/dev/$path[0]");
+    } else {
+	@path = map { "/dev/$_" } @path;
+	if (defined $options{'v'}) {
+	    print "    path=[ @path ]\n";
+	}
+    }
 
-if (getopts("cdhst:v") == 0)
+    return (@path);
+}
+
+sub get_devices_info ($)
 {
-    print_usage;
-    exit(1);
+    my $dev = shift;
+    my $name = basename ($dev);
+    my @info = ();
+
+    if (-e "/sys/block/$name/device/vendor") {
+	open (\*FILE, "</sys/block/$name/device/vendor");
+	chomp ($info[0] = <FILE>);
+	close (FILE);
+    }
+
+    if (-e "/sys/block/$name/device/model") {
+	open (\*FILE, "</sys/block/$name/device/model");
+	chomp ($info[1] = <FILE>);
+	close (FILE);
+    }
+
+    map { s/^\s+// } @info;
+    map { s/\s+$// } @info;
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev)\n";
+	print "    info=[ @info ]\n";
+    }
+
+    return (@info);
 }
 
-if ($opt_h)
+sub get_keys_register ($)
 {
-    print_usage;
-    exit(0);
+    my $dev = shift;
+    my @keys = ();
+
+    my $cmd = "sg_persist -n -i -k -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
+
+    foreach (@out) {
+	chomp;
+	push (@keys, $_) if ($_ =~ s/^\s+0x//i);
+    }
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
+	print "    keys=[ @keys ]\n";
+    }
+
+    return (@keys);
 }
 
-if ($opt_c && $opt_s) {
-    print_usage;
-    exit(1);
+sub get_keys_reserve
+{
+    my $dev = shift;
+    my @keys = ();
+
+    my $cmd = "sg_persist -n -i -r -d $dev";
+    my @out = qx { $cmd 2> /dev/null };
+    my $err = ($?>>8);
+
+    foreach (@out) {
+	chomp;
+	push (@keys, $_) if ($_ =~ s/^\s+key=0x//i);
+    }
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev)\n";
+	print "    cmd=$cmd\n";
+	print "    err=$err\n";
+	print "    keys=[ @keys ]\n";
+    }
+
+    return (@keys);
 }
 
-if ($opt_c)
+sub test_config_fence ()
 {
-    print "\nTesting devices in cluster volumes...\n";
-    get_cluster_vol_devices;
-    test_devices;
-    print_results;
+    my $xml = XML::LibXML->new();
+    my $file = "/etc/cluster/cluster.conf";
+    my $tree = $xml->parse_file ($file);
+    my $root = "//cluster/fencedevices/fencedevice";
+    my $err = 0;
+
+    my $xpath_agent = "count(${root}[\@agent='fence_scsi'])";
+
+    if ($tree->findvalue ($xpath_agent) == 0) {
+	$err = 1;
+    }
+
+    exit ($err);
 }
 
-if ($opt_s)
+sub test_config_nodes ()
 {
-    print "\nTesting all SCSI block devices...\n";
-    get_scsi_block_devices;
-    test_devices;
-    print_results;
+    my $xml = XML::LibXML->new();
+    my $file = "/etc/cluster/cluster.conf";
+    my $tree = $xml->parse_file ($file);
+    my $root = "//cluster/clusternodes/clusternode";
+    my $err = 0;
+
+    my $xpath_name = "count(${root}/\@name)";
+    my $xpath_nodeid = "count(${root}/\@nodeid)";
+
+    if ($tree->findvalue ($xpath_name) != $tree->findvalue ($xpath_nodeid)) {
+	$err = 1;
+    }
+
+    exit ($err);
 }
 
-if ($opt_t)
+sub print_devices ()
 {
-    if ($opt_t eq "fence")
-    {
-	exit check_config_fence;
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self\n";
+	foreach (@devices) {
+	    print "    $_\n";
+	}
     }
-    if ($opt_t eq "nodes")
-    {
-	exit check_config_nodes;
+
+    return;
+}
+
+sub print_options ()
+{
+    return;
+}
+
+sub print_results ($)
+{
+    my $dev = shift;
+    my @results = @{$results{$dev}};
+
+    if (defined $options{'v'}) {
+	$self = (caller(0))[3];
+	print "  $self (dev=$dev)\n";
+	print "    results=[ action=$results[0] verify=$results[1] ]\n";
+    } else {
+	printf ("  %-*s", $width, $_);
+	if (grep { $_  } @results) {
+	    $test = colored (" FAIL ", "red");
+	} else {
+	    $test = colored ("  OK  ", "green");
+	}
+	printf ("[%s]\n", $test);
     }
+
+    return;
 }
 
-if (!$opt_c && !$opt_s && !$opt_t)
+sub print_usage
 {
-    print "\nPlease specify either cluster or SCSI mode.\n";
-    print_usage;
-    exit(1);
+    print "\n";
+    print "Usage: fence_scsi_test -o <on|off> -k <key> [options]\n";
+    print "\n";
+    print "Actions:\n";
+    print "\n";
+    print "  on                    Register <key> with the devices.\n";
+    print "  off                   Remove <key> form the devices.\n";
+    print "\n";
+    print "Options:\n";
+    print "\n";
+    print "  -d, --devices=LIST    Devices used for the current action.\n";
+    print "  -h, --help            Display this help and exit.\n";
+    print "  -v, --verbose         Verbose mode.\n";
+    print "\n";
+
+    defined $options{'h'} ? exit (0) : exit (1);
+}
+
+################################################################################
+
+get_options ();
+
+if (scalar (keys %options) == 0) {
+    print_usage ();
+}
+
+if (defined $options{'v'}) {
+    print_options ();
+}
+
+if (defined $options{'h'}) {
+    print_usage ();
+}
+
+if (defined $options{'t'}) {
+    for ($options{'t'}) {
+	($_ =~ /^fence$/i) && do {
+	    test_config_fence ();
+	    last;
+	};
+	($_ =~ /^nodes$/i) && do {
+	    test_config_nodes ();
+	    last;
+	};
+	exit (1);
+    }
+}
+
+if ($options{'k'} =~ /^[[:xdigit:]]+$/) {
+    $node_key = lc ($options{'k'});
+} else {
+    print_usage ();
+}
+
+for ($options{'o'}) {
+    ($_ =~ /^on$/i) && do {
+	do_key_write ($node_key);
+	last;
+    };
+    ($_ =~ /^off$/i) && do {
+	do_key_read (\$host_key);
+	last;
+    };
+    print_usage ();
+}
+
+if (defined $options{'d'}) {
+    @devices = get_devices ();
+} else {
+    @devices = get_devices_clvm ();
+}
+
+if (scalar (@devices) == 0) {
+    die "error: no devices found\n";
+} else {
+    $count = scalar (@devices);
+    $width = (reverse sort { $a <=> $b } map { (length) + 8 } @devices)[0];
+}
+
+if (defined $options{'v'}) {
+    print_devices ();
+}
+
+foreach (@devices) {
+    if (! -e $_) {
+	die "error: $_ does not exist\n";
+    }
+    if (! -b $_) {
+	die "error: $_ is not a block device\n";
+    }
+
+    $devices_name{$_} = get_devices_name ($_);
+    $devices_path{$_} = [ get_devices_path ($devices_name{$_}) ];
+}
+
+for ($options{'o'}) {
+    ($_ =~ /^on$/i) && do {
+	print "\n" if (!defined $options{'v'});
+	foreach (@devices) {
+	    $results{$_}[0] = do_action_on (@{$devices_path{$_}}, $_, $node_key);
+	    $results{$_}[1] = do_verify_on (@{$devices_path{$_}}, $_, $node_key);
+	    print_results ($_);
+	}
+	print "\n" if (!defined $options{'v'});
+	last;
+    };
+    ($_ =~ /^off$/i) && do {
+	print "\n" if (!defined $options{'v'});
+	foreach (@devices) {
+	    $results{$_}[0] = do_action_off ($devices_name{$_}, $node_key, $host_key);
+	    $results{$_}[1] = do_verify_off ($devices_name{$_}, $node_key, $host_key);
+	    print_results ($_);
+	}
+	print "\n" if (!defined $options{'v'});
+	last;
+    };
+    print_usage ();
 }
diff --git a/fence/man/fence_scsi_test.8 b/fence/man/fence_scsi_test.8
new file mode 100644
index 0000000..3252dca
--- /dev/null
+++ b/fence/man/fence_scsi_test.8
@@ -0,0 +1,68 @@
+.\"  Copyright (C) 2010 Red Hat, Inc.  All rights reserved.
+.\"  
+.\"  This copyrighted material is made available to anyone wishing to use,
+.\"  modify, copy, or redistribute it subject to the terms and conditions
+.\"  of the GNU General Public License v.2.
+
+.TH fence_scsi_test 8
+
+.SH NAME
+fence_scsi_test - Test for SCSI persistent reservation fencing
+
+.SH SYNOPSIS
+.B
+fence_scsi_test -o <on|off> -k <key>
+[\fIOPTIONS\fR]
+
+.SH DESCRIPTION
+fence_scsi_test is a script used to verify that specific hardware
+configurations are capable of being used with the fence_scsi
+agent. All storage devices that are to be used with the fence_scsi
+agent must be capable of SCSI persistent reservations. This script
+assists in determining that the requirements are met by performing
+appropriate SCSI-PR actions and verifying the results.
+
+This script is capable of creating reservations and registrations, as
+well as removing them. The "on" action is used to create reservations,
+just as you would do when a node comes online. The "off" action is
+used to remove registrations, which is equivalent to fencing. It is
+important to test both the "on" and "off" actions when testing for
+fence_scsi compatibility.
+
+Because this script is capable of creating, modifying, and removing
+existing reservations and registrations, it should not be used on any
+systems that are actively using SCSI persistent reservations.
+
+.SH OPTIONS
+.TP
+\fB-o, --action=[on|off]\fR
+The action to perform. This value can be "on" or "off". For "on", the
+script will attempt to register a key (see -k option) with the
+device(s) (see -d option) and create a reservation if none exists. The
+"off" action will attempt to remove a key from the device(s). This
+option is required.
+
+.TP
+\fB-k, --key=VALUE\fR
+The key to use for the current action. The key must be a hexadecimal
+value and should be unique to a node. For the "on" action, the key
+specifies the key value use to register the local node with the
+device(s). For the "off" action, the key specifies the key value to be
+removed from the device(s).
+
+.TP
+\fB-d, --devices=LIST\fR
+List of devices to use for current action. This can be a single device
+or a comma-separated list of devices. Each device should be given as
+the full path (eg. /dev/sdc).
+
+.TP
+\fB-h, --help\fR
+Print out a help message describing available options, then exit.
+
+.TP
+\fB-v, --verbose\fR
+Verbose output.
+
+.SH SEE ALSO
+fence_scsi(8), fence(8), fence_node(8), sg_persist(8), lvs(8), lvm.conf(5)
-- 
1.7.2.2