From bf77062b93a43a2ef288ca8b6e6b0a889c2993c3 Mon Sep 17 00:00:00 2001 From: Marek 'marx' Grac Date: Thu, 29 Aug 2013 16:22:15 +0200 Subject: [PATCH 5/6] fence_brocade: Port fencing agent to fencing library Resolves: rhbz#641632 rhbz#642232 rhbz#841556 --- fence/agents/brocade/Makefile.am | 4 +- fence/agents/brocade/fence_brocade.pl | 322 --------------------------------- fence/agents/brocade/fence_brocade.py | 86 +++++++++ 3 files changed, 88 insertions(+), 324 deletions(-) delete mode 100644 fence/agents/brocade/fence_brocade.pl create mode 100644 fence/agents/brocade/fence_brocade.py diff --git a/fence/agents/brocade/Makefile.am b/fence/agents/brocade/Makefile.am index 3338804..171425f 100644 --- a/fence/agents/brocade/Makefile.am +++ b/fence/agents/brocade/Makefile.am @@ -2,7 +2,7 @@ MAINTAINERCLEANFILES = Makefile.in TARGET = fence_brocade -SRC = $(TARGET).pl +SRC = $(TARGET).py EXTRA_DIST = $(SRC) @@ -11,7 +11,7 @@ sbin_SCRIPTS = $(TARGET) man_MANS = $(TARGET).8 include $(top_srcdir)/make/fencebuild.mk -include $(top_srcdir)/make/fencemanperl.mk +include $(top_srcdir)/make/fenceman.mk clean-local: clean-man rm -f $(TARGET) diff --git a/fence/agents/brocade/fence_brocade.pl b/fence/agents/brocade/fence_brocade.pl deleted file mode 100644 index 4be0436..0000000 --- a/fence/agents/brocade/fence_brocade.pl +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/perl - -use Getopt::Std; -use Net::Telnet (); - -my $ME = $0; - -END { - defined fileno STDOUT or return; - close STDOUT and return; - warn "$ME: failed to close standard output: $!\n"; - $? ||= 1; -} - -# Get the program name from $0 and strip directory names -$_=$0; -s/.*\///; -my $pname = $_; - -$opt_o = 'disable'; # Default fence action - -# WARNING!! Do not add code bewteen "#BEGIN_VERSION_GENERATION" and -# "#END_VERSION_GENERATION" It is generated by the Makefile - -#BEGIN_VERSION_GENERATION -$RELEASE_VERSION=""; -$REDHAT_COPYRIGHT=""; -$BUILD_DATE=""; -#END_VERSION_GENERATION - - -sub usage -{ - print "Usage:\n"; - print "\n"; - print "$pname [options]\n"; - print "\n"; - print "Options:\n"; - print " -a IP address or hostname of switch\n"; - print " -h usage\n"; - print " -l Login name\n"; - print " -n Port number to operate on\n"; - print " -o Action: disable (default), enable or metadata\n"; - print " -p Password for login\n"; - print " -S Script to run to retrieve password\n"; - print " -q quiet mode\n"; - print " -V version\n"; - - exit 0; -} - -sub fail -{ - ($msg) = @_; - print $msg."\n" unless defined $opt_q; - $t->close if defined $t; - exit 1; -} - -sub fail_usage -{ - ($msg)=@_; - print STDERR $msg."\n" if $msg; - print STDERR "Please use '-h' for usage.\n"; - exit 1; -} - -sub version -{ - print "$pname $RELEASE_VERSION $BUILD_DATE\n"; - print "$REDHAT_COPYRIGHT\n" if ( $REDHAT_COPYRIGHT ); - - exit 0; -} - -sub print_metadata -{ -print ' - - -fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while a GFS cluster is running because the connection will block any necessary fencing actions. - -After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action. - -http://www.brocade.com - - - - - Fencing Action - - - - - IP Address or Hostname - - - - - Login Name - - - - - Login password or passphrase - - - - - Script to retrieve password - - - - - Physical plug number or name of virtual machine - - - - - Display help and exit - - - - - - - - - -'; -} - - -if (@ARGV > 0) { - getopts("a:hl:n:o:p:S:qV") || fail_usage ; - - usage if defined $opt_h; - version if defined $opt_V; - - fail_usage "Unknown parameter." if (@ARGV > 0); - - if ((defined $opt_o) && ($opt_o =~ /metadata/i)) { - print_metadata(); - exit 0; - } - - if (defined $opt_S) { - $pwd_script_out = `$opt_S`; - chomp($pwd_script_out); - if ($pwd_script_out) { - $opt_p = $pwd_script_out; - } - } - - fail_usage "No '-a' flag specified." unless defined $opt_a; - fail_usage "No '-n' flag specified." unless defined $opt_n; - fail_usage "No '-l' flag specified." unless defined $opt_l; - fail_usage "No '-p' or '-S' flag specified." unless defined $opt_p; - fail_usage "Unrecognised action '$opt_o' for '-o' flag" - unless $opt_o =~ /^(disable|enable)$/i; - -} else { - get_options_stdin(); - - if ((defined $opt_o) && ($opt_o =~ /metadata/i)) { - print_metadata(); - exit 0; - } - - fail "failed: no IP address" unless defined $opt_a; - fail "failed: no plug number" unless defined $opt_n; - fail "failed: no login name" unless defined $opt_l; - - if (defined $opt_S) { - $pwd_script_out = `$opt_S`; - chomp($pwd_script_out); - if ($pwd_script_out) { - $opt_p = $pwd_script_out; - } - } - - fail "failed: no password" unless defined $opt_p; - fail "failed: unrecognised action: $opt_o" - unless $opt_o =~ /^(disable|enable)$/i; -} - -if ( $opt_o =~ /^(disable|enable)$/i ) -{ - $opt_o = "port".$1; -} - - -# -# Set up and log in -# - -$t = new Net::Telnet; - -$t->open($opt_a); - -$t->waitfor('/login:/'); - -$t->print($opt_l); - -$t->waitfor('/assword:/'); - -$t->print($opt_p); - -$t->waitfor('/\>/'); - - - -# -# Do the command -# - -$cmd = "$opt_o $opt_n"; -$t->print($cmd); - - -# -# Assume here that the word "error" will appear after errors (bad assumption! see next check) -# - -($text, $match) = $t->waitfor('/\>/'); -if ($text =~ /error/) -{ - fail "failed: error from switch\n"; -} - - -# -# Do a portshow on the port and look for the DISABLED string to verify success -# - -$t->print("portshow $opt_n"); -($text, $match) = $t->waitfor('/\>/'); - -if ( $opt_o eq "portdisable" && !($text =~ /DISABLED/) ) -{ - fail "failed: portshow $opt_n does not show DISABLED\n"; -} -elsif ( $opt_o eq "portenable" && ($text =~ /DISABLED/) ) -{ - fail "failed: portshow $opt_n shows DISABLED\n"; -} - - -print "success: $opt_o $opt_n\n" unless defined $opt_q; -exit 0; - -sub get_options_stdin -{ - my $opt; - my $line = 0; - while( defined($in = <>) ) - { - $_ = $in; - chomp; - - # strip leading and trailing whitespace - s/^\s*//; - s/\s*$//; - - # skip comments - next if /^#/; - - $line+=1; - $opt=$_; - next unless $opt; - - ($name,$val)=split /\s*=\s*/, $opt; - - if ( $name eq "" ) - { - print STDERR "parse error: illegal name in option $line\n"; - exit 2; - } - - # DO NOTHING -- this field is used by fenced - elsif ($name eq "agent" ) { } - - # FIXME -- depricated. use "port" instead. - elsif ($name eq "fm" ) - { - (my $dummy,$opt_n) = split /\s+/,$val; - print STDERR "Depricated \"fm\" entry detected. refer to man page.\n"; - } - - elsif ($name eq "ipaddr" ) - { - $opt_a = $val; - } - elsif ($name eq "login" ) - { - $opt_l = $val; - } - - # FIXME -- depreicated residue of old fencing system - elsif ($name eq "name" ) { } - - elsif (($name eq "option" ) || ($name eq "action")) - { - $opt_o = $val; - } - elsif ($name eq "passwd" ) - { - $opt_p = $val; - } - elsif ($name eq "passwd_script") { - $opt_S = $val; - } - elsif ($name eq "port" ) - { - $opt_n = $val; - } - # elsif ($name eq "test" ) - # { - # $opt_T = $val; - # } - } -} diff --git a/fence/agents/brocade/fence_brocade.py b/fence/agents/brocade/fence_brocade.py new file mode 100644 index 0000000..25581fd --- /dev/null +++ b/fence/agents/brocade/fence_brocade.py @@ -0,0 +1,86 @@ +#!/usr/bin/python + +import sys, re, pexpect, exceptions +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import * + +#BEGIN_VERSION_GENERATION +RELEASE_VERSION="New Brocade Agent - test release on steroids" +REDHAT_COPYRIGHT="" +BUILD_DATE="March, 20013" +#END_VERSION_GENERATION + +def get_power_status(conn, options): + conn.send_eol("portCfgShow " + options["--plug"]) + + exp_result = conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) + + show_re = re.compile('^\s*Persistent Disable\s*(ON|OFF)\s*$', re.IGNORECASE) + lines = conn.before.split("\n") + + for x in lines: + res = show_re.search(x) + if (res != None): + # We queried if it is disabled, so we have to negate answer + if res.group(1) == "ON": + return "off" + else: + return "on" + + fail(EC_STATUS) +def set_power_status(conn, options): + action = { + 'on' : "portCfgPersistentEnable", + 'off': "portCfgPersistentDisable" + }[options["--action"]] + + conn.send_eol(action + " " + options["--plug"]) + conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) + +def main(): + device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "fabric_fencing" ] + + atexit.register(atexit_handler) + + all_opt["cmd_prompt"]["default"] = [ "> " ] + + options = check_input(device_opt, process_input(device_opt)) + options["eol"] = "\n" + + docs = { } + docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh" + docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \ +It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \ +connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \ +a GFS cluster is running because the connection will block any necessary fencing actions. \ +\ +After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \ +When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \ +FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action" + docs["vendorurl"] = "http://www.brocade.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + conn = fence_login(options) + + result = fence_action(conn, options, set_power_status, get_power_status, None) + + ## + ## Logout from system + ## + ## In some special unspecified cases it is possible that + ## connection will be closed before we run close(). This is not + ## a problem because everything is checked before. + ###### + try: + conn.send_eol("exit") + conn.close() + except: + pass + + sys.exit(result) + +if __name__ == "__main__": + main() -- 1.7.7.6