fence-agents: master - New fence_scsi with config options.
rohara
rohara at fedoraproject.org
Tue Dec 8 15:51:32 UTC 2009
Gitweb: http://git.fedorahosted.org/git/fence-agents.git?p=fence-agents.git;a=commitdiff;h=b8f0c9eefc0a3b2a387b8b678a42d56c38e10687
Commit: b8f0c9eefc0a3b2a387b8b678a42d56c38e10687
Parent: ba17f1ef9bf3a5e9bf7bb5d8a5668c807e69269e
Author: Ryan O'Hara <rohara at redhat.com>
AuthorDate: Tue Dec 8 09:51:06 2009 -0600
Committer: Ryan O'Hara <rohara at redhat.com>
CommitterDate: Tue Dec 8 09:51:06 2009 -0600
New fence_scsi with config options.
---
fence/agents/scsi/fence_scsi.pl | 712 +++++++++++++++++++++++++--------------
1 files changed, 462 insertions(+), 250 deletions(-)
diff --git a/fence/agents/scsi/fence_scsi.pl b/fence/agents/scsi/fence_scsi.pl
index d95198b..e58a5b1 100644
--- a/fence/agents/scsi/fence_scsi.pl
+++ b/fence/agents/scsi/fence_scsi.pl
@@ -1,22 +1,8 @@
#!/usr/bin/perl
+use File::Basename;
use Getopt::Std;
use IPC::Open3;
-use POSIX;
-
-my $ME = $0;
-
-END {
- defined fileno STDOUT or return;
- close STDOUT and return;
- warn "$ME: failed to close standard output: $!\n";
- $? ||= 1;
-}
-
-$_ = $0;
-s/.*\///;
-my $pname = $_;
-my @device_list;
#BEGIN_VERSION_GENERATION
$RELEASE_VERSION="";
@@ -24,373 +10,599 @@ $REDHAT_COPYRIGHT="";
$BUILD_DATE="";
#END_VERSION_GENERATION
-sub usage
+my $ME = fileparse ($0, ".pl");
+
+################################################################################
+
+sub log_debug ($)
{
- print "Usage\n";
- print "\n";
- print "$pname [options]\n";
- print "\n";
- print "Options:\n";
- print " -n <node> ip address or hostname of node to fence\n";
- print " -h usage\n";
- print " -u unfence\n";
- print " -v verbose\n";
- print " -V version\n";
+ my ($msg) = @_;
- exit 0;
+ print STDOUT "[debug]: $msg\n" unless defined ($opt_q);
}
-sub version
+sub log_error ($)
{
- print "$pname $RELEASE_VERSION $BUILD_DATE\n";
- print "$REDHAT_COPYRIGHT\n" if ($REDHAT_COPYRIGHT);
+ my ($msg) = @_;
+
+ print STDERR "[error]: $msg\n" unless defined ($opt_q);
}
-sub fail_usage
+sub do_action_on ($@)
{
- ($msg) = @_;
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($node_key, @devices) = @_;
+
+ key_write ($node_key);
- print STDERR $msg."\n" if $msg;
- print STDERR "Please use '-h' for usage.\n";
+ foreach $dev (@devices) {
+ do_register_ignore ($node_key, $dev);
- exit 1;
+ if (!get_reservation_key ($dev)) {
+ do_reserve ($node_key, $dev);
+ }
+ }
}
-sub check_sg_persist
+sub do_action_off ($@)
{
- my ($in, $out, $err);
- my $cmd = "sg_persist -V";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($node_key, @devices) = @_;
- waitpid($pid, 0);
+ my $host_key = key_read ();
- die "unable to execute sg_persist.\n" if ($?>>8);
+ if ($host_key eq $node_key) {
+ log_error ($self);
+ exit (1);
+ }
+
+ foreach $dev (@devices) {
+ my @keys = grep { /$node_key/ } get_registration_keys ($dev);
- close ($in);
- close ($out);
- close ($err);
+ if (scalar (@keys) != 0) {
+ do_preempt_abort ($host_key, $node_key, $dev);
+ }
+ }
}
-sub get_cluster_id
+sub do_action_status ($@)
{
- my ($in, $out, $err);
- my $cmd = "cman_tool status";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- waitpid($pid, 0);
+ my ($node_key, @devices) = @_;
- die "unable to execute cman_tool.\n" if ($?>>8);
+ my $dev_count = 0;
+ my $key_count = 0;
- my $cluster_id;
+ foreach $dev (@devices) {
+ my @keys = grep { /$node_key/ } get_registration_keys ($dev);
- while (<$out>) {
- chomp;
+ if (scalar (@keys) != 0) {
+ $dev_count++;
+ }
+ }
- my ($name, $value) = split(/\s*:\s*/, $_);
+ if ($dev_count != 0) {
+ exit (0);
+ }
+ else {
+ exit (2);
+ }
+}
- if ($name eq "Cluster Id") {
- $cluster_id = $value;
- last;
+sub do_register ($$$)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($host_key, $node_key, $dev) = @_;
+
+ if (substr ($dev, 5) =~ /^dm/) {
+ my @slaves = get_mpath_slaves ($dev);
+
+ foreach (@slaves) {
+ do_register ($node_key, $_);
}
+ return;
}
- close ($in);
- close ($out);
- close ($err);
+ my $cmd = "sg_persist -n -o -G -K $host_key -S $node_key -d $dev";
+ $cmd .= " -Z" if (defined $opt_a);
+
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
- return $cluster_id;
+ die "[error]: $self\n" if ($?>>8);
+
+ close (IN);
+ close (OUT);
+ close (ERR);
}
-sub get_node_id
+sub do_register_ignore ($$)
{
- ($node) = @_;
-
- my ($in, $out, $err);
- my $cmd = "ccs_tool query /cluster/clusternodes/clusternode[\@name=\\\"$node\\\"]/\@nodeid";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- waitpid($pid, 0);
+ my ($node_key, $dev) = @_;
- die "Unable to execute ccs_tool.\n" if ($?>>8);
+ if (substr ($dev, 5) =~ /^dm/) {
+ my @slaves = get_mpath_slaves ($dev);
- while (<$out>) {
- chomp;
- $node_id = $_;
+ foreach (@slaves) {
+ do_register_ignore ($node_key, $_);
+ }
+ return;
}
- close ($in);
- close ($out);
- close ($err);
+ my $cmd = "sg_persist -n -o -I -S $node_key -d $dev";
+ $cmd .= " -Z" if (defined $opt_a);
+
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
+
+ waitpid ($pid, 0);
+
+ die "[error]: $self\n" if ($?>>8);
- return $node_id;
+ close (IN);
+ close (OUT);
+ close (ERR);
}
-sub get_host_name
+sub do_reserve ($$)
{
- my ($in, $out, $err);
- my $cmd = "cman_tool status";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- waitpid($pid, 0);
+ my ($host_key, $dev) = @_;
- die "unable to execute cman_tool.\n" if ($?>>8);
+ my $cmd = "sg_persist -n -o -R -T 5 -K $host_key -d $dev";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
- my $host_name;
+ waitpid ($pid, 0);
- while (<$out>) {
- chomp;
+ die "[error]: $self\n" if ($?>>8);
- my ($name, $value) = split(/\s*:\s*/, $_);
+ close (IN);
+ close (OUT);
+ close (ERR);
+}
- if ($name eq "Node name") {
- $host_name = $value;
- last;
- }
- }
+sub do_release ($$)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($host_key, $dev) = @_;
- close ($in);
- close ($out);
- close ($err);
+ my $cmd = "sg_persist -n -o -L -T 5 -K $host_key -d $dev";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
- return $host_name;
+ waitpid ($pid, 0);
+
+ die "[error]: $self\n" if ($?>>8);
+
+ close (IN);
+ close (OUT);
+ close (ERR);
}
-sub get_node_name
+sub do_preempt ($$$)
{
- return $opt_n;
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($host_key, $node_key, $dev) = @_;
+
+ my $cmd = "sg_persist -n -o -P -T 5 -K $host_key -S $node_key -d $dev";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
+
+ waitpid ($pid, 0);
+
+ die "[error]: $self\n" if ($?>>8);
+
+ close (IN);
+ close (OUT);
+ close (ERR);
}
-sub get_key
+sub do_preempt_abort ($$$)
{
- ($node) = @_;
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- my $cluster_id = get_cluster_id;
- my $node_id = get_node_id($node);
+ my ($host_key, $node_key, $dev) = @_;
- if ($node_id == 0) {
- die "unable to determine nodeid for node '$node'\n";
- }
+ my $cmd = "sg_persist -n -o -A -T 5 -K $host_key -S $node_key -d $dev";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
+
+ waitpid ($pid, 0);
- my $key = sprintf "%.4x%.4x", $cluster_id, $node_id;
+ die "[error]: $self ($dev)\n" if ($?>>8);
- return $key;
+ close (IN);
+ close (OUT);
+ close (ERR);
}
-sub get_options_stdin
+sub key_read ()
{
- my $opt;
- my $line = 0;
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- while (defined($in = <>)) {
+ open (\*FILE, "</var/lib/cluster/fence_scsi.key") or die "$!\n";
- $_ = $in;
- chomp;
+ chomp (my $key = <FILE>);
- ## strip leading and trailing whitespace
- ##
- s/^\s*//;
- s/\s*$//;
+ close (FILE);
- ## skip comments
- ##
- next if /^#/;
+ return ($key);
+}
- $line += 1;
- $opt = $_;
+sub key_write ($)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- next unless $opt;
+ open (\*FILE, ">/var/lib/cluster/fence_scsi.key") or die "$!\n";
- ($name, $value) = split(/\s*=\s*/, $opt);
+ print FILE "$_[0]\n";
- if ($name eq "")
- {
- print STDERR "parse error: illegal name in option $line\n";
- exit 2;
- }
- elsif ($name eq "agent")
- {
- ## ignore this
- }
- elsif ($name eq "node")
- {
- $opt_n = $value;
- }
- elsif ($name eq "nodename")
- {
- $opt_n = $value;
- }
- elsif ($name eq "action")
- {
- ## if "action=on", the we are performing an unfence operation.
- ## any other value for "action" is ignored. the default is a
- ## fence operation.
- ##
- if ($value eq "on") {
- $opt_u = $value;
- }
+ close (FILE);
+}
+
+sub get_key ($)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my $key = sprintf ("%.4x%.4x", get_cluster_id (), get_node_id ($_[0]));
+
+ return ($key);
+}
+
+sub get_node_id ($)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my $cmd = "cman_tool nodes -n $_[0] -F id";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
+
+ waitpid ($pid, 0);
+
+ die "[error]: $self\n" if ($?>>8);
+
+ chomp (my $node_id = <OUT>);
+
+ close (IN);
+ close (OUT);
+ close (ERR);
+
+ return ($node_id);
+}
+
+sub get_cluster_id ()
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my $cmd = "cman_tool status";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
+
+ waitpid ($pid, 0);
+
+ die "[error]: $self\n" if ($?>>8);
+
+ my $cluster_id;
+
+ while (<OUT>) {
+ chomp;
+
+ my ($param, $value) = split (/\s*:\s*/, $_);
+
+ if ($param =~ /^cluster\s+id/i) {
+ $cluster_id = $value;
}
}
+
+ close (IN);
+ close (OUT);
+ close (ERR);
+
+ return ($cluster_id);
}
-sub get_scsi_devices
+sub get_devices_clvm ()
{
- my ($in, $out, $err);
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- my $cmd = "vgs --config 'global { locking_type = 0 }'" .
- " --noheadings --separator : -o vg_attr,pv_name 2> /dev/null";
+ my $cmd = "vgs --noheadings " .
+ " --separator : " .
+ " --sort pv_uuid " .
+ " --options vg_attr,pv_name " .
+ " --config 'global { locking_type = 0 } " .
+ " devices { preferred_names = [ \"^/dev/dm\" ] }'";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
- waitpid($pid, 0);
+ waitpid ($pid, 0);
- die "unable to execute vgs.\n" if ($?>>8);
+ die "[error]: $self\n" if ($?>>8);
- while (<$out>) {
+ my @devices;
+
+ while (<OUT>) {
chomp;
- my ($attrs, $dev) = split(/:/, $_);
+ my ($vg_attr, $pv_name) = split (/:/, $_);
- if ($attrs =~ /.*c$/) {
- $dev =~ s/\(.*\)//;
- push(@device_list, $dev);
+ if ($vg_attr =~ /c$/) {
+ push (@devices, $pv_name);
}
}
- close ($in);
- close ($out);
- close ($err);
+ close (IN);
+ close (OUT);
+ close (ERR);
+
+ return (@devices);
}
-sub create_registration
+sub get_devices_scsi ()
{
- my ($key, $dev) = @_;
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- my ($in, $out, $err);
- my $cmd = "sg_persist -n -d $dev -o -I -S $key";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ opendir (\*DIR, "/sys/block/") or die "$!\n";
- waitpid($pid, 0);
+ my @devices = grep { /^sd/ } readdir (DIR);
- die "unable to create registration.\n" if ($?>>8);
+ closedir (DIR);
- close ($in);
- close ($out);
- close ($err);
+ return (@devices);
}
-sub create_reservation
+sub get_mpath_name ($)
{
- my ($key, $dev) = @_;
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($dev) = @_;
- my ($in, $out, $err);
- my $cmd = "sg_persist -n -d $dev -o -R -K $key -T 5";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ if ($dev =~ /^\/dev\//) {
+ $dev = substr ($dev, 5);
+ }
+
+ open (\*FILE, "/sys/block/$dev/dm/name") or die "$!\n";
- waitpid($pid, 0);
+ chomp (my $name = <FILE>);
- die "unable to create reservation.\n" if ($?>>8);
+ close (FILE);
- close ($in);
- close ($out);
- close ($err);
+ return ($name);
}
-sub fence_node
+sub get_mpath_uuid ($)
{
- my $host_name = get_host_name;
- my $host_key = get_key($host_name);
+ (my $self = (caller(0))[3]) =~ s/^main:://;
- my $node_name = get_node_name;
- my $node_key = get_key($node_name);
+ my ($dev) = @_;
- my ($in, $out, $err);
+ if ($dev =~ /^\/dev\//) {
+ $dev = substr ($dev, 5);
+ }
- foreach $dev (@device_list)
- {
- ## check that the key we are attempting to remove
- ## is actually registered with the device. if the key is not
- ## registered, there is nothing to do for this device.
- ##
- system ("sg_persist -n -d $dev -i -k | grep -qiE \"^[[:space:]]*0x$key\"");
-
- if (($?>>8) != 0) {
- next;
- }
+ open (\*FILE, "/sys/block/$dev/dm/uuid") or die "$!\n";
- if ($host_key eq $node_key) {
- ## this sg_persist command is for the case where you attempt to
- ## fence yourself (ie. the local node is the same at the node to
- ## be fence). this will not work if the node is the reservation
- ## holder, since you can't unregister while holding the reservation.
- ##
- my $cmd = "sg_persist -n -d $dev -o -G -K $host_key -S 0";
- }
- else {
- ## this sg_persist command will remove the registration for $host_key.
- ## the local node will also become the reservation holder, regardless
- ## of which node was holding the reservation prior to the fence operation.
- ##
- my $cmd = "sg_persist -n -d $dev -o -A -K $host_key -S $node_key -T 5";
+ chomp (my $uuid = <FILE>);
+
+ close (FILE);
+
+ return ($name);
+}
+
+sub get_mpath_slaves ($)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($dev) = @_;
+
+ if ($dev =~ /^\/dev\//) {
+ $dev = substr ($dev, 5);
+ }
+
+ opendir (\*DIR, "/sys/block/$dev/slaves/") or die "$!\n";
+
+ my @slaves = grep { !/^\./ } readdir (DIR);
+
+ if ($slaves[0] =~ /^dm/) {
+ @slaves = get_mpath_slaves ($slaves[0]);
+ }
+ else {
+ @slaves = map { "/dev/$_" } @slaves;
+ }
+
+ closedir (DIR);
+
+ return (@slaves);
+}
+
+sub get_registration_keys ($)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($dev) = @_;
+
+ my $cmd = "sg_persist -n -i -k -d $dev";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
+
+ waitpid ($pid, 0);
+
+ die "[error]: $self\n" if ($?>>8);
+
+ my @keys;
+
+ while (<OUT>) {
+ chomp;
+
+ if ($_ =~ s/^\s+0x//i) {
+ push (@keys, $_);
}
+ }
+
+ close (IN);
+ close (OUT);
+ close (ERR);
+
+ return (@keys);
+}
+
+sub get_reservation_key ($)
+{
+ (my $self = (caller(0))[3]) =~ s/^main:://;
+
+ my ($dev) = @_;
+
+ my $cmd = "sg_persist -n -i -r -d $dev";
+ my $pid = open3 (\*IN, \*OUT, \*ERR, $cmd) or die "$!\n";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
+ waitpid ($pid, 0);
- waitpid($pid, 0);
+ die "[error]: $self\n" if ($?>>8);
- die "unable to execute sg_persist.\n" if ($?>>8);
+ my $key;
- close ($in);
- close ($out);
- close ($err);
+ while (<OUT>) {
+ chomp;
+
+ if ($_ =~ s/^\s+key=0x//i) {
+ $key = $_;
+ last;
+ }
}
+
+ close (IN);
+ close (OUT);
+ close (ERR);
+
+ return ($key);
}
-sub unfence_node
+sub get_options_stdin ()
{
- my $host_name = get_host_name;
- my $host_key = get_key($host_name);
+ my $num = 0;
- foreach $dev (@device_list)
+ while (<STDIN>)
{
- create_registration ($host_key, $dev);
+ chomp;
+
+ s/^\s*//;
+ s/\s*$//;
- ## check to see if a reservation already exists.
- ## if no reservation exists, this node/key will become
- ## the reservation holder.
- ##
- system ("sg_persist -n -d $dev -i -r | grep -qiE \"^[[:space:]]*Key=0x\"");
+ next if (/^#/);
- if (($?>>8) != 0) {
- create_reservation ($host_key, $dev);
+ $num++;
+
+ next unless ($_);
+
+ my ($opt, $arg) = split (/\s*=\s*/, $_);
+
+ if ($opt eq "") {
+ exit (1);
+ }
+ elsif ($opt eq "aptpl") {
+ $opt_a = $arg;
+ }
+ elsif ($opt eq "devices") {
+ $opt_d = $arg;
+ }
+ elsif ($opt eq "logfile") {
+ $opt_f = $arg;
+ }
+ elsif ($opt eq "key") {
+ $opt_k = $arg;
+ }
+ elsif ($opt eq "nodename") {
+ $opt_n = $arg;
+ }
+ elsif ($opt eq "action") {
+ $opt_o = $arg;
}
}
}
+sub print_usage ()
+{
+ print "Usage:\n";
+ print "\n";
+ print "$ME [options]\n";
+ print "\n";
+ print "Options:\n";
+ print " -a Use APTPL flag\n";
+ print " -d <devices> Devices to be used for action\n";
+ print " -f <logfile> File to write debug/error output\n";
+ print " -h Usage\n";
+ print " -k <key> Key to be used for current action\n";
+ print " -n <nodename> Name of node to operate on\n";
+ print " -o <action> Action: off (default), on, or status\n";
+ print " -q Quiet mode\n";
+ print " -V Version\n";
+
+ exit (0);
+}
+
+sub print_version ()
+{
+ print "$ME $RELEASE_VERSION $BUILD_DATE\n";
+ print "$REDHAT_COPYRIGHT\n" if ( $REDHAT_COPYRIGHT );
+
+ exit (0);
+}
+
+################################################################################
+
if (@ARGV > 0) {
+ getopts ("ad:f:hk:n:o:qV") or die "$!\n";
- getopts("hn:uvV") || fail_usage;
+ print_usage if (defined $opt_h);
+ print_version if (defined $opt_V);
+}
+else {
+ get_options_stdin ();
+}
- usage if defined $opt_h;
- version if defined $opt_V;
+if (defined $opt_f) {
+ open (LOG, ">$opt_f") or die "$!\n";
+ open (STDOUT, ">&LOG");
+ open (STDERR, ">&LOG");
+}
- if (!defined $opt_u) {
- fail_usage "No '-n' flag specified." unless defined $opt_n;
- }
+if ((!defined $opt_n) && (!defined $opt_k)) {
+ log_error ("No '-n' or '-k' flag specified.");
+ exit (1);
+}
-} else {
+if (defined $opt_k) {
+ $key = $opt_k;
+}
+else {
+ $key = get_key ($opt_n);
+}
- get_options_stdin();
+if (defined $opt_d) {
+ @devices = split (/\s*,\s*/, $opt_d);
+}
+else {
+ @devices = get_devices_clvm ();
+}
+if (!defined $opt_o) {
+ $opt_o = "off";
}
-## get a list of scsi devices. this call will build a list of devices
-## (device_list) by querying clvm for a list of devices that exist in
-## volume groups that have the cluster bit set.
-##
-get_scsi_devices;
+if ($opt_o =~ /^on$/i) {
+ do_action_on ($key, @devices);
+}
+elsif ($opt_o =~ /^off$/i) {
+ do_action_off ($key, @devices);
+}
+elsif ($opt_o =~ /^status/i) {
+ do_action_status ($key, @devices);
+}
+else {
+ log_error ("unknown action '$opt_o'");
+ exit (1);
+}
-if ($opt_u) {
- unfence_node;
-} else {
- fence_node;
+if (defined $opt_f) {
+ close (LOG);
}
More information about the cluster-commits
mailing list