From: Marek 'marx' Grac <mgrac@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [PATCH] fence_zvmip: Port fence agent to fencing library
Date: Mon, 22 Dec 2014 12:25:37 +0100 [thread overview]
Message-ID: <1419247537-6975-1-git-send-email-mgrac@redhat.com> (raw)
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.
Additional fix that makes fence agent work if output information is longer than
MTU.
---
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 | 171 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 183 insertions(+), 110 deletions(-)
delete mode 100644 fence/agents/zvm/fence_zvmip.8
create mode 100644 fence/agents/zvm/fence_zvmip.py
diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py
index 5449373..c122d96 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..797186a
--- /dev/null
+++ b/fence/agents/zvm/fence_zvmip.py
@@ -0,0 +1,171 @@
+#!/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, 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)
+
+ result = fence_action(None, options, set_power_status, get_power_status, get_power_status)
+ sys.exit(result)
+
+if __name__ == "__main__":
+ main()
--
1.9.3
next reply other threads:[~2014-12-22 11:25 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-22 11:25 Marek 'marx' Grac [this message]
-- strict thread matches above, loose matches on Subject: below --
2014-12-22 9:07 [Cluster-devel] [PATCH] fence_zvmip: Port fence agent to fencing library Marek 'marx' Grac
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1419247537-6975-1-git-send-email-mgrac@redhat.com \
--to=mgrac@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).