Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=8a2... Commit: 8a2a70414d7e287f801d31d7b89c9a1de269f936 Parent: 49a5baea19ac2a371439454d1cf01559612b6efe Author: Marek 'marx' Grac mgrac@redhat.com AuthorDate: Fri Nov 25 11:41:05 2011 +0100 Committer: Marek 'marx' Grac mgrac@redhat.com CommitterDate: Thu Jan 12 16:44:34 2012 +0100
fence_rsb: Fence agent ported to fencing library
Fence agent was rewritten to use fencing library. Main benefits are support for ssh connection, XML metadata, automatic man page generation.
Resolves: rhbz#742003 --- fence/agents/lib/fencing.py.py | 2 +- fence/agents/rsb/Makefile.am | 5 +- fence/agents/rsb/fence_rsb.8 | 76 ------ fence/agents/rsb/fence_rsb.py | 491 ++++++++-------------------------------- 4 files changed, 102 insertions(+), 472 deletions(-)
diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index ec84bbc..8be0a61 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -871,7 +871,7 @@ def fence_login(options):
try: re_login = re.compile("(login\s*: )|(Login Name: )|(username: )|(User Name :)", re.IGNORECASE) - re_pass = re.compile("password", re.IGNORECASE) + re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE)
if options.has_key("-z"): command = '%s %s %s %s' % (SSL_PATH, force_ipvx, options["-a"], options["-u"]) diff --git a/fence/agents/rsb/Makefile.am b/fence/agents/rsb/Makefile.am index e8193be..939db98 100644 --- a/fence/agents/rsb/Makefile.am +++ b/fence/agents/rsb/Makefile.am @@ -8,9 +8,10 @@ EXTRA_DIST = $(SRC)
sbin_SCRIPTS = $(TARGET)
-dist_man_MANS = $(TARGET).8 +man_MANS = $(TARGET).8
include $(top_srcdir)/make/fencebuild.mk +include $(top_srcdir)/make/fenceman.mk
-clean-local: +clean-local: clean-man rm -f $(TARGET) diff --git a/fence/agents/rsb/fence_rsb.8 b/fence/agents/rsb/fence_rsb.8 deleted file mode 100644 index d278271..0000000 --- a/fence/agents/rsb/fence_rsb.8 +++ /dev/null @@ -1,76 +0,0 @@ -.TH fence_rsb 8 - -.SH NAME -fence_rsb - I/O Fencing agent for Fujitsu-Siemens RSB - -.SH SYNOPSIS -.B -fence_rsb -[\fIOPTION\fR]... - -.SH DESCRIPTION -fence_rsb is an I/O Fencing agent which can be used with the Fujitsu-Siemens -RSB management interface. It logs into an RSB device via telnet and reboots -the associated machine. Lengthy telnet connections to the RSB device -should be avoided while a GFS cluster is running because the connection -will block any necessary fencing actions. - -fence_rsb accepts options on the command line as well as from stdin. -Fenced sends parameters through stdin when it execs the agent. fence_rsb -can be run by itself with command line options. This is useful for testing. - -Vendor URL: http://www.fujitsu.com -.SH OPTIONS -.TP -\fB-a\fP \fIIPaddress\fR -IP address or hostname of the RSB device. -.TP -\fB-h\fP -Print out a help message describing available options, then exit. -.TP -\fB-l\fP \fIlogin\fR -Login name. -.TP -\fB-n\fP \fItelnet_port\fR -The port number on which the telnet service listens. -.TP -\fB-o\fP \fIaction\fR -The action required. This can be reboot (default), off, on, or status. -.TP -\fB-p\fP \fIpassword\fR -Password for login. -.TP -\fB-S\fP \fIpath\fR -Full path to an executable to generate the password for login. -.TP -\fB-v\fP -Verbose. Print informational messages to standard out. -.TP -\fB-V\fP -Print out a version message, then exit. - -.SH STDIN PARAMETERS -.TP -\fIagent = < param >\fR -This option is used by fence_node(8) and is ignored by fence_rsb. -.TP -\fIipaddr = < hostname | ip >\fR -IP address or hostname of the device. -.TP -\fItelnet_port = < port number >\fR -The port number on which the telnet service listens. -.TP -\fIlogin = < param >\fR -Login name. -.TP -\fIoption = < param >\fR -The action required. This can be reboot (default), off, on, or status. -.TP -\fIpasswd = < param >\fR -Password for login. -.TP -\fIpasswd_script = < param >\fR -Full path to an executable to generate the password for login. - -.SH SEE ALSO -fence(8), fence_node(8) diff --git a/fence/agents/rsb/fence_rsb.py b/fence/agents/rsb/fence_rsb.py old mode 100644 new mode 100755 index 759ae2d..fe1ec60 --- a/fence/agents/rsb/fence_rsb.py +++ b/fence/agents/rsb/fence_rsb.py @@ -1,18 +1,8 @@ #!/usr/bin/python
-import getopt, sys -import os -import socket -import time -import atexit - -from telnetlib import Telnet - -TELNET_TIMEOUT=30 #How long to wait for a response from a telnet try -MAX_TRIES = 20 - -# WARNING!! Do not add code bewteen "#BEGIN_VERSION_GENERATION" and -# "#END_VERSION_GENERATION" It is generated by the Makefile +import sys, re, pexpect, exceptions +sys.path.append("@FENCEAGENTSLIBDIR@") +from fencing import *
#BEGIN_VERSION_GENERATION RELEASE_VERSION="" @@ -20,389 +10,104 @@ REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION
-def usage(): - print "Usage:" - print "fence_rsb [options]" - print "Options:" - print " -a <ipaddress> ip or hostname of rsb" - print " -h print out help" - print " -l [login] login name" - print " -n [telnet port] telnet port" - print " -p [password] password" - print " -S [path] script to run to retrieve password" - print " -o [action] reboot (default), off, on, or status" - print " -v Verbose Verbose mode" - print " -V Print Version, then exit" - - sys.exit (0) - -def version(): - print "fence_rsb %s %s\n" % (RELEASE_VERSION, BUILD_DATE) - print "%s\n" % REDHAT_COPYRIGHT - sys.exit(0) +def get_power_status(conn, options): + try: + conn.send("2") + conn.log_expect(options, options["-c"], int(options["-Y"])) + status = re.compile("Power Status : (on|off)", re.IGNORECASE).search(conn.before).group(1) + conn.send("0") + conn.log_expect(options, options["-c"], int(options["-Y"])) + + return (status.lower().strip()) + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT) + +def set_power_status(conn, options): + action = { + 'on' : "4", + 'off': "1" + }[options["-o"]]
-def atexit_handler(): try: - sys.stdout.close() - os.close(1) - except IOError: - sys.stderr.write("%s failed to close standard output\n"%(sys.argv[0])) - sys.exit(1) + conn.send("2") + conn.log_expect(options, options["-c"], int(options["-Y"])) + conn.sendline(action) + conn.log_expect(options, ["want to power off", "'yes' or 'no'"], int(options["-Y"])) + conn.send("yes\r") + conn.log_expect(options, "any key to continue", int(options["-g"])) + conn.send("\r") + conn.log_expect(options, options["-c"], int(options["-Y"])) + conn.sendline("0") + conn.log_expect(options, options["-c"], int(options["-Y"])) + except pexpect.EOF: + fail(EC_CONNECTION_LOST) + except pexpect.TIMEOUT: + fail(EC_TIMED_OUT)
def main(): - depth = 0 - POWER_OFF = 0 - POWER_ON = 1 - POWER_STATUS = 2 - POWER_REBOOT = 3 - - STATUS_ON = 0 - STATUS_OFF = 2 - - power_command_issued = 0 - - address = "" - login = "" - passwd = "" - passwd_script = "" - action = POWER_REBOOT #default action - telnet_port = 3172 - verbose = False - power_state = None - - standard_err = 2 - - result = 0 - - completed_action = 0 - - #set up regex list - USERNAME = 0 - PASSWORD = 1 - PROMPT = 2 - STATE = 3 - ERROR = 4 - CONT = 5 - CONFIRM = 6 - DONE = 7 - - regex_list = list() - regex_list.append("user name\s*:") - regex_list.append("pass phrase\s*:") - regex_list.append("[Ee]nter\s+[Ss]election[^\r\n]*:") - regex_list.append("[pP]ower Status\s*:") - regex_list.append("[Ee]rror\s*:") - regex_list.append("[Pp]ress any key to continue") - regex_list.append("really want to") - regex_list.append("CLOSING TELNET CONNECTION") - - atexit.register(atexit_handler) - - if len(sys.argv) > 1: - try: - opts, args = getopt.getopt(sys.argv[1:], "a:hl:n:o:p:S:vV", ["help", "output="]) - except getopt.GetoptError: - #print help info and quit - usage() - sys.exit(2) - - for o, a in opts: - if o == "-v": - verbose = True - if o == "-V": - version() - if o in ("-h", "--help"): - usage() - sys.exit(0) - if o == "-l": - login = a - if o == "-n": - telnet_port = a - if o == "-p": - passwd = a - if o == "-S": - passwd_script = a - if o == "-o": - a_lower=a.lower() - if a_lower == "off": - action = POWER_OFF - elif a_lower == "on": - action = POWER_ON - elif a_lower == "status": - action = POWER_STATUS - elif a_lower == "reboot": - action = POWER_REBOOT - else: - usage() - sys.exit(1) - if o == "-a": - address = a - if address == "" or login == "" or (passwd == "" and passwd_script == ""): - usage() - sys.exit(1) - - else: #Take args from stdin... - params = {} - #place params in dict - for line in sys.stdin: - val = line.split("=") - if len(val) == 2: - params[val[0].strip()] = val[1].strip() - - try: - address = params["ipaddr"] - except KeyError, e: - os.write(standard_err, "FENCE: Missing ipaddr param for fence_rsb...exiting") - sys.exit(1) - - try: - login = params["login"] - except KeyError, e: - os.write(standard_err, "FENCE: Missing login param for fence_rsb...exiting") - sys.exit(1) - - try: - if 'passwd' in params: - passwd = params["passwd"] - if 'passwd_script' in params: - passwd_script = params['passwd_script'] - if passwd == "" and passwd_script == "": - raise Exception, "missing password" - except KeyError, e: - os.write(standard_err, "FENCE: Missing passwd param for fence_rsb...exiting") - sys.exit(1) - - try: - telnet_port = params["telnet_port"] - except KeyError, e: - pass - - try: - a = params["option"] - a_lower=a.lower() - if a_lower == "off": - action = POWER_OFF - elif a_lower == "on": - action = POWER_ON - elif a_lower == "reboot": - action = POWER_REBOOT - except KeyError, e: - action = POWER_REBOOT - - ####End of stdin section - - - # retrieve passwd from passwd_script (if specified) - passwd_scr = '' - if len(passwd_script): - try: - if not os.access(passwd_script, os.X_OK): - raise Exception, 'script not executable' - p = os.popen(passwd_script, 'r', 1024) - passwd_scr = p.readline().strip() - if p.close() != None: - raise Exception, 'script failed' - except: - sys.stderr.write('password-script "%s" failed\n' % passwd_script) - passwd_scr = '' - - if passwd == "" and passwd_scr == "": - sys.stderr.write('password not available, exiting...') - sys.exit(1) - elif passwd == passwd_scr: - pass - elif passwd and passwd_scr: - # execute self, with password_scr as passwd, - # if that fails, continue with "passwd" argument as password - if len(sys.argv) > 1: - comm = sys.argv[0] - skip_next = False - for w in sys.argv[1:]: - if skip_next: - skip_next = False - elif w in ['-p', '-S']: - skip_next = True - else: - comm += ' ' + w - comm += ' -p ' + passwd_scr - ret = os.system(comm) - if ret != -1 and os.WIFEXITED(ret) and os.WEXITSTATUS(ret) == 0: - # success - sys.exit(0) - else: - sys.stderr.write('Use of password from "passwd_script" failed, trying "passwd" argument\n') - else: # use stdin - p = os.popen(sys.argv[0], 'w', 1024) - for par in params: - if par not in ['passwd', 'passwd_script']: - p.write(par + '=' + params[par] + '\n') - p.write('passwd=' + passwd_scr + '\n') - p.flush() - if p.close() == None: - # success - sys.exit(0) - else: - sys.stderr.write('Use of password from "passwd_script" failed, trying "passwd" argument\n') - elif passwd_scr: - passwd = passwd_scr - # passwd all set - - - - try: - telnet_port = int(telnet_port) - except: - os.write(standard_err, ("FENCE: Invalid telnet port: %s\n" % telnet_port)) - sys.exit(1) - - ##Time to open telnet session and log in. - try: - sock = Telnet(address.strip(), telnet_port) - except socket.error, (errno, msg): - my_msg = "FENCE: A problem was encountered opening a telnet session with " + address - os.write(standard_err, my_msg) - os.write(standard_err, ("FENCE: Error number: %d -- Message: %s\n" % (errno, msg))) - os.write(standard_err, "Firewall issue? Correct address?\n") - sys.exit(1) - - if verbose: - #sock.set_debuglevel(10000) - print "socket open to %s %d\n" % (address, telnet_port) - - tries = MAX_TRIES - while 1: - i, mo, txt = sock.expect(regex_list, TELNET_TIMEOUT) - if i == ERROR: - os.write(standard_err,("FENCE: An error was encountered when communicating with the rsb device at %s" % address)) - buf = sock.read_eager() - os.write(standard_err,("FENCE: The error message is - %s" % txt + " " + buf)) - sock.close() - sys.exit(1) - - try: - buf = sock.read_eager() - except EOFError: - if completed_action == 1: - # action was completed succesfully, connection closed is OK - sys.exit(result) - else: - raise - - if i == USERNAME: - if verbose: - print "Sending login: %s\n" % login - sock.write(login + "\r") - - elif i == PASSWORD: - if verbose: - print "Sending password: %s\n" % passwd - sock.write(passwd + "\r") - - elif i == CONT: - if verbose: - print "Sending continue char..." - sock.write("\r") - time.sleep(2) - - elif i == CONFIRM: - if verbose: - print "Confirming..." - sock.write("yes\r") - - elif i == PROMPT: - if verbose: - print "Evaluating prompt...\n" - - if depth == 0: - sock.write("2\r") - depth += 1 - elif depth == 1: - if action == POWER_OFF or action == POWER_REBOOT: - if power_command_issued == 0: - if verbose: - print "Sending power off %s" % address - sock.write("1\r") - power_command_issued += 1 - time.sleep(2) - elif power_command_issued and power_state == 0: - if verbose: - print "Power off was successful" - if action == POWER_OFF: - completed_action = 1 - depth += 1 - sock.write("0\r") - else: - action = POWER_ON - power_command_issued = 0 - sock.write("\r") - elif tries > 0: - if verbose: - print "Waiting for power off to complete" - tries -= 1 - sock.write("\r") - time.sleep(2) - else: - os.write(standard_err, "FENCE: Unable to power off server") - depth += 1 - sock.write("0\r") - - elif action == POWER_ON: - if power_command_issued == 0: - if verbose: - print "Sending power on %s" % address - sock.write("4\r") - power_command_issued += 1 - time.sleep(2) - elif power_command_issued and power_state == 1: - if verbose: - print "Power on was successful" - completed_action = 1 - depth += 1 - sock.write("0\r") - elif tries > 0: - if verbose: - print "Waiting for power on to complete" - tries -= 1 - sock.write("\r") - time.sleep(2) - else: - os.write(standard_err, "FENCE: Unable to power on server") - depth += 1 - sock.write("0\r") - else: - sock.write("0\r") - - elif i == STATE: - if buf.find(" On") != (-1): - power_state = 1 - elif buf.find(" Off") != (-1): - power_state = 0 - else: - power_state = None - - if action == POWER_STATUS: - if verbose: - print "Determining power state..." - if power_state == 1: - print "Server is On" - result = STATUS_ON - elif power_state == 0: - print "Server is Off" - result = STATUS_OFF - else: - os.write(standard_err, ("FENCE: Cannot determine power state: %s" % buf)) - sys.exit(1) - depth = 2 - completed_action = 1 - - elif i == DONE: - break - - else: - sock.write("\r") - - sock.close() - sys.exit(result) + device_opt = [ "help", "version", "agent", "quiet", "verbose", "debug", + "action", "ipaddr", "login", "passwd", "passwd_script", + "secure", "identity_file", "separator", "cmd_prompt", + "inet4_only", "inet6_only", "ipport", "telnet_port", + "power_timeout", "shell_timeout", "login_timeout", "power_wait" ] + + atexit.register(atexit_handler) + all_opt["telnet_port"] = { + "getopt" : "n:", + "longopt" : "telnet_port", + "help" : "-n TCP port to use (deprecated, use -u)", + "required" : "0", + "shortdesc" : "TCP port to use for connection with device (default is 3172 for telnet)", + "order" : 1 + } + all_opt["cmd_prompt"]["default"] = "to quit:" + + opt = process_input(device_opt) + # option -n for backward compatibility (-n is normally port no) + if 1 == opt.has_key("-n"): + opt["-u"] = opt["-n"] + + # set default port for telnet only + if 0 == opt.has_key("-x") and 0 == opt.has_key("-u"): + opt["-u"] = 3172 + options = check_input(device_opt, opt) + + docs = { } + docs["shortdesc"] = "I/O Fencing agent for Fujitsu-Siemens RSB" + docs["longdesc"] = "fence_rsb is an I/O Fencing agent \ +which can be used with the Fujitsu-Siemens RSB management interface. It logs \ +into device via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh \ +connections should be avoided while a GFS cluster is running because the connection \ +will block any necessary fencing actions." + docs["vendorurl"] = "http://www.fujitsu.com" + show_docs(options, docs) + + ## + ## Operate the fencing device + #### + print options["-u"] + + 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.sendline("0") + conn.close() + except exceptions.OSError: + pass + except pexpect.ExceptionPexpect: + pass + + sys.exit(result)
if __name__ == "__main__": - main() + main()
cluster-commits@lists.fedorahosted.org