fence-agents: master - fencing: Short options can be misinterpreted
by Marek Grác
Gitweb: http://git.fedorahosted.org/git/?p=fence-agents.git;a=commitdiff;h=60333a...
Commit: 60333a24b22438ba33184aa803eb2386fca0e0ad
Parent: f5401fc8dad9a39da0a279b7d55149dc0ebcba26
Author: Marek 'marx' Grac <mgrac(a)redhat.com>
AuthorDate: Wed Jan 7 14:11:13 2015 +0100
Committer: Marek 'marx' Grac <mgrac(a)redhat.com>
CommitterDate: Wed Jan 7 14:11:13 2015 +0100
fencing: Short options can be misinterpreted
If there are several entries in all_opt that have same short getopt. It
is possible that they are handled incorrectly and they are stored under same
key in 'options' variable.
This update fixes this problem for cases when the other of all_opt entries should
not be present at all. E.g. -d is used for vmware_type and snmp_version, and they are
not allowed at same time.
---
fence/agents/lib/fencing.py.py | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py
index 83bbfcd..9172782 100644
--- a/fence/agents/lib/fencing.py.py
+++ b/fence/agents/lib/fencing.py.py
@@ -1195,6 +1195,7 @@ def _parse_input_stdin(avail_opt):
return opt
def _parse_input_cmdline(avail_opt):
+ filtered_opts = {}
(getopt_string, longopt_list) = _prepare_getopt_args(avail_opt)
try:
@@ -1202,12 +1203,15 @@ def _parse_input_cmdline(avail_opt):
except getopt.GetoptError, error:
fail_usage("Parse error: " + error.msg)
+ for opt in avail_opt:
+ filtered_opts.update({opt : all_opt[opt]})
+
# Short and long getopt names are changed to consistent "--" + long name (e.g. --username)
long_opts = {}
for arg_name in dict(entered_opt).keys():
- all_key = [key for (key, value) in all_opt.items() \
+ all_key = [key for (key, value) in filtered_opts.items() \
if "--" + value.get("longopt", "") == arg_name or "-" + value.get("getopt", "").rstrip(":") == arg_name][0]
- long_opts["--" + all_opt[all_key]["longopt"]] = dict(entered_opt)[arg_name]
+ long_opts["--" + filtered_opts[all_key]["longopt"]] = dict(entered_opt)[arg_name]
return long_opts
9 years, 3 months
fence-agents: master - fence_zvmip: Port fence agent to fencing library
by Marek Grác
Gitweb: http://git.fedorahosted.org/git/?p=fence-agents.git;a=commitdiff;h=f5401f...
Commit: f5401fc8dad9a39da0a279b7d55149dc0ebcba26
Parent: 028f0bba76b2171a3c25f5d755209ecb29c8053d
Author: Marek 'marx' Grac <mgrac(a)redhat.com>
AuthorDate: Mon Jan 5 10:15:36 2015 +0100
Committer: Marek 'marx' Grac <mgrac(a)redhat.com>
CommitterDate: Mon Jan 5 10:18:34 2015 +0100
fence_zvmip: Port fence agent to fencing library
This rewrite adds a correct result codes, support for 'list' action and
autogenerated manual page. The original code is still part of codebase as
new agent requires additional testing.
---
fence/agents/lib/fencing.py.py | 4 +
fence/agents/zvm/Makefile.am | 26 ++----
fence/agents/zvm/fence_zvmip.8 | 92 -------------------
fence/agents/zvm/fence_zvmip.py | 172 +++++++++++++++++++++++++++++++++++
tests/data/metadata/fence_zvmip.xml | 165 +++++++++++++++++++++++++--------
5 files changed, 310 insertions(+), 149 deletions(-)
diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py
index a8ea448..83bbfcd 100644
--- a/fence/agents/lib/fencing.py.py
+++ b/fence/agents/lib/fencing.py.py
@@ -7,6 +7,7 @@ import subprocess
import threading
import shlex
import exceptions
+import socket
import __main__
## do not add code here.
@@ -805,6 +806,9 @@ def fence_action(connection, options, set_power_fn, get_power_fn, get_outlet_lis
except pycurl.error, ex:
logging.error("%s\n", str(ex))
fail(EC_TIMED_OUT)
+ except socket.timeout, ex:
+ logging.error("%s\n", str(ex))
+ fail(EC_TIMED_OUT)
return result
diff --git a/fence/agents/zvm/Makefile.am b/fence/agents/zvm/Makefile.am
index 62eb862..a29754d 100644
--- a/fence/agents/zvm/Makefile.am
+++ b/fence/agents/zvm/Makefile.am
@@ -2,26 +2,16 @@ MAINTAINERCLEANFILES = Makefile.in
TARGET = fence_zvmip
-sbin_PROGRAMS = fence_zvm fence_zvmip
+SRC = $(TARGET).py
-noinst_HEADERS = fence_zvm.h
+EXTRA_DIST = $(SRC)
-fence_zvm_SOURCES = fence_zvm.c
-fence_zvm_CFLAGS = -D_GNU_SOURCE
+sbin_SCRIPTS = $(TARGET)
-fence_zvmip_SOURCES = fence_zvmip.c
-fence_zvmip_CFLAGS = -D_GNU_SOURCE
+man_MANS = $(TARGET).8
-dist_man_MANS = fence_zvm.8 fence_zvmip.8
+FENCE_TEST_ARGS = -l test -p test -a test -n 1
-#include $(top_srcdir)/make/fencemanc.mk
-
-clean-local:
- rm -f $(sbin_PROGRAMS)
-
-FENCE_TEST_ARGS = -n test -a test -p test -u test
-
-include $(top_srcdir)/make/agentccheck.mk
-
-# we do not test fence_zvm because it can be compiled only on specific architecture
-check: xml-check.fence_zvmip delay-check.fence_zvmip
\ No newline at end of file
+include $(top_srcdir)/make/fencebuild.mk
+include $(top_srcdir)/make/fenceman.mk
+include $(top_srcdir)/make/agentpycheck.mk
diff --git a/fence/agents/zvm/fence_zvmip.8 b/fence/agents/zvm/fence_zvmip.8
deleted file mode 100644
index 6b01425..0000000
--- a/fence/agents/zvm/fence_zvmip.8
+++ /dev/null
@@ -1,92 +0,0 @@
-.TH fence_zvmip 8
-
-.SH NAME
-fence_zvmip - Power Fencing agent for GFS on System z z/VM Clusters using IP interface to SMAPI
-
-.SH SYNOPSIS
-.B
-fence_zvmip
-[\fIOPTION\fR]...
-
-.SH DESCRIPTION
-fence_zvmip is a Power Fencing agent used on a GFS virtual machine in a System z z/VM cluster.
-It uses the TCP/IP SMAPI interface to recycle an active image.
-
-fence_zvmip accepts options on the command line as well as from stdin.
-fence_node sends the options through stdin when it execs the agent.
-fence_zvmip can be run by itself with command line options which is useful
-for testing.
-
-Vendor URL: http://www.sinenomine.net
-
-.SH OPTIONS
-.TP
-\fB-o --action\fP
-Fencing action: "off" - deactivate virtual machine; "on" - activate virtual machine; "metadata" - display device metadata" - describe fence agent parameters; "status" - state of virtual machine
-.TP
-\fB--delay\fP \fIseconds\fP
-Time to delay fencing action in seconds
-.TP
-\fB-n --plug\fP \fItarget\fP
-Name of target virtual machine to fence
-.TP
-\fB-h --help\fP
-Print out a help message describing available options, then exit.
-.TP
-\fB-a --ip\fP \fIsmapi Server\fP
-Host name or IP address of SMAPI server
-.TP
-\fB-u --username\fP \fISMAPI authorized user\fP
-Name of an authorized SMAPI user
-.TP
-\fB-p --password\fP \fISMAPI authorized user's password\fP
-Password of the authorized SMAPI user
-.TP
-\fB-t --timeout\fP \fIRecycle timeout\fP
-Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being
-forcibly terminated. Currently this is ignored.
-.TP
-\fB-h --help\fP
-Display usage information
-
-.SH STDIN PARAMETERS
-.TP
-\fIagent = < param >\fP
-This option is used by fence_node(8) and is ignored by fence_zvmip.
-.TP
-\fIaction = < action >\fP
-Fencing action: "off" - deactivate virtual machine; "on" - activate virtual machine; "metadata" - display device metadata" - describe fence agent parameters; "status" - state of virtual machine
-.TP
-\fIplug = < plug >\fP
-Name of virtual machine to recycle.
-.TP
-\fIipaddr = < server host name or IP address >\fP
-Host name or IP address of SMAPI server
-.TP
-\fIlogin = < SMAPI authorized user >\fP
-Name of an authorized SMAPI user
-.TP
-\fIpasswd = < SMAPI authorized user's password >\fP
-Password of the authorized SMAPI user
-.TP
-\fItimeout = < shutdown timeout >\fP
-Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being
-forcibly terminated. Currently this is ignored.
-
-.SH SEE ALSO
-fence(8), fenced(8), fence_node(8)
-
-.SH NOTES
-To use this agent the z/VM SMAPI service needs to be configured to allow the virtual
-machine running this agent to connect to it and issue the image_recycle operation.
-This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look
-something similar to this:
-
-.nf
-Column 1 Column 66 Column 131
-| | |
-V V V
-XXXXXXXX ALL IMAGE_OPERATIONS
-.fi
-
-Where XXXXXXX is the name of the virtual machine used in the authuser field of the request.
diff --git a/fence/agents/zvm/fence_zvmip.py b/fence/agents/zvm/fence_zvmip.py
new file mode 100644
index 0000000..63f7fa7
--- /dev/null
+++ b/fence/agents/zvm/fence_zvmip.py
@@ -0,0 +1,172 @@
+#!/usr/bin/python -tt
+
+import sys
+import atexit
+import socket
+import struct
+import logging
+sys.path.append("@FENCEAGENTSLIBDIR@")
+from fencing import *
+from fencing import fail, fail_usage, run_delay, EC_LOGIN_DENIED, EC_TIMED_OUT
+
+#BEGIN_VERSION_GENERATION
+RELEASE_VERSION=""
+REDHAT_COPYRIGHT=""
+BUILD_DATE=""
+#END_VERSION_GENERATION
+
+INT4 = 4
+
+def open_socket(options):
+ try:
+ if "--inet6-only" in options:
+ protocol = socket.AF_INET6
+ elif "--inet4-only" in options:
+ protocol = socket.AF_INET
+ else:
+ protocol = 0
+ (_, _, _, _, addr) = socket.getaddrinfo( \
+ options["--ip"], options["--ipport"], protocol,
+ 0, socket.IPPROTO_TCP, socket.AI_PASSIVE
+ )[0]
+ except socket.gaierror:
+ fail(EC_LOGIN_DENIED)
+
+ conn = socket.socket()
+ conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ conn.settimeout(float(options["--shell-timeout"]))
+ try:
+ conn.connect(addr)
+ except socket.error:
+ fail(EC_LOGIN_DENIED)
+
+ return conn
+
+def smapi_pack_string(string):
+ return struct.pack("!i%ds" % (len(string)), len(string), string)
+
+def prepare_smapi_command(options, smapi_function, additional_args):
+ packet_size = 3*INT4 + len(smapi_function) + len(options["--username"]) + len(options["--password"])
+ for arg in additional_args:
+ packet_size += INT4 + len(arg)
+
+ command = struct.pack("!i", packet_size)
+ command += smapi_pack_string(smapi_function)
+ command += smapi_pack_string(options["--username"])
+ command += smapi_pack_string(options["--password"])
+ for arg in additional_args:
+ command += smapi_pack_string(arg)
+
+ return command
+
+def get_power_status(conn, options):
+ del conn
+
+ # '*' = list all active images
+ (return_code, reason_code, images_active) = \
+ get_list_of_images(options, "Image_Status_Query", "*")
+ logging.debug("Image_Status_Query results are (%d,%d)", return_code, reason_code)
+ (return_code, reason_code, images_defined) = \
+ get_list_of_images(options, "Image_Name_Query_DM", options["--username"])
+ logging.debug("Image_Name_Query_DM results are (%d,%d)", return_code, reason_code)
+
+ if ["list", "monitor"].count(options["--action"]) == 1:
+ return dict([(i, ("", "on" if i in images_active else "off")) for i in images_defined])
+ else:
+ status = "error"
+ if options["--plug"].upper() in images_defined:
+ if options["--plug"].upper() in images_active:
+ status = "on"
+ else:
+ status = "off"
+ return status
+
+def set_power_status(conn, options):
+ conn = open_socket(options)
+
+ packet = None
+ if options["--action"] == "on":
+ packet = prepare_smapi_command(options, "Image_Activate", [options["--plug"]])
+ elif options["--action"] == "off":
+ packet = prepare_smapi_command(options, "Image_Deactivate", [options["--plug"], "IMMED"])
+ conn.send(packet)
+
+ request_id = struct.unpack("!i", conn.recv(INT4))[0]
+ (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4))
+ logging.debug("Image_(De)Activate results are (%d,%d)", return_code, reason_code)
+
+ conn.close()
+ return
+
+def get_list_of_images(options, command, data_as_plug):
+ conn = open_socket(options)
+
+ packet = prepare_smapi_command(options, command, [data_as_plug])
+ conn.send(packet)
+
+ request_id = struct.unpack("!i", conn.recv(INT4))[0]
+ (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4))
+ images = set()
+
+ if output_len > 3*INT4:
+ array_len = struct.unpack("!i", conn.recv(INT4))[0]
+ data = ""
+
+ while True:
+ read_data = conn.recv(1024, socket.MSG_WAITALL)
+ data += read_data
+ if array_len == len(data):
+ break
+ elif not read_data:
+ logging.error("Failed: Not enough data read from socket")
+ fail(EC_TIMED_OUT)
+
+ parsed_len = 0
+ while parsed_len < array_len:
+ string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4])[0]
+ parsed_len += INT4
+ image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len])[0]
+ parsed_len += string_len
+ images.add(image_name)
+
+ conn.close()
+ return (return_code, reason_code, images)
+
+def main():
+ device_opt = ["ipaddr", "login", "passwd", "port", "method"]
+
+ atexit.register(atexit_handler)
+
+ all_opt["ipport"]["default"] = "44444"
+ all_opt["shell_timeout"]["default"] = "5.0"
+ options = check_input(device_opt, process_input(device_opt))
+
+ if len(options.get("--plug", "")) > 8:
+ fail_usage("Failed: Name of image can not be longer than 8 characters")
+
+ docs = {}
+ docs["shortdesc"] = "Fence agent for use with z/VM Virtual Machines"
+ docs["longdesc"] = """The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP
+
+To use this agent the z/VM SMAPI service needs to be configured to allow the virtual machine running this agent to connect to it and issue
+the image_recycle operation. This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look something similar to
+this:
+
+Column 1 Column 66 Column 131
+
+ | | |
+ V V V
+
+XXXXXXXX ALL IMAGE_OPERATIONS
+
+Where XXXXXXX is the name of the virtual machine used in the authuser field of the request.
+"""
+ docs["vendorurl"] = "http://www.ibm.com"
+ show_docs(options, docs)
+
+ run_delay(options)
+ result = fence_action(None, options, set_power_status, get_power_status, get_power_status)
+ sys.exit(result)
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/data/metadata/fence_zvmip.xml b/tests/data/metadata/fence_zvmip.xml
index 7791303..75d90c4 100644
--- a/tests/data/metadata/fence_zvmip.xml
+++ b/tests/data/metadata/fence_zvmip.xml
@@ -1,51 +1,138 @@
<?xml version="1.0" ?>
-<resource-agent name="fence_zvmip" shortdesc="Fence agent for use with z/VM Virtual Machines">
-<longdesc>The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP</longdesc>
+<resource-agent name="fence_zvmip" shortdesc="Fence agent for use with z/VM Virtual Machines" >
+<longdesc>The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP
+
+To use this agent the z/VM SMAPI service needs to be configured to allow the virtual machine running this agent to connect to it and issue
+the image_recycle operation. This involves updating the VSMWORK1 AUTHLIST VMSYS:VSMWORK1. file. The entry should look something similar to
+this:
+
+Column 1 Column 66 Column 131
+
+ | | |
+ V V V
+
+XXXXXXXX ALL IMAGE_OPERATIONS
+
+Where XXXXXXX is the name of the virtual machine used in the authuser field of the request.
+</longdesc>
<vendor-url>http://www.ibm.com</vendor-url>
<parameters>
- <parameter name="port" unique="1" required="1">
- <getopt mixed="-n, --plug" />
- <content type="string" />
- <shortdesc lang="en">Name of the Virtual Machine to be fenced</shortdesc>
- </parameter>
- <parameter name="ipaddr" unique="1" required="1">
- <getopt mixed="-i, --ip" />
- <content type="string" />
- <shortdesc lang="en">IP Name or Address of SMAPI Server</shortdesc>
- </parameter>
- <parameter name="login" unique="1" required="1">
- <getopt mixed="-u, --username" />
- <content type="string" />
- <shortdesc lang="en">Name of authorized SMAPI user</shortdesc>
- </parameter>
- <parameter name="passwd" unique="1" required="1">
- <getopt mixed="-p, --password" />
- <content type="string" />
- <shortdesc lang="en">Password of authorized SMAPI user</shortdesc>
- </parameter>
- <parameter name="action" unique="1" required="0">
- <getopt mixed="-o, --action" />
- <content type="string" default="off" />
- <shortdesc lang="en">Fencing action</shortdesc>
- </parameter>
- <parameter name="delay" unique="1" required="0">
- <getopt mixed="--delay" />
- <content type="string" default="0" />
- <shortdesc lang="en">Time to delay fencing action in seconds</shortdesc>
- </parameter>
- <parameter name="usage" unique="1" required="0">
+ <parameter name="action" unique="0" required="1">
+ <getopt mixed="-o, --action=[action]" />
+ <content type="string" default="reboot" />
+ <shortdesc lang="en">Fencing Action</shortdesc>
+ </parameter>
+ <parameter name="inet4_only" unique="0" required="0">
+ <getopt mixed="-4, --inet4-only" />
+ <content type="boolean" />
+ <shortdesc lang="en">Forces agent to use IPv4 addresses only</shortdesc>
+ </parameter>
+ <parameter name="inet6_only" unique="0" required="0">
+ <getopt mixed="-6, --inet6-only" />
+ <content type="boolean" />
+ <shortdesc lang="en">Forces agent to use IPv6 addresses only</shortdesc>
+ </parameter>
+ <parameter name="ipaddr" unique="0" required="1">
+ <getopt mixed="-a, --ip=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP Address or Hostname</shortdesc>
+ </parameter>
+ <parameter name="ipport" unique="0" required="0">
+ <getopt mixed="-u, --ipport=[port]" />
+ <content type="string" default="44444" />
+ <shortdesc lang="en">TCP/UDP port to use for connection with device</shortdesc>
+ </parameter>
+ <parameter name="login" unique="0" required="1">
+ <getopt mixed="-l, --username=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Login Name</shortdesc>
+ </parameter>
+ <parameter name="method" unique="0" required="0">
+ <getopt mixed="-m, --method=[method]" />
+ <content type="select" default="onoff" >
+ <option value="onoff" />
+ <option value="cycle" />
+ </content>
+ <shortdesc lang="en">Method to fence (onoff|cycle)</shortdesc>
+ </parameter>
+ <parameter name="passwd" unique="0" required="0">
+ <getopt mixed="-p, --password=[password]" />
+ <content type="string" />
+ <shortdesc lang="en">Login password or passphrase</shortdesc>
+ </parameter>
+ <parameter name="passwd_script" unique="0" required="0">
+ <getopt mixed="-S, --password-script=[script]" />
+ <content type="string" />
+ <shortdesc lang="en">Script to retrieve password</shortdesc>
+ </parameter>
+ <parameter name="port" unique="0" required="1">
+ <getopt mixed="-n, --plug=[id]" />
+ <content type="string" />
+ <shortdesc lang="en">Physical plug number, name of virtual machine or UUID</shortdesc>
+ </parameter>
+ <parameter name="verbose" unique="0" required="0">
+ <getopt mixed="-v, --verbose" />
+ <content type="boolean" />
+ <shortdesc lang="en">Verbose mode</shortdesc>
+ </parameter>
+ <parameter name="debug" unique="0" required="0">
+ <getopt mixed="-D, --debug-file=[debugfile]" />
+ <content type="string" />
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
+ </parameter>
+ <parameter name="version" unique="0" required="0">
+ <getopt mixed="-V, --version" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display version information and exit</shortdesc>
+ </parameter>
+ <parameter name="help" unique="0" required="0">
<getopt mixed="-h, --help" />
- <content type="boolean" />
- <shortdesc lang="en">Print usage</shortdesc>
+ <content type="boolean" />
+ <shortdesc lang="en">Display help and exit</shortdesc>
+ </parameter>
+ <parameter name="separator" unique="0" required="0">
+ <getopt mixed="-C, --separator=[char]" />
+ <content type="string" default="," />
+ <shortdesc lang="en">Separator for CSV created by operation list</shortdesc>
+ </parameter>
+ <parameter name="delay" unique="0" required="0">
+ <getopt mixed="--delay=[seconds]" />
+ <content type="string" default="0" />
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
+ </parameter>
+ <parameter name="login_timeout" unique="0" required="0">
+ <getopt mixed="--login-timeout=[seconds]" />
+ <content type="string" default="5" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
+ </parameter>
+ <parameter name="power_timeout" unique="0" required="0">
+ <getopt mixed="--power-timeout=[seconds]" />
+ <content type="string" default="20" />
+ <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="power_wait" unique="0" required="0">
+ <getopt mixed="--power-wait=[seconds]" />
+ <content type="string" default="0" />
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="shell_timeout" unique="0" required="0">
+ <getopt mixed="--shell-timeout=[seconds]" />
+ <content type="string" default="5.0" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
+ </parameter>
+ <parameter name="retry_on" unique="0" required="0">
+ <getopt mixed="--retry-on=[attempts]" />
+ <content type="string" default="1" />
+ <shortdesc lang="en">Count of attempts to retry power on</shortdesc>
</parameter>
</parameters>
<actions>
+ <action name="on" automatic="0"/>
<action name="off" />
- <action name="on" automatic="0" />
+ <action name="reboot" />
+ <action name="status" />
<action name="list" />
- <action name="metadata" />
<action name="monitor" />
- <action name="status" />
- <action name="reboot" />
+ <action name="metadata" />
</actions>
</resource-agent>
9 years, 4 months