Gitweb:
http://git.fedorahosted.org/git/fence-agents.git?p=fence-agents.git;a=com...
Commit: 6f27315c0737a98395b7d905dc289ef3c344630b
Parent: 664ccc6aa2fcd4b79459ca3083f8528969300a78
Author: Marek 'marx' Grac <mgrac(a)redhat.com>
AuthorDate: Fri Nov 25 11:41:05 2011 +0100
Committer: Marek 'marx' Grac <mgrac(a)redhat.com>
CommitterDate: Fri Dec 9 09:44:24 2011 +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()