summaryrefslogtreecommitdiffstats
path: root/agents/zvm
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--agents/zvm/fence_zvm.c1056
-rw-r--r--agents/zvm/fence_zvm.h583
-rw-r--r--agents/zvm/fence_zvm_man_page88
-rw-r--r--agents/zvm/fence_zvmip.c1001
-rw-r--r--agents/zvm/fence_zvmip.py226
5 files changed, 2954 insertions, 0 deletions
diff --git a/agents/zvm/fence_zvm.c b/agents/zvm/fence_zvm.c
new file mode 100644
index 0000000..6f1469e
--- /dev/null
+++ b/agents/zvm/fence_zvm.c
@@ -0,0 +1,1056 @@
+/*
+ * fence_zvm.c: SMAPI interface for managing zVM Guests
+ *
+ * Copyright (C) 2012 Sine Nomine Associates
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Neale Ferguson <neale@sinenomine.net>
+ *
+ */
+
+#ifdef __s390__
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netiucv/iucv.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <syslog.h>
+#include "fence_zvm.h"
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define DEFAULT_TIMEOUT 300
+#define DEFAULT_DELAY 0
+
+#define ACT_OFFON 0
+#define ACT_OFF 1
+#define ACT_ON 2
+#define ACT_METADATA 3
+#define ACT_STATUS 4
+#define ACT_MONITOR 5
+#define ACT_LIST 6
+#define ACT_HELP 7
+
+static int zvm_smapi_reportError (void *, void *);
+
+static struct option longopts[] = {
+ {"action", required_argument, NULL, 'o'},
+ {"delay", required_argument, NULL, 'h'},
+ {"help", no_argument, NULL, 'h'},
+ {"ip", required_argument, NULL, 'a'},
+ {"plug", required_argument, NULL, 'n'},
+ {"timeout", required_argument, NULL, 'T'},
+ {"zvmsys", required_argument, NULL, 'z'},
+ {NULL, 0, NULL, 0}
+};
+
+static const char *optString = "a:ho:n:T:";
+
+static int zvm_metadata (void);
+static int usage (void);
+
+/**
+ * zvm_smapi_open:
+ * @zvm: z/VM driver information
+ *
+ * Opens a connection with the z/VM SMAPI server
+ */
+int
+zvm_smapi_open (zvm_driver_t * zvm)
+{
+ int rc = -1, sockaddrlen;
+ static char iucvprog[9] = "DMSRSRQU\0";
+ struct sockaddr_iucv siucv_addr;
+ const struct sockaddr *siucv_ptr = (void *) &siucv_addr;
+
+ if ((zvm->sd = socket (AF_IUCV, SOCK_STREAM, IPPROTO_IP)) != -1) {
+ memset (&siucv_addr, 0, sizeof (siucv_addr));
+ siucv_addr.siucv_family = AF_IUCV;
+ siucv_addr.siucv_port = 0;
+ siucv_addr.siucv_addr = 0;
+ memset (&siucv_addr.siucv_nodeid, ' ', 8);
+ memset (&siucv_addr.siucv_user_id, ' ', 8);
+ memset (&siucv_addr.siucv_name, ' ', 8);
+ sockaddrlen = sizeof (siucv_addr);
+ if ((rc = bind (zvm->sd, siucv_ptr, sockaddrlen)) != -1) {
+ memcpy (&siucv_addr.siucv_user_id, zvm->smapiSrv,
+ strlen (zvm->smapiSrv));
+ memcpy (&siucv_addr.siucv_name, &iucvprog, 8);
+ memcpy (&siucv_addr.siucv_nodeid, zvm->node,
+ strlen (zvm->node));
+ rc = connect (zvm->sd,
+ (__CONST_SOCKADDR_ARG) siucv_ptr,
+ sockaddrlen);
+ }
+ if (rc == -1) {
+ syslog (LOG_ERR, "Error connecting to %s - %m",
+ zvm->smapiSrv);
+ close (zvm->sd);
+ }
+ }
+ return (rc);
+}
+
+/**
+ * zvm_smapi_imageRecycle
+ * @zvm: z/VM driver information
+ *
+ * Deactivates a virtual image
+ */
+int
+zvm_smapi_imageRecycle (zvm_driver_t * zvm)
+{
+ struct _inPlist
+ {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[13];
+ int32_t lUser;
+ int32_t lPass;
+ int32_t lTarget;
+ char target[0];
+ } __attribute__((__packed__)) * inPlist;
+ int32_t lInPlist;
+ struct _outPlist
+ {
+ smapiOutHeader_t hdr;
+ int32_t nActive;
+ int32_t nInActive;
+ int32_t lFail;
+ char failArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep (zvm->delay);
+
+ lInPlist = sizeof (*inPlist) + strlen (zvm->target);
+ inPlist = malloc (lInPlist);
+ if (inPlist != NULL) {
+ inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist);
+ inPlist->lFName = sizeof (inPlist->fName);
+ memcpy (inPlist->fName, Image_Recycle,
+ sizeof (inPlist->fName));
+ inPlist->lUser = inPlist->lPass = 0;
+ inPlist->lTarget = strlen (zvm->target);
+ memcpy (inPlist->target, zvm->target, inPlist->lTarget);
+ if ((rc =
+ zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ syslog (LOG_INFO,
+ "Recycling of %s successful",
+ zvm->target);
+ rc = 0;
+ }
+ else {
+ if ((outPlist->hdr.rc ==
+ RCERR_IMAGEOP) & ((outPlist->hdr.
+ reason ==
+ RS_NOT_ACTIVE)
+ | (outPlist->
+ hdr.
+ reason ==
+ RS_BEING_DEACT)))
+ {
+ syslog (LOG_INFO,
+ "Recycling of %s successful",
+ zvm->target);
+ rc = 0;
+ }
+ else {
+ rc = outPlist->hdr.rc;
+ zvm->reason =
+ outPlist->hdr.reason;
+ (void) zvm_smapi_reportError
+ (inPlist, outPlist);
+ }
+ }
+ }
+ }
+ free (inPlist);
+ free (outPlist);
+ }
+ else {
+ syslog (LOG_ERR, "%s - cannot allocate parameter list",
+ __func__);
+ rc = -1;
+ }
+ return (rc);
+}
+
+/**
+ * zvm_smapi_imageDeactivate
+ * @zvm: z/VM driver information
+ *
+ * Deactivates a virtual image
+ */
+int
+zvm_smapi_imageDeactivate (zvm_driver_t * zvm)
+{
+ struct _inPlist
+ {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[16];
+ int32_t lUser;
+ int32_t lPass;
+ int32_t lTarget;
+ char target[0];
+ } __attribute__((__packed__)) * inPlist;
+ struct _deactTime
+ {
+ int32_t lForceTime;
+ char forceTime[5];
+ } __attribute__((__packed__)) * deactTime;
+ int32_t lInPlist;
+ struct _outPlist
+ {
+ smapiOutHeader_t hdr;
+ int32_t nActive;
+ int32_t nInActive;
+ int32_t lFail;
+ char failArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep (zvm->delay);
+
+ lInPlist =
+ sizeof (*inPlist) + strlen (zvm->target) +
+ sizeof (*deactTime);
+ inPlist = malloc (lInPlist);
+ if (inPlist != NULL) {
+ inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist);
+ inPlist->lFName = sizeof (inPlist->fName);
+ memcpy (inPlist->fName, Image_Deactivate,
+ sizeof (inPlist->fName));
+ deactTime =
+ (void *) ((intptr_t) inPlist + sizeof (*inPlist) +
+ strlen (zvm->target));
+ deactTime->lForceTime = sizeof (deactTime->forceTime);
+ memcpy (deactTime->forceTime, "IMMED",
+ sizeof (deactTime->forceTime));
+ inPlist->lUser = inPlist->lPass = 0;
+ inPlist->lTarget = strlen (zvm->target);
+ memcpy (inPlist->target, zvm->target, inPlist->lTarget);
+ if ((rc =
+ zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ syslog (LOG_INFO,
+ "Deactivation of %s successful",
+ zvm->target);
+ rc = 0;
+ }
+ else {
+ if ((outPlist->hdr.rc ==
+ RCERR_IMAGEOP) & ((outPlist->hdr.
+ reason ==
+ RS_NOT_ACTIVE)
+ | (outPlist->
+ hdr.
+ reason ==
+ RS_BEING_DEACT)))
+ {
+ syslog (LOG_INFO,
+ "Deactivation of %s successful",
+ zvm->target);
+ rc = 0;
+ }
+ else {
+ rc = outPlist->hdr.rc;
+ zvm->reason =
+ outPlist->hdr.reason;
+ (void) zvm_smapi_reportError
+ (inPlist, outPlist);
+ }
+ }
+ }
+ }
+ free (inPlist);
+ free (outPlist);
+ }
+ else {
+ syslog (LOG_ERR, "%s - cannot allocate parameter list",
+ __func__);
+ rc = -1;
+ }
+ return (rc);
+}
+
+/**
+ * zvm_smapi_imageActivate
+ * @zvm: z/VM driver information
+ *
+ * Deactivates a virtual image
+ */
+int
+zvm_smapi_imageActivate (zvm_driver_t * zvm)
+{
+ struct _inPlist
+ {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[14];
+ int32_t lUser;
+ int32_t lPass;
+ int32_t lTarget;
+ char target[0];
+ } __attribute__((__packed__)) * inPlist;
+ int32_t lInPlist;
+ struct _outPlist
+ {
+ smapiOutHeader_t hdr;
+ int32_t nActive;
+ int32_t nInActive;
+ int32_t lFail;
+ char failArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep (zvm->delay);
+
+ lInPlist = sizeof (*inPlist) + strlen (zvm->target);
+ inPlist = malloc (lInPlist);
+ if (inPlist != NULL) {
+ inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist);
+ inPlist->lFName = sizeof (inPlist->fName);
+ memcpy (inPlist->fName, Image_Activate,
+ sizeof (inPlist->fName));
+ inPlist->lUser = inPlist->lPass = 0;
+ inPlist->lTarget = strlen (zvm->target);
+ memcpy (inPlist->target, zvm->target, inPlist->lTarget);
+ if ((rc =
+ zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ syslog (LOG_INFO,
+ "Activation of %s successful",
+ zvm->target);
+ rc = 0;
+ }
+ else {
+ if ((outPlist->hdr.rc ==
+ RCERR_IMAGEOP) & (outPlist->hdr.
+ reason ==
+ RS_ALREADY_ACTIVE))
+ {
+ syslog (LOG_INFO,
+ "Activation of %s successful",
+ zvm->target);
+ rc = 0;
+ }
+ else {
+ rc = outPlist->hdr.rc;
+ zvm->reason =
+ outPlist->hdr.reason;
+ (void) zvm_smapi_reportError
+ (inPlist, outPlist);
+ }
+ }
+ }
+ }
+ free (inPlist);
+ free (outPlist);
+ }
+ else {
+ syslog (LOG_ERR, "%s - cannot allocate parameter list",
+ __func__);
+ rc = -1;
+ }
+ return (rc);
+}
+
+/**
+ * zvm_smapi_imageQuery
+ * @zvm: z/VM driver information
+ *
+ * Queries the state of a virtual image
+ */
+int
+zvm_smapi_imageQuery (zvm_driver_t * zvm)
+{
+ struct _inPlist
+ {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[18];
+ int32_t lUser;
+ int32_t lPass;
+ int32_t lTarget;
+ char target[0];
+ } __attribute__((__packed__)) * inPlist;
+ int32_t lInPlist;
+ struct _outPlist
+ {
+ smapiOutHeader_t hdr;
+ int32_t lNames;
+ char nameArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep (zvm->delay);
+
+ lInPlist = sizeof (*inPlist) + strlen (zvm->target);
+ inPlist = malloc (lInPlist);
+ if (inPlist != NULL) {
+ inPlist->lPlist = lInPlist - sizeof (inPlist->lPlist);
+ inPlist->lFName = sizeof (inPlist->fName);
+ memcpy (inPlist->fName, Image_Status_Query,
+ sizeof (inPlist->fName));
+ inPlist->lUser = inPlist->lPass = 0;
+ inPlist->lTarget = strlen (zvm->target);
+ memcpy (inPlist->target, zvm->target, inPlist->lTarget);
+ if ((rc =
+ zvm_smapi_send (zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv (zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ if (outPlist->hdr.reason == 0) {
+ syslog (LOG_INFO,
+ "Node %s is active",
+ zvm->target);
+ rc = 0;
+ }
+ else {
+ syslog (LOG_INFO,
+ "Node %s is inactive",
+ zvm->target);
+ rc = 2;
+ }
+ }
+ else {
+ rc = 1;
+ zvm->reason = outPlist->hdr.reason;
+ (void) zvm_smapi_reportError (inPlist,
+ outPlist);
+ }
+ }
+ }
+ free (inPlist);
+ free (outPlist);
+ }
+ else {
+ syslog (LOG_ERR, "%s - cannot allocate parameter list",
+ __func__);
+ rc = -1;
+ }
+ return (rc);
+}
+
+/**
+ * zvm_smapi_send:
+ * @zvm: z/VM driver information
+ * @reqid: Returned request id
+ * @req: Request parameter list
+ * @lSend: Length of request
+ *
+ * Send a request to the SMAPI server and retrieve the request id
+ */
+int
+zvm_smapi_send (zvm_driver_t * zvm, void *req, uint32_t * reqId,
+ int32_t lSend)
+{
+ int rc, nFds;
+ fd_set readFds;
+ struct timeval timeout;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+ zvm->reason = -1;
+ if ((rc = zvm_smapi_open (zvm)) == 0) {
+ rc = send (zvm->sd, req, lSend, 0);
+ if (rc != -1) {
+ FD_ZERO (&readFds);
+ FD_SET (zvm->sd, &readFds);
+ nFds = zvm->sd + 1;
+
+ if ((rc =
+ select (nFds, &readFds, NULL, NULL,
+ &timeout)) != -1) {
+ /*
+ * Get request ID
+ */
+ rc = recv (zvm->sd, reqId, sizeof (*reqId),
+ 0);
+ if (rc == -1)
+ syslog (LOG_ERR,
+ "Error receiving from SMAPI - %m");
+ }
+ }
+ else
+ syslog (LOG_ERR, "Error sending to SMAPI - %m");
+ }
+ return (rc);
+}
+
+/**
+ * zvm_smapi_recv:
+ * @zvm: z/VM driver information
+ * @req: Returned response parameter list
+ * @lRsp: Length of response
+ *
+ * Receive a response from the SMAPI server
+ */
+int
+zvm_smapi_recv (zvm_driver_t * zvm, void **rsp, int32_t * lRsp)
+{
+ int rc, lRem = 0, nFds;
+ void *pRecv = rsp;
+ fd_set readFds;
+ smapiOutHeader_t *out;
+ struct timeval timeout;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+ FD_ZERO (&readFds);
+ FD_SET (zvm->sd, &readFds);
+ nFds = zvm->sd + 1;
+
+ zvm->reason = -1;
+ if ((rc = select (nFds, &readFds, NULL, NULL, &timeout)) != -1) {
+ /*
+ * Get response length
+ */
+ if ((rc = recv (zvm->sd, lRsp, sizeof (*lRsp), 0)) != -1) {
+ lRem = *lRsp;
+ if (*rsp == NULL)
+ *rsp = malloc (*lRsp + sizeof (out->outLen));
+ out = *rsp;
+ out->outLen = *lRsp;
+ pRecv = &out->reqId;
+ while (lRem > 0) {
+ if ((rc =
+ recv (zvm->sd, pRecv, lRem, 0)) != -1) {
+ lRem -= rc;
+ pRecv = (void *) ((uintptr_t) pRecv +
+ rc);
+ }
+ else
+ syslog (LOG_ERR,
+ "Error receiving from SMAPI - %m");
+ (void) zvm_smapi_close (zvm);
+ return (rc);
+ }
+ zvm->reason = out->reason;
+ }
+ }
+ else
+ syslog (LOG_ERR, "Error receiving from SMAPI - %m");
+
+ (void) zvm_smapi_close (zvm);
+
+ return (rc);
+}
+
+/**
+ * zvm_smapi_close:
+ * @zvm: z/VM driver information
+ *
+ * Close a connection with the z/VM SMAPI server
+ */
+int
+zvm_smapi_close (zvm_driver_t * zvm)
+{
+ close (zvm->sd);
+ return (0);
+}
+
+/**
+ * zvm_smapi_reportError
+ * @inHdr - Input parameter list header
+ * @outHdr - Output parameter list header
+ *
+ * Report an error from the SMAPI server
+ */
+static int
+zvm_smapi_reportError (void *inHdr, void *oHdr)
+{
+ struct _inParm
+ {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[0];
+ } *inParm = inHdr;
+ smapiOutHeader_t *outHdr = oHdr;
+ char fName[64];
+
+ memset (fName, 0, sizeof (fName));
+ memcpy (fName, inParm->fName, inParm->lFName);
+ syslog (LOG_ERR, "%s - returned (%d,%d)",
+ fName, outHdr->rc, outHdr->reason);
+ return (-1);
+}
+
+
+/**
+ * trim - Trim spaces from string
+ * @str - Pointer to string
+ *
+ */
+static int
+trim (char *str)
+{
+ char *p;
+ int len;
+
+ if (!str)
+ return (0);
+
+ len = strlen (str);
+
+ while (len--) {
+ if (isspace (str[len])) {
+ str[len] = 0;
+ }
+ else {
+ break;
+ }
+ }
+
+ for (p = str; *p && isspace (*p); p++);
+
+ memmove (str, p, strlen (p) + 1);
+
+ return (strlen (str));
+}
+
+/**
+ * zvm_metadata - Show fence metadata
+ * @self - Path to this executable
+ *
+ */
+static int
+zvm_metadata ()
+{
+ fprintf (stdout, "<?xml version=\"1.0\" ?>\n");
+ fprintf (stdout, "<resource-agent name=\"fence_zvm\"");
+ fprintf (stdout,
+ " shortdesc=\"Fence agent for use with z/VM Virtual Machines\">\n");
+ fprintf (stdout, "<longdesc>");
+ fprintf (stdout,
+ "The fence_zvm agent is intended to be used with with z/VM SMAPI service.");
+ fprintf (stdout, "</longdesc>\n");
+ fprintf (stdout, "<vendor-url>http://www.ibm.com</vendor-url>\n");
+
+ fprintf (stdout, "<parameters>\n");
+
+ fprintf (stdout,
+ "\t<parameter name=\"port\" unique=\"1\" required=\"1\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-n, --plug\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Name of the Virtual Machine to be fenced");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout,
+ "\t<parameter name=\"ipaddr\" unique=\"1\" required=\"1\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-a, --ip\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Name of the SMAPI IUCV Server Virtual Machine");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout,
+ "\t<parameter name=\"zvmsys\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"--zvmsys\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Node of the SMAPI IUCV Server Virtual Machine");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout,
+ "\t<parameter name=\"action\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-o, --action\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"off\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Fencing action");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout,
+ "\t<parameter name=\"delay\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"--delay\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"0\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Time to delay fencing action in seconds");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout,
+ "\t<parameter name=\"usage\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-h, --help\" />\n");
+ fprintf (stdout, "\t\t<content type=\"boolean\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Print usage");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "</parameters>\n");
+
+ fprintf (stdout, "<actions>\n");
+ fprintf (stdout, "\t<action name=\"off\" />\n");
+ fprintf (stdout, "\t<action name=\"on\" automatic=\"0\" />\n");
+ fprintf (stdout, "\t<action name=\"list\" />\n");
+ fprintf (stdout, "\t<action name=\"metadata\" />\n");
+ fprintf (stdout, "\t<action name=\"monitor\" />\n");
+ fprintf (stdout, "\t<action name=\"reboot\" />\n");
+ fprintf (stdout, "\t<action name=\"status\" />\n");
+ fprintf (stdout, "</actions>\n");
+
+ fprintf (stdout, "</resource-agent>\n");
+
+ return (0);
+
+}
+
+/**
+ * get_options_stdin - get options from stdin
+ * @zvm - Pointer to driver information
+ *
+ */
+static int
+get_options_stdin (zvm_driver_t * zvm)
+{
+ char buf[1024], *endPtr, *opt, *arg;
+ int32_t lSrvName, lSrvNode, lTarget;
+ int fence = ACT_OFFON;
+
+ while (fgets (buf, sizeof (buf), stdin) != 0) {
+ if (trim (buf) == 0) {
+ continue;
+ }
+ if (buf[0] == '#') {
+ continue;
+ }
+
+ opt = buf;
+
+ if ((arg = strchr (opt, '=')) != 0) {
+ *arg = 0;
+ arg++;
+ }
+ else {
+ continue;
+ }
+
+ if (trim (arg) == 0)
+ continue;
+
+ if (!strcasecmp (opt, "action")) {
+ if (strcasecmp (arg, "reboot") == 0) {
+ fence = ACT_OFFON;
+ }
+ else if (strcasecmp (arg, "off") == 0) {
+ fence = ACT_OFF;
+ }
+ else if (strcasecmp (arg, "on") == 0) {
+ fence = ACT_ON;
+ }
+ else if (strcasecmp (arg, "metadata") == 0) {
+ fence = ACT_METADATA;
+ }
+ else if (strcasecmp (arg, "status") == 0) {
+ fence = ACT_STATUS;
+ }
+ else if (strcasecmp (arg, "monitor") == 0) {
+ fence = ACT_MONITOR;
+ }
+ else if (strcasecmp (arg, "list") == 0) {
+ fence = ACT_LIST;
+ }
+ else {
+ fence = ACT_HELP;
+ }
+ }
+ else if (!strcasecmp (opt, "ipaddr")) {
+ lSrvName = MIN (strlen (arg), sizeof (zvm->smapiSrv));
+ memcpy (zvm->smapiSrv, arg, lSrvName);
+ continue;
+ }
+ else if (!strcasecmp (opt, "port")) {
+ lTarget =
+ MIN (strlen (arg), sizeof (zvm->target) - 1);
+ strncpy (zvm->target, arg, lTarget);
+ continue;
+ }
+ else if (!strcasecmp (opt, "timeout")) {
+ zvm->timeOut = strtoul (arg, &endPtr, 10);
+ if (*endPtr != 0) {
+ syslog (LOG_WARNING,
+ "Invalid timeout value specified %s "
+ "defaulting to %d", arg,
+ DEFAULT_DELAY);
+ zvm->timeOut = DEFAULT_DELAY;
+ }
+ }
+ else if (!strcasecmp (opt, "zvmsys")) {
+ lSrvNode = MIN (strlen (arg), sizeof (zvm->node));
+ memcpy (zvm->node, arg, lSrvNode);
+ continue;
+ }
+ else if (!strcasecmp (opt, "delay")) {
+ zvm->delay = strtoul (arg, &endPtr, 10);
+ if (*endPtr != 0) {
+ syslog (LOG_WARNING,
+ "Invalid delay value specified %s "
+ "defaulting to %d", arg,
+ DEFAULT_DELAY);
+ zvm->delay = DEFAULT_DELAY;
+ }
+ }
+ else if (!strcasecmp (opt, "help")) {
+ fence = ACT_HELP;
+ }
+ }
+ return (fence);
+}
+
+/**
+ * get_options - get options from the command line
+ * @argc - Count of arguments
+ * @argv - Array of character strings
+ * @zvm - Pointer to driver information
+ *
+ */
+static int
+get_options (int argc, char **argv, zvm_driver_t * zvm)
+{
+ int c, fence = ACT_OFFON;
+ int32_t lSrvName, lSrvNode, lTarget;
+ char *endPtr;
+
+ while ((c =
+ getopt_long (argc, argv, optString, longopts, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ lTarget = MIN (strlen (optarg), sizeof (zvm->target));
+ memcpy (zvm->target, optarg, lTarget);
+ break;
+ case 'o':
+ if (strcasecmp (optarg, "reboot") == 0) {
+ fence = ACT_OFFON;
+ }
+ else if (strcasecmp (optarg, "off") == 0) {
+ fence = ACT_OFF;
+ }
+ else if (strcasecmp (optarg, "on") == 0) {
+ fence = ACT_ON;
+ }
+ else if (strcasecmp (optarg, "metadata") == 0) {
+ fence = ACT_METADATA;
+ }
+ else if (strcasecmp (optarg, "status") == 0) {
+ fence = ACT_STATUS;
+ }
+ else if (strcasecmp (optarg, "monitor") == 0) {
+ fence = ACT_MONITOR;
+ }
+ else if (strcasecmp (optarg, "list") == 0) {
+ fence = ACT_LIST;
+ }
+ else {
+ fence = ACT_HELP;
+ }
+ break;
+ case 'a':
+ lSrvName =
+ MIN (strlen (optarg), sizeof (zvm->smapiSrv));
+ memcpy (zvm->smapiSrv, optarg, lSrvName);
+ break;
+ case 'T':
+ zvm->timeOut = strtoul (optarg, &endPtr, 10);
+ if (*endPtr != 0) {
+ syslog (LOG_WARNING,
+ "Invalid timeout value specified: %s - "
+ "defaulting to %d", optarg,
+ DEFAULT_TIMEOUT);
+ zvm->timeOut = DEFAULT_TIMEOUT;
+ }
+ break;
+ case 'd':
+ zvm->delay = strtoul (optarg, &endPtr, 10);
+ if (*endPtr != 0) {
+ syslog (LOG_WARNING,
+ "Invalid delay value specified: %s - "
+ "defaulting to %d", optarg,
+ DEFAULT_DELAY);
+ zvm->delay = DEFAULT_DELAY;
+ }
+ break;
+ case 'z':
+ lSrvNode = MIN (strlen (optarg), sizeof (zvm->node));
+ memcpy (zvm->node, optarg, lSrvNode);
+ break;
+ default:
+ fence = ACT_HELP;
+ }
+ }
+ return (fence);
+}
+
+/**
+ * usage - display command syntax and parameters
+ *
+ */
+static int
+usage ()
+{
+ printf ("Usage: fence_zvm [options]\n\n"
+ "\tWhere [options] =\n"
+ "\t-o --action [action] - \"off\", \"on\", \"list\", \"metadata\", "
+ "\"monitor\", \"reboot\", \"status\"\n"
+ "\t--delay [seconds] - Time to delay fencing action in seconds\n"
+ "\t-n --plug [target] - Name of virtual machine to fence\n"
+ "\t-a --ip [server] - Name of SMAPI IUCV Request server\n"
+ "\t-T --timeout [secs] - Time to wait for fence in seconds - currently ignored\n"
+ "\t--zvmsys [node] - z/VM Node on which SMAPI server lives\n"
+ "\t-h --help - Display this usage information\n");
+ return (0);
+}
+
+/**
+ * check_param - Check that mandatory parameters have been specified
+ * @zvm - Pointer to driver information
+ *
+ */
+static int
+check_parm (zvm_driver_t * zvm)
+{
+ int rc;
+
+ if (zvm->smapiSrv[0] != 0) {
+ if (zvm->target[0] != 0) {
+ rc = 0;
+ }
+ else {
+ syslog (LOG_ERR, "Missing fence target name");
+ rc = 2;
+ }
+ }
+ else {
+ syslog (LOG_ERR, "Missing SMAPI server name");
+ rc = 1;
+ }
+ return (rc);
+}
+
+int
+main (int argc, char **argv)
+{
+ zvm_driver_t zvm;
+ int fence, rc = 0;
+
+ openlog ("fence_zvm", LOG_CONS | LOG_PID, LOG_DAEMON);
+ memset (&zvm, 0, sizeof (zvm));
+ zvm.timeOut = DEFAULT_TIMEOUT;
+ zvm.delay = DEFAULT_DELAY;
+
+ if (argc > 1)
+ fence = get_options (argc, argv, &zvm);
+ else
+ fence = get_options_stdin (&zvm);
+
+ switch (fence) {
+ case ACT_OFFON: // OFFON
+ if ((rc = check_parm (&zvm)) == 0)
+ rc = zvm_smapi_imageRecycle (&zvm);
+ break;
+ case ACT_OFF: // OFF
+ if ((rc = check_parm (&zvm)) == 0)
+ rc = zvm_smapi_imageDeactivate (&zvm);
+ break;
+ case ACT_ON: // ON
+ if ((rc = check_parm (&zvm)) == 0)
+ rc = zvm_smapi_imageActivate (&zvm);
+ break;
+ case ACT_METADATA: // METADATA
+ rc = zvm_metadata ();
+ break;
+ case ACT_STATUS: // STATUS
+ if ((rc = check_parm (&zvm)) == 0)
+ rc = zvm_smapi_imageQuery (&zvm);
+ break;
+ case ACT_MONITOR: // MONITOR
+ rc = 0;
+ break;
+ case ACT_LIST: // LIST
+ printf ("N/A");
+ rc = 0;
+ break;
+ case ACT_HELP:
+ rc = usage ();
+ }
+ closelog ();
+ return (rc);
+}
+#else
+#include <syslog.h>
+int
+main (int argc, char **argv)
+{
+ openlog ("fence_zvm", LOG_CONS | LOG_PID, LOG_DAEMON);
+ syslog (LOG_ERR,
+ "Fencing of a z/VM agent is not possible on this platform\n");
+ closelog ();
+ return (-1);
+}
+#endif
diff --git a/agents/zvm/fence_zvm.h b/agents/zvm/fence_zvm.h
new file mode 100644
index 0000000..ca18e4d
--- /dev/null
+++ b/agents/zvm/fence_zvm.h
@@ -0,0 +1,583 @@
+/*
+ * fence_zvm.h: SMAPI interface for z/VM Guests
+ *
+ * Copyright (C) 2012 Sine Nomine Associates
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Neale Ferguson <neale@sinenomine.net>
+ *
+ */
+
+#ifndef FENCE_ZVM_H
+# define FENCE_ZVM_H
+
+# include <sys/types.h>
+
+# define SMAPI_TARGET "OVIRTADM"
+# define SMAPI_MAXCPU 96
+
+/*
+ * Return codes
+ */
+# define RC_OK 0 /* Request successful */
+# define RC_WNG 4 /* Warning */
+# define RC_ERR 8 /* Error */
+# define RCERR_SYNTAX 24 /* Function parameter syntax error */
+# define RCERR_FILE_NOT_FOUND 28 /* File not found */
+# define RCERR_FILE_CANNOT_BE_UPDATED 36 /* Name list file cannot be updated */
+# define RCERR_AUTH 100 /* Request not authorized by ESM */
+# define RCERR_NO_AUTHFILE 104 /* Authorization file not found */
+# define RCERR_AUTHFILE_RO 106 /* Authorization file cannot be updated */
+# define RCERR_EXISTS 108 /* Authorization file entry already exists */
+# define RCERR_NO_ENTRY 112 /* Authorization file entry does not exist */
+# define RCERR_USER_PW_BAD 120 /* Authentication error: Userid or pwd invalid */
+# define RCERR_PW_EXPIRED 128 /* Authentication error: password expired */
+# define RCERR_ESM 188 /* ESM failure */
+# define RCERR_PW_CHECK 192 /* Internal error: can't authenticate user or pwd */
+# define RCERR_DMSCSL 196 /* Internal Callable Services error */
+# define RCERR_IMAGEOP 200 /* Image Operation error */
+# define RCERR_LIST 200 /* Bad rc for list or list function */
+# define RCERR_IMAGEDEVU 204 /* Image Device Usage error */
+# define RCERR_IMAGEDISKU 208 /* Image Disk Usage error */
+# define RCERR_IMAGECONN 212 /* Image Connectivity Definition error */
+# define RCERR_IMAGECPU 216 /* Image CPU definition error */
+# define RCERR_VOLUME 300 /* Image Volume function error */
+# define RCERR_INTERNAL 396 /* Internal product-specific error */
+# define RCERR_IMAGE_NAME 400 /* Image Name error */
+# define RCERR_IMAGEDEF 400 /* Image Definition error */
+# define RCERR_IMAGEDEVD 404 /* Image Device Definition error */
+# define RCERR_IMAGEDISKD 408 /* Image Disk Definition error */
+# define RCERR_IMAGECONND 412 /* Image Connectivity Definition error */
+# define RCERR_PROTODEF 416 /* Prototype Definition error */
+# define RCERR_DASD_DM 420 /* Volume/region name already defined or region in group */
+# define RCERR_SEGMENT_DM 424 /* Segment definition errors */
+# define RCERR_NOTIFY 428 /* Notification subscription errors */
+# define RCERR_TAG 432 /* Local tag definition errors */
+# define RCERR_PROFILED 436 /* Profile definition errors */
+# define RCERR_POLICY_PW 444 /* Password policy error */
+# define RCERR_POLICY_ACCT 448 /* Account number policy error */
+# define RCERR_TASK 452 /* Task error */
+# define RCERR_SCSI 456 /* SCSI error */
+# define RCERR_DM 500 /* Directory Manager error */
+# define RCERR_LIST_DM 504 /* Directory Manager list error */
+# define RCERR_ASYNC_DM 592 /* Asynchronous Operation error */
+# define RCERR_INTERNAL_DM 596 /* Internal Directory Manager error */
+# define RCERR_SHSTOR 600 /* Shared Memory function error */
+# define RCERR_VIRTUALNETWORKD 620 /* Vswitch function error */
+# define RCERR_VMRM 800 /* Error from VMRM functions */
+# define RCERR_SERVER 900 /* Socket-Server error */
+
+/*
+ * Syntax error reason codes
+ */
+# define RS_NONE 0
+# define RS_TOOMANY 0
+# define RS_TANY 0
+# define RS_TBIN 2
+# define RS_UNSIGNEDINT 10
+# define RS_TNUM 10
+# define RS_UNSUPPORTED 11
+# define RS_SHORT 14
+# define RS_LESSTHANMIN 15
+# define RS_HEX 16
+# define RS_THEX 16
+# define RS_THEXHY 17
+# define RS_LONG 13
+# define RS_MORETHANMAX 18
+# define RS_UNRECOG 19
+# define RS_CONFLICTING 23
+# define RS_UNSPECIFIED 24
+# define RS_EXTRANEOUS 25
+# define RS_ALPHABETIC 26
+# define RS_TALPHA 26
+# define RS_FUNCTIONNAME 27
+# define RS_TALPHA_ 27
+# define RS_ALPHANUMERIC 36
+# define RS_TNUMALPHA 36
+# define RS_ALPHANUMERIC_ 37
+# define RS_TNUMALPHAHY 37
+# define RS_TLIST 38
+# define RS_DIRMAINTFILE 42
+# define RS_TFILE 42
+# define RS_DIRMAINTFILE_ 43
+# define RS_TFILE_ 43
+# define RS_DIRMAINTFILE_EQ 44
+# define RS_TFILE_EQ 44
+# define RS_UNEXPECTED_END 88
+# define RS_NON_BREAKING_CHAR 99
+# define RS_TNONBLANK 99
+
+/*
+ * Non-syntax related reason codes
+ */
+# define RS_NONE 0 /* Request successful */
+# define RS_INVALID_USER 2 /* Invalid user */
+# define RS_INVALID_DEVICE 2 /* invalid device */
+# define RS_NO_OSAS 4 /* No OSAs exist */
+# define RS_INVALID_OP 3 /* Invalid LAN operation */
+# define RS_INVALID_PRO 4 /* Invalid LAN promiscuity */
+# define RS_NO_DEV 4 /* No IPL device */
+# define RS_DEFERRED_SERVER 4 /* Authorization deferred to server */
+# define RS_DUP_NAME 4 /* Duplicate tag name */
+# define RS_EXISTS 4 /* Device already exists*/
+# define RS_IN_USE 4 /* Image Disk already in use */
+# define RS_IVS_NAME_USED 4 /* Group/region/volume already defined */
+# define RS_LOADDEV_NOT_FOUND 4 /* LOADDEV statement not found */
+# define RS_NO_PARTNER 4 /* Partner image not found */
+# define RS_NO_UPDATES 4 /* Directory manager not accepting update*/
+# define RS_NOT_FOUND 4 /* Image/Task Not Found */
+# define RS_NOTIFY_DUPLICATE 4 /* Duplicate subscription */
+# define RS_SEG_NAME_DUPLICATE 4 /* Segment name already used */
+# define RS_AFFINITY_SUPPRESSED 4 /* CPU defined but affinity suppressed */
+# define RS_WORK_OUTSTANDING 4 /* Image_Defintion_* asynch */
+# define RS_UNRESTRICTED_LAN 5 /* LAN is unrestricted */
+# define RS_NO_USERS 6 /* No users authorized for LAN */
+# define RS_ADAPTER_NOT_EXIST 8 /* Adapter does not exist */
+# define RS_ALREADY_ACTIVE 8 /* Image already active */
+# define RS_AUTHERR_CONNECT 8 /* Not authorized to connect */
+# define RS_AUTHERR_ESM 8 /* Request not authorized by an ESM */
+# define RS_BAD_RANGE 8 /* Bad page range */
+# define RS_DEV_NOT_FOUND 8 /* Device not found */
+# define RS_IVS_NAME_NOT_USED 8 /* Group/region/volume is not defined */
+# define RS_NAME_EXISTS 8 /* Image Name already defined */
+# define RS_NO_MEASUREMENT_DATA 8 /* No VMRM measurement query data */
+# define RS_NOT_AVAILABLE 8 /* Directory manager not available */
+# define RS_NOT_DEFINED 8 /* Image Device/Volume/Region/Group/Tag name not defined */
+# define RS_NOT_EXIST 8 /* Device does not exist */
+# define RS_NOTIFY_NOT_FOUND 8 /* No matching entries */
+# define RS_NOT_IN_USE 8 /* Image disk not in use */
+# define RS_OFFLINE 8 /* Successful; Object directory offline */
+# define RS_SEG_NAME_NOT_FOUND 8 /* Segment name not used */
+# define RS_WORKER_NOT_FOUND 8 /* Worker server not found */
+# define RS_DEV_NOT_AVAIL_TO_ATTACH 10 /* Device not found */
+# define RS_TOO_MANY_PARM 10 /* Too many parms in parameter list */
+# define RS_TOO_FEW_PARM 11 /* Too few parms in parameter list */
+# define RS_ALREADY_LOCKED 12 /* Image definition already locked */
+# define RS_AUTHERR_DM 12 /* Request not authorized by Directory Manager */
+# define RS_BUSY 12 /* Image device is busy */
+# define RS_DUP_ORDINAL 12 /* Duplicate tag ordinal */
+# define RS_FUNCTION_NOT_VALID 12 /* Not a valid SMAPI function */
+# define RS_IVS_NAME_NOT_INCLUDED 12 /* Name not included (ISR,ISQ)*/
+# define RS_LAN_NOT_EXIST 12 /* LAN does not exist */
+# define RS_LOCKED 12 /* Image definition is locked */
+# define RS_NAMESAVE_EXISTS 12 /* Namesave statementt already in directory*/
+# define RS_NEW_LIST 12 /* Successful new list created */
+# define RS_NOT_ACTIVE 12 /* Image not active */
+# define RS_NOT_INCLUDED 12 /* Region not included in group */
+# define RS_NOT_LOGGED_ON 12 /* User not logged on */
+# define RS_DEV_NOT_VOLUME 12 /* Device not a volume */
+# define RS_UPDATE_SYNTAX_ERROR 12 /* Errors in configuration update buffer */
+# define RS_FREE_MODE_NOT_AVAIL 14 /* Free mode not available */
+# define RS_AUTHERR_SERVER 16 /* Request not authorized by server */
+# define RS_BEING_DEACT 16 /* Image being deactivated */
+# define RS_CANNOT_ACCESS_DATA 16 /* Cannot access configuration or VMRM measurement data */
+# define RS_CANNOT_DELETE 16 /* Cannot delete image definition */
+# define RS_CANNOT_REVOKE 16 /* Cannot revoke tag definition */
+# define RS_CANNOT_SHARE 16 /* Image disk cannot be shared */
+# define RS_DEV_NOT_ONLINE 16 /* Device not online */
+# define RS_LIST_DESTROYED 16 /* Successful no more entries: list destroyed */
+# define RS_NO_MATCH 16 /* Parameters don't match existing directory statement */
+# define RS_NO_SHARING 16 /* Image disk sharing not allowed by target image definition */
+# define RS_NOSAVE 16 /* Could not save segment */
+# define RS_PTS_ENTRY_NOT_VALID 16 /* Parser entry not valid */
+# define RS_TAG_LONG 16 /* Tag too long */
+# define RS_VOLID_NOT_FOUND 18 /* Volid not found */
+# define RS_IS_CONNECTED 20 /* Device already connected */
+# define RS_NOT_AUTHORIZED 20 /* Not authorized for function */
+# define RS_OWNER_NOT_ACTIVE 20 /* Owner of reqested LAN not active */
+# define RS_PARM_LIST_NOT_VALID 20 /* Parameter list not valid */
+# define RS_PW_FORMAT_NOT_SUPPORTED 20 /* Directory manager does not support password format */
+# define RS_SHARE_DIFF_MODE 20 /* Image disk shared in different mode */
+# define RS_VOLID_IN_USE 20 /* Volid is in use */
+# define RS_TARGET_IMG_NOT_AUTH 20 /* Target Image not authorized to issue the command */
+# define RS_PDISKS_SAME 22 /* Parm disk 1 and 2 are same */
+# define RS_CONFLICTING_PARMS 24 /* Conflicting storage parameters */
+# define RS_LAN_NAME_EXISTS 24 /* Same name as an existing LAN */
+# define RS_LIST_NOT_FOUND 24 /* List not found */
+# define RS_NO_SPACE 24 /* Image disk space not available */
+# define RS_NOT_LOCKED 24 /* Image name is not locked */
+# define RS_PARM_DISK_LINK_ERR 24 /* Error linking parm disk (1 or 2)*/
+# define RS_SFS_ERROR 24 /* Shared File System error */
+# define RS_TYPE_NOT_SAME 24 /* Image device type not same as source */
+# define RS_UPDATE_WRITE_ERROR 24 /* Configuration update could not write files */
+# define RS_TAPE_NOT_ASSIGNED 24 /* Tape not assigned */
+# define RS_VCPU_ALREADY_EXISTS 24 /* Virtual CPU already defined */
+# define RS_VCPU_OUT_OF_RANGE 28 /* CPU beyond range defined in directory */
+# define RS_DEV_INCOMPATIBLE 28 /* Incorrect device type */
+# define RS_EMPTY 28 /* Return buffer is empty */
+# define RS_FILE_NOT_FOUND 28 /* File not found */
+# define RS_NO_MATCH_ON_SEARCH 28 /* No entries match search criteria */
+# define RS_NOT_ALL 28 /* Some images in list not activated */
+# define RS_OUTPUT_NOT_VALID 28 /* Output from function not valid */
+# define RS_PARM_DISK_NOT_RW 28 /* Parm Disk (1 or 2) not R/W */
+# define RS_PW_NEEDED 28 /* Image Disk does not have required password */
+# define RS_SEGMENT_NOT_FOUND 28 /* Shared Storage Segment not found */
+# define RS_SIZE_NOT_SAME 28 /* Image device size not same as source */
+# define RS_DEV_NOT_SHARED 28 /* Device not shared */
+# define RS_BAD_PW 32 /* Incorrect password specified for image disk */
+# define RS_NOT_CONNECTED 32 /* Device not connected */
+# define RS_NOT_IN_LIST 32 /* Name was not in list */
+# define RS_SOME_NOT_DEACT 32 /* Some Images in list not deactivated */
+# define RS_UPDATE_PROCESS_ERROR 32 /* Configuration update internal processer */
+# define RS_SYS_CONF_NOT_FOUND 32 /* System configuration file not found on PARM disk */
+# define RS_DEV_NOT_RESERVED 32 /* Device not reserved */
+# define RS_REQRESP_NOT_VALID 32 /* Internal request error */
+# define RS_SYS_CONF_BAD_DATA 34 /* Syntax Errors with original system configuration */
+# define RS_IVS_NAME_NOT_DASD 36 /* Name not DASD (for ISD) */
+# define RS_LENGTH_NOT_VALID 36 /* Length on input/output not valid */
+# define RS_NAME_IN_LIST 36 /* Name is already in list */
+# define RS_NO_VOLUME 36 /* No such DASD vol mounted on system; Unable to determine dev type */
+# define RS_SOME_NOT_RECYC 36 /* Some images in list not recycled */
+# define RS_SYS_CONF_SYNTX_ERR 36 /* Syntax errors with system configuration update*/
+# define RS_TIME_NOT_VALID 36 /* Force time for deactvation not valid */
+# define RS_VSWITCH_EXISTS 36 /* VSwitch already exists */
+# define RS_DEV_IO_ERROR 36 /* Device I/O error */
+# define RS_NO_DIR_AUTH_TO_LINK 36 /* No directory authority to link */
+# define RS_CPDISK_MODE_NOT_AVAIL 38 /* CP disk modes not available */
+# define RS_PARM_DISK_FULL 40 /* Parm Disk (1 or 2) is full */
+# define RS_VSWITCH_NOT_EXISTS 40 /* VSwitch doesn't exist */
+# define RS_NWDEV_NOT_DETACHED 40 /* Device not detached */
+# define RS_MULTIPLE 40 /* Multiple - multiple what? */
+# define RS_SOCKET 40 /* Socket error */
+# define RS_TYPE_NOT_SUPPORTED 40 /* CPU type not supported on your system */
+# define RS_PDISK_ACC_NOT_ALLOWED 42 /* Parm Disk 1 or 2 - access not allowed */
+# define RS_ALREADY_AUTH 44 /* Image already granted */
+# define RS_PDISK_PW_NOT_SUPPLIED 44 /* Parm Disk (1 or 2) password not supplied */
+# define RS_DASD_IN_USE 44 /* DASD in use */
+# define RS_IS_DISCONNECTED 48 /* Disconnected */
+# define RS_PDISK_PW_INCORRECT 46 /* Parm Disk (1 or 2) password is incorrect */
+# define RS_PARM_DISK_NOT_IN_SRVR_DIR 48 /* Parm Disk (1 or 2) is not in server's user directory */
+# define RS_VLAN_NOT_FOUND 48 /* vLAN not found */
+# define RS_MAX_CONN 52 /* Max connections reached */
+# define RS_CPRELEASE_ERROR 50 /* CPRELEASE error for Parm Disk (1 or 2) */
+# define RS_CPACCESS_ERROR 52 /* CPACCESS error for Parm Disk (1 or 2) */
+# define RS_DEF_VSWITCH_EXISTS 54 /* DEFINE exists in System Config */
+# define RS_GRANT_EXISTS 56 /* GRANT exists in System Config */
+# define RS_REVOKE_FAILED 58 /* MODIFY does not exist in System Config */
+# define RS_DEF_VSWITCH_NOT_EXIST 60 /* DEFINE does not exist in System config */
+# define RS_VSWITCH_CONFLICT 62 /* VSwitch conflict for set API */
+# define RS_DEF_MOD_MULTI_FOUND 64 /* Multiple Define or Modify statements found */
+# define RS_DEF_MOD_MULTI_ERASED 66 /* Multiple Define or Modify statements erased */
+# define RS_DATABASE 68 /* Unable to access database */
+# define RS_UNKNOWN 96 /* Connect request failed for unknown reason */
+# define RS_RETRY 99 /* Suggest retry API call */
+# define RS_ASYNC_OP_SUCCEEDED 100 /* Asynch operation succeeded */
+# define RS_ASYNC_OP_IN_PROGRESS 104 /* Asynch operation in progress */
+# define RS_ASYNC_OP_FAILED 108 /* Asynch operation failed */
+# define RS_CLASS_S_ALREADY_DEFINED 299 /* DEFSEG class S file exists */
+# define RS_NOT_YET_AVAILABLE 999 /* Function not yet available */
+# define RS_DEVNO_REQUIRES_FREE_DISK 1157 /* DEVNO parameter requires the device to be a free volume*/
+# define RS_INVALID_LANID 2783 /* invalid LAN id */
+# define RS_INVALID_LAN_PARM 2795 /* LAN parameter for this LAN id */
+# define RS_RELOCATION_ERRORS 3000 /* Relocation error(s) encountered */
+# define RS_NO_RELOCATION_ACTIVE 3001 /* No active relocations found */
+# define RS_INVALID_PARAMETER 3002 /* Invalid parameter name */
+# define RS_INVALID_OPERAND 3003 /* Invalid parameter operand */
+# define RS_MISSING_PARAMETER 3004 /* Missing parameter */
+# define RS_NOT_IN_SSI 3005 /* System not in an SSI */
+# define RS_SSI_UNSTABLE 3006 /* SSI is not in a stable state */
+# define RS_SSI_CPOWNED_CONFLICT 3007 /* The volume or slot is not on all systems in SSI */
+# define RS_NOT_SSI_MEMBER 3008 /* Not a member of an SSI cluster */
+# define RS_REPAIR_IPL_PARAM 3009 /* IPLed with the REPAIR IPL param */
+# define RS_RELOCATION_MODIFY_ERROR 3010 /* VMRELOCATE Modify error */
+# define RS_NO_SLOTS_AVAILABLE 3011 /* No unique CP_OWNED slot available on system and in config */
+# define RS_VOLUME_NOT_FOUND 3012 /* VOLUME cannot be found */
+# define RS_VOLUME_OFFLINE 3013 /* The volume is offline */
+# define RS_SHARE_UNSUPPORTED 3014 /* Volume does not support sharing */
+
+/*
+ * API functional level
+ */
+# define RS_530 0 /* 5.3.0 level */
+# define RS_540 540 /* 5.4.0 level */
+# define RS_610 610 /* 6.1.0 level */
+# define RS_611 611 /* 6.1.1 level */
+# define RS_620 620 /* 6.2.0 level */
+# define RS_621 621 /* 6.2.1 level */
+# define RS_630 630 /* 6.3.0 level */
+
+/*
+ * SMAPI Operations
+ */
+# define Asynchronous_Notification_Disable_DM "Asynchronous_Notification_Disable_DM"
+# define Asynchronous_Notification_Enable_DM "Asynchronous_Notification_Enable_DM"
+# define Asynchronous_Notification_Query_DM "Asynchronous_Notification_Query_DM"
+# define Authorization_List_Add "Authorization_List_Add"
+# define Authorization_List_Query "Authorization_List_Query"
+# define Authorization_List_Remove "Authorization_List_Remove"
+# define Check_Authentication "Check_Authentication"
+# define Delete_ABEND_Dump "Delete_ABEND_Dump"
+# define Directory_Manager_Local_Tag_Define_DM "Directory_Manager_Local_Tag_Define_DM"
+# define Directory_Manager_Local_Tag_Delete_DM "Directory_Manager_Local_Tag_Delete_DM"
+# define Directory_Manager_Local_Tag_Query_DM "Directory_Manager_Local_Tag_Query_DM"
+# define Directory_Manager_Local_Tag_Set_DM "Directory_Manager_Local_Tag_Set_DM"
+# define Directory_Manager_Search_DM "Directory_Manager_Search_DM"
+# define Directory_Manager_Task_Cancel_DM "Directory_Manager_Task_Cancel_DM"
+# define Event_Stream_Add "Event_Stream_Add"
+# define Event_Subscribe "Event_Subscribe"
+# define Event_Unsubscribe "Event_Unsubscribe"
+# define Image_Activate "Image_Activate"
+# define Image_Active_Configuration_Query "Image_Active_Configuration_Query"
+# define Image_CPU_Define "Image_CPU_Define"
+# define Image_CPU_Define_DM "Image_CPU_Define_DM"
+# define Image_CPU_Delete "Image_CPU_Delete"
+# define Image_CPU_Delete_DM "Image_CPU_Delete_DM"
+# define Image_CPU_Query "Image_CPU_Query"
+# define Image_CPU_Query_DM "Image_CPU_Query_DM"
+# define Image_CPU_Set_Maximum_DM "Image_CPU_Set_Maximum_DM"
+# define Image_Create_DM "Image_Create_DM"
+# define Image_Deactivate "Image_Deactivate"
+# define Image_Definition_Async_Updates "Image_Definition_Async_Updates"
+# define Image_Definition_Create_DM "Image_Definition_Create_DM"
+# define Image_Definition_Delete_DM "Image_Definition_Delete_DM"
+# define Image_Definition_Query_DM "Image_Definition_Query_DM"
+# define Image_Definition_Update_DM "Image_Definition_Update_DM"
+# define Image_Delete_DM "Image_Delete_DM"
+# define Image_Device_Dedicate "Image_Device_Dedicate"
+# define Image_Device_Dedicate_DM "Image_Device_Dedicate_DM"
+# define Image_Device_Reset "Image_Device_Reset"
+# define Image_Device_Undedicate "Image_Device_Undedicate"
+# define Image_Device_Undedicate_DM "Image_Device_Undedicate_DM"
+# define Image_Disk_Copy "Image_Disk_Copy"
+# define Image_Disk_Copy_DM "Image_Disk_Copy_DM"
+# define Image_Disk_Create "Image_Disk_Create"
+# define Image_Disk_Create_DM "Image_Disk_Create_DM"
+# define Image_Disk_Delete "Image_Disk_Delete"
+# define Image_Disk_Delete_DM "Image_Disk_Delete_DM"
+# define Image_Disk_Query "Image_Disk_Query"
+# define Image_Disk_Share "Image_Disk_Share"
+# define Image_Disk_Share_DM "Image_Disk_Share_DM"
+# define Image_Disk_Unshare "Image_Disk_Unshare"
+# define Image_Disk_Unshare_DM "Image_Disk_Unshare_DM"
+# define Image_IPL_Delete_DM "Image_IPL_Delete_DM"
+# define Image_IPL_Query_DM "Image_IPL_Query_DM"
+# define Image_IPL_Set_DM "Image_IPL_Set_DM"
+# define Image_Lock_DM "Image_Lock_DM"
+# define Image_Name_Query_DM "Image_Name_Query_DM"
+# define Image_Password_Set_DM "Image_Password_Set_DM"
+# define Image_Query_Activate_Time "Image_Query_Activate_Time"
+# define Image_Query_DM "Image_Query_DM"
+# define Image_Recycle "Image_Recycle"
+# define Image_Replace_DM "Image_Replace_DM"
+# define Image_SCSI_Characteristics_Define_DM "Image_SCSI_Characteristics_Define_DM"
+# define Image_SCSI_Characteristics_Query_DM "Image_SCSI_Characteristics_Query_DM"
+# define Image_Status_Query "Image_Status_Query"
+# define Image_Unlock_DM "Image_Unlock_DM"
+# define Image_Volume_Add "Image_Volume_Add"
+# define Image_Volume_Delete "Image_Volume_Delete"
+# define Image_Volume_Share "Image_Volume_Share"
+# define Image_Volume_Space_Define_DM "Image_Volume_Space_Define_DM"
+# define Image_Volume_Space_Define_Extended_DM "Image_Volume_Space_Define_Extended_DM"
+# define Image_Volume_Space_Query_DM "Image_Volume_Space_Query_DM"
+# define Image_Volume_Space_Query_Extended_DM "Image_Volume_Space_Query_Extended_DM"
+# define Image_Volume_Space_Remove_DM "Image_Volume_Space_Remove_DM"
+# define Metadata_Delete "Metadata_Delete"
+# define Metadata_Get "Metadata_Get"
+# define Metadata_Set "Metadata_Set"
+# define Name_List_Add "Name_List_Add"
+# define Name_List_Destroy "Name_List_Destroy"
+# define Name_List_Query "Name_List_Query"
+# define Name_List_Remove "Name_List_Remove"
+# define Page_or_Spool_Volume_Add "Page_or_Spool_Volume_Add"
+# define Process_ABEND_Dump "Process_ABEND_Dump"
+# define Profile_Create_DM "Profile_Create_DM"
+# define Profile_Delete_DM "Profile_Delete_DM"
+# define Profile_Lock_DM "Profile_Lock_DM"
+# define Profile_Query_DM "Profile_Query_DM"
+# define Profile_Replace_DM "Profile_Replace_DM"
+# define Profile_Unlock_DM "Profile_Unlock_DM"
+# define Prototype_Create_DM "Prototype_Create_DM"
+# define Prototype_Delete_DM "Prototype_Delete_DM"
+# define Prototype_Name_Query_DM "Prototype_Name_Query_DM"
+# define Prototype_Query_DM "Prototype_Query_DM"
+# define Prototype_Replace_DM "Prototype_Replace_DM"
+# define Query_ABEND_Dump "Query_ABEND_Dump"
+# define Query_All_DM "Query_All_DM"
+# define Query_API_Functional_Level "Query_API_Functional_Level"
+# define Query_Asynchronous_Operation_DM "Query_Asynchronous_Operation_DM"
+# define Query_Directory_Manager_Level_DM "Query_Directory_Manager_Level_DM"
+# define Response_Recovery "Response_Recovery"
+# define Shared_Memory_Access_Add_DM "Shared_Memory_Access_Add_DM"
+# define Shared_Memory_Access_Query_DM "Shared_Memory_Access_Query_DM"
+# define Shared_Memory_Access_Remove_DM "Shared_Memory_Access_Remove_DM"
+# define Shared_Memory_Create "Shared_Memory_Create"
+# define Shared_Memory_Delete "Shared_Memory_Delete"
+# define Shared_Memory_Query "Shared_Memory_Query"
+# define Shared_Memory_Replace "Shared_Memory_Replace"
+# define SSI_Query "SSI_Query"
+# define Static_Image_Changes_Activate_DM "Static_Image_Changes_Activate_DM"
+# define Static_Image_Changes_Deactivate_DM "Static_Image_Changes_Deactivate_DM"
+# define Static_Image_Changes_Immediate_DM "Static_Image_Changes_Immediate_DM"
+# define System_Config_Syntax_Check "System_Config_Syntax_Check"
+# define System_Disk_Accessibility "System_Disk_Accessibility"
+# define System_Disk_Add "System_Disk_Add"
+# define System_Disk_Query "System_Disk_Query"
+# define System_FCP_Free_Query "System_FCP_Free_Query"
+# define System_Performance_Threshold_Disable "System_Performance_Threshold_Disable"
+# define System_Performance_Threshold_Enable "System_Performance_Threshold_Enable"
+# define System_SCSI_Disk_Add "System_SCSI_Disk_Add"
+# define System_SCSI_Disk_Delete "System_SCSI_Disk_Delete"
+# define System_SCSI_Disk_Query "System_SCSI_Disk_Query"
+# define System_WWPN_Query "System_WWPN_Query"
+# define Virtual_Channel_Connection_Create "Virtual_Channel_Connection_Create"
+# define Virtual_Channel_Connection_Create_DM "Virtual_Channel_Connection_Create_DM"
+# define Virtual_Channel_Connection_Delete "Virtual_Channel_Connection_Delete"
+# define Virtual_Channel_Connection_Delete_DM "Virtual_Channel_Connection_Delete_DM"
+# define Virtual_Network_Adapter_Connect_LAN "Virtual_Network_Adapter_Connect_LAN"
+# define Virtual_Network_Adapter_Connect_LAN_DM "Virtual_Network_Adapter_Connect_LAN_DM"
+# define Virtual_Network_Adapter_Connect_Vswitch "Virtual_Network_Adapter_Connect_Vswitch"
+# define Virtual_Network_Adapter_Connect_Vswitch_DM "Virtual_Network_Adapter_Connect_Vswitch_DM"
+# define Virtual_Network_Adapter_Connect_Vswitch_Extended "Virtual_Network_Adapter_Connect_Vswitch_Extended"
+# define Virtual_Network_Adapter_Create "Virtual_Network_Adapter_Create"
+# define Virtual_Network_Adapter_Create_DM "Virtual_Network_Adapter_Create_DM"
+# define Virtual_Network_Adapter_Create_Extended "Virtual_Network_Adapter_Create_Extended"
+# define Virtual_Network_Adapter_Create_Extended_DM "Virtual_Network_Adapter_Create_Extended_DM"
+# define Virtual_Network_Adapter_Delete "Virtual_Network_Adapter_Delete"
+# define Virtual_Network_Adapter_Delete_DM "Virtual_Network_Adapter_Delete_DM"
+# define Virtual_Network_Adapter_Disconnect "Virtual_Network_Adapter_Disconnect"
+# define Virtual_Network_Adapter_Disconnect_DM "Virtual_Network_Adapter_Disconnect_DM"
+# define Virtual_Network_Adapter_Query "Virtual_Network_Adapter_Query"
+# define Virtual_Network_LAN_Access "Virtual_Network_LAN_Access"
+# define Virtual_Network_LAN_Access_Query "Virtual_Network_LAN_Access_Query"
+# define Virtual_Network_LAN_Create "Virtual_Network_LAN_Create"
+# define Virtual_Network_LAN_Delete "Virtual_Network_LAN_Delete"
+# define Virtual_Network_LAN_Query "Virtual_Network_LAN_Query"
+# define Virtual_Network_OSA_Query "Virtual_Network_OSA_Query"
+# define Virtual_Network_VLAN_Query_Stats "Virtual_Network_VLAN_Query_Stats"
+# define Virtual_Network_Vswitch_Create "Virtual_Network_Vswitch_Create"
+# define Virtual_Network_Vswitch_Create_Extended "Virtual_Network_Vswitch_Create_Extended"
+# define Virtual_Network_Vswitch_Delete "Virtual_Network_Vswitch_Delete"
+# define Virtual_Network_Vswitch_Delete_Extended "Virtual_Network_Vswitch_Delete_Extended"
+# define Virtual_Network_Vswitch_Query "Virtual_Network_Vswitch_Query"
+# define Virtual_Network_Vswitch_Query_Extended "Virtual_Network_Vswitch_Query_Extended"
+# define Virtual_Network_Vswitch_Query_Stats "Virtual_Network_Vswitch_Query_Stats"
+# define Virtual_Network_Vswitch_Set "Virtual_Network_Vswitch_Set"
+# define Virtual_Network_Vswitch_Set_Extended "Virtual_Network_Vswitch_Set_Extended"
+# define VMRELOCATE "VMRELOCATE"
+# define VMRELOCATE_Image_Attributes "VMRELOCATE_Image_Attributes"
+# define VMRELOCATE_Modify "VMRELOCATE_Modify"
+# define VMRELOCATE_Status "VMRELOCATE_Status"
+# define VMRM_Configuration_Query "VMRM_Configuration_Query"
+# define VMRM_Configuration_Update "VMRM_Configuration_Update"
+# define VMRM_Measurement_Query "VMRM_Measurement_Query"
+
+# define FORCE_IMMED "IMMED"
+# define FORCE_WITHIN "WITHIN 99999"
+
+/*
+ * Standard fields in a response from SMAPI server
+ */
+typedef struct {
+ uint32_t outLen; /* Length of output data */
+ uint32_t reqId; /* Request ID to which response refers */
+ uint32_t rc; /* Return code */
+ uint32_t reason; /* Reason code */
+} smapiOutHeader_t;
+
+typedef struct {
+ smapiOutHeader_t hdr; /* Output header */
+ uint32_t lArray; /* Length of array output */
+ char array[0]; /* Start of array output */
+} smapiArrayHeader_t;
+
+/*
+ * Structures returned from Image_Active_Configuration_Query
+ */
+typedef struct {
+ smapiOutHeader_t hdr;
+ int32_t memSize;
+ uint8_t memUnit;
+# define SMAPI_MEMUNIT_KB 1
+# define SMAPI_MEMUNIT_MB 2
+# define SMAPI_MEMUNIT_GB 3
+ uint8_t shareType;
+# define SMAPI_SHRTYPE_R 1
+# define SMAPI_SHRTYPE_A 2
+ int32_t lShare;
+ char share[0];
+} __attribute__ ((__packed__)) zvm_actImgHdr_t;
+
+typedef struct {
+ char share[5];
+} zvm_actImgShr_t;
+
+typedef struct {
+ int32_t nCPU;
+ int32_t lCPUArray;
+ char cpuArray[0];
+} zvm_actImgCPUArr_t;
+
+typedef struct {
+ int32_t lCPUStruct;
+ char cpuStruct[0];
+} zvm_actImgCPUHdr_t;
+
+typedef struct {
+ int32_t cpuNumber;
+ int32_t lCPUId;
+ char cpuId[16];
+} zvm_actImgCPUId_t;
+
+typedef struct {
+ uint8_t cpuState;
+# define SMAPI_CPUSTATE_BASE 1
+# define SMAPI_CPUSTATE_STOPPED 2
+# define SMAPI_CPUSTATE_CHECK 3
+# define SMAPI_CPUSTATE_ACTIVE 4
+ int32_t lDevArray;
+ char devArray[0];
+} __attribute__ ((__packed__)) zvm_actImgCPUState_t;
+
+typedef struct {
+ int32_t lDevStruct;
+ char devStruct[0];
+} zvm_actImgDevHdr_t;
+
+typedef struct {
+ uint8_t devType;
+# define SMAPI_DEVTYPE_CONS 1
+# define SMAPI_DEVTYPE_RDR 2
+# define SMAPI_DEVTYPE_PUN 3
+# define SMAPI_DEVTYPE_PRT 4
+# define SMAPI_DEVTYPE_DASD 5
+ int32_t lDevAddr;
+ uint8_t devAddr[4];
+} __attribute__ ((__packed__)) zvm_actImgDev_t;
+
+typedef struct {
+ int sd;
+ int reason;
+ uint32_t timeOut;
+ uint32_t delay;
+ char target[9];
+ char authUser[9];
+ char authPass[9];
+ char node[9];
+ char smapiSrv[128];
+} zvm_driver_t;
+
+int zvm_smapi_open(zvm_driver_t *);
+int zvm_smapi_send(zvm_driver_t *, void *, uint32_t *, int32_t);
+int zvm_smapi_recv(zvm_driver_t *, void **, int32_t *);
+int zvm_smapi_close(zvm_driver_t *);
+int zvm_smapi_imageActivate(zvm_driver_t *);
+int zvm_smapi_imageActiveQuery(zvm_driver_t *);
+int zvm_smapi_imageDeactivate(zvm_driver_t *);
+int zvm_smapi_imageRecycle(zvm_driver_t *);
+int zvm_smapi_imageQuery(zvm_driver_t *);
+
+#endif /* FENCE_ZVM_H */
diff --git a/agents/zvm/fence_zvm_man_page b/agents/zvm/fence_zvm_man_page
new file mode 100644
index 0000000..057cc6d
--- /dev/null
+++ b/agents/zvm/fence_zvm_man_page
@@ -0,0 +1,88 @@
+.TH fence_zvm 8
+
+.SH NAME
+fence_zvm - Power Fencing agent for GFS on System z z/VM Clusters
+
+.SH SYNOPSIS
+.B
+fence_zvm
+[\fIOPTION\fR]...
+
+.SH DESCRIPTION
+fence_zvm is a Power Fencing agent used on a GFS virtual machine in a System z z/VM cluster.
+It uses the SMAPI interface to recycle an active image.
+
+fence_zvm accepts options on the command line as well as from stdin.
+fence_node sends the options through stdin when it execs the agent.
+fence_zvm 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 virtual machine to recycle.
+.TP
+\fB-h --help\fP
+Print out a help message describing available options, then exit.
+.TP
+\fB-a --ip\fP \fIsmapi Server\fP
+\fBName\fP of SMAPI server virtual machine. To be consistent with other fence agents this name is a little misleading: it is the name of the virtual machine not its IP address or hostname.
+.TP
+\fB--zvmsys\fP \fIz/VM System\fP
+\fBName\fP of z/VM on which the SMAPI server virtual machine resides. Optional - defaults to system on which the node is running.
+.TP
+\fB-h --help\fP
+Display usage information
+.TP
+\fI-t --timeout = < shutdown timeout >\fP
+Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being
+forcibly terminated. Currently, this option is ignored.
+
+.SH STDIN PARAMETERS
+.TP
+\fIagent = < param >\fP
+This option is used by fence_node(8) and is ignored by fence_zvm.
+.TP
+\fIaction = < action >\fP
+Fencing action: "off" - fence off device; "metadata" - display device metadata; "status" - state of device
+.TP
+\fIport = < target >\fP
+Name of virtual machine to recycle.
+.TP
+\fIipaddr= < server name >\fP
+\fBName\fP of SMAPI server virtual machine. To be consistent with other fence agents thisname is a little misleading: it is the name of the virtual machine not its IP address or hostname.
+.TP
+\fItimeout = < shutdown timeout >\fP
+Amount of \fIgrace\fP time to give the virtual machine to shutdown cleanly before being
+forcibly terminated. Currently, this option 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_CHARACTERISTICS
+.fi
+
+Where XXXXXXX is the name of the virtual machine used in the authuser field of the request. This virtual machine also has to be authorized
+to access the system's directory manager.
+
+In addition, the VM directory entry that defines this virtual machine requires the
+IUCV ANY statement (or IUCV <userid of SMAPI Server>). This authorizes use of IUCV
+to connect to the SMAPI server.
diff --git a/agents/zvm/fence_zvmip.c b/agents/zvm/fence_zvmip.c
new file mode 100644
index 0000000..b16de48
--- /dev/null
+++ b/agents/zvm/fence_zvmip.c
@@ -0,0 +1,1001 @@
+/*
+ * fence_zvmip.c: SMAPI interface for managing zVM Guests
+ *
+ * Copyright (C) 2012 Sine Nomine Associates
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Neale Ferguson <neale@sinenomine.net>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netiucv/iucv.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <syslog.h>
+#include "fence_zvm.h"
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define DEFAULT_TIMEOUT 300
+#define DEFAULT_DELAY 0
+
+#define ACT_OFFON 0
+#define ACT_OFF 1
+#define ACT_ON 2
+#define ACT_METADATA 3
+#define ACT_STATUS 4
+#define ACT_MONITOR 5
+#define ACT_LIST 6
+#define ACT_HELP 7
+
+static int zvm_smapi_reportError(void *, void *);
+
+static struct option longopts[] = {
+ {"action", required_argument, NULL, 'o'},
+ {"delay", required_argument, NULL, 'd'},
+ {"help", no_argument, NULL, 'h'},
+ {"ipaddr", required_argument, NULL, 'a'},
+ {"password", required_argument, NULL, 'p'},
+ {"plug", required_argument, NULL, 'n'},
+ {"timeout", required_argument, NULL, 't'},
+ {"username", required_argument, NULL, 'u'},
+ {NULL, 0, NULL, 0}
+};
+
+static const char *optString = "a:o:hn:p:t:u:";
+
+static int zvm_metadata(void);
+static int usage(void);
+
+/**
+ * zvm_smapi_open:
+ * @zvm: z/VM driver information
+ *
+ * Opens a connection with the z/VM SMAPI server
+ */
+int
+zvm_smapi_open(zvm_driver_t *zvm)
+{
+ int rc = -1,
+ option = SO_REUSEADDR,
+ optVal = 1,
+ lOption = sizeof(optVal);
+ struct addrinfo hints, *ai;
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_TCP;
+ if ((rc = getaddrinfo(zvm->smapiSrv, "44444", &hints, &ai)) == 0) {
+ if ((zvm->sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) != -1) {
+ rc = setsockopt(zvm->sd,SOL_SOCKET,option,&optVal,lOption);
+
+ if ((rc = connect(zvm->sd, ai->ai_addr, ai->ai_addrlen)) == -1) {
+ syslog(LOG_ERR, "Error connecting to %s - %m", zvm->smapiSrv);
+ close(zvm->sd);
+ }
+ } else {
+ syslog(LOG_ERR, "Error creating socket - %m");
+ }
+ } else {
+ syslog(LOG_ERR, "Error resolving server address: %s", gai_strerror(rc));
+ }
+ return(rc);
+}
+
+/**
+ * zvm_smapi_imageRecycle
+ * @zvm: z/VM driver information
+ *
+ * Deactivates a virtual image
+ */
+int
+zvm_smapi_imageRecycle(zvm_driver_t *zvm)
+{
+ struct _inPlist {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[13];
+ } __attribute__ ((packed)) *inPlist;
+ struct _authUser {
+ int32_t lAuthUser;
+ char userId[0];
+ } __attribute__ ((packed)) *authUser;
+ struct _authPass {
+ int32_t lAuthPass;
+ char password[0];
+ } __attribute__ ((packed)) *authPass;
+ struct _image {
+ int32_t lTarget;
+ char target[0];
+ } __attribute__ ((packed)) *image;
+ int32_t lInPlist;
+ struct _outPlist {
+ smapiOutHeader_t hdr;
+ int32_t nActive;
+ int32_t nInActive;
+ int32_t lFail;
+ char failArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep(zvm->delay);
+
+ lInPlist = sizeof(*inPlist) + sizeof(*authUser) + strlen(zvm->authUser) +
+ sizeof(*authPass) + strlen(zvm->authPass) + sizeof(*image) +
+ + strlen(zvm->target);
+ inPlist = malloc(lInPlist);
+ if (inPlist != NULL) {
+ authUser = (void *) ((uintptr_t) inPlist + sizeof(*inPlist));
+ authPass = (void *) ((uintptr_t) authUser + sizeof(*authUser) +
+ strlen(zvm->authUser));
+ image = (void *) ((uintptr_t) authPass + sizeof(*authPass) +
+ strlen(zvm->authPass));
+ inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist);
+ inPlist->lFName = sizeof(inPlist->fName);
+ memcpy(inPlist->fName, Image_Recycle, sizeof(inPlist->fName));
+ authUser->lAuthUser = strlen(zvm->authUser);
+ memcpy(authUser->userId, zvm->authUser, strlen(zvm->authUser));
+ authPass->lAuthPass = strlen(zvm->authPass);
+ memcpy(authPass->password, zvm->authPass, strlen(zvm->authPass));
+ image->lTarget = strlen(zvm->target);
+ strncpy(image->target, zvm->target, strlen(zvm->target));
+ if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ syslog(LOG_INFO, "Recycling of %s successful",
+ zvm->target);
+ rc = 0;
+ } else {
+ if ((ntohl(outPlist->hdr.rc) == RCERR_IMAGEOP) &
+ ((ntohl(outPlist->hdr.reason) == RS_NOT_ACTIVE) |
+ (ntohl(outPlist->hdr.reason) == RS_BEING_DEACT))) {
+ syslog(LOG_INFO, "Recycling of %s successful",
+ zvm->target);
+ rc = 0;
+ } else {
+ rc = ntohl(outPlist->hdr.rc);
+ zvm->reason = ntohl(outPlist->hdr.reason);
+ (void) zvm_smapi_reportError(inPlist, outPlist);
+ }
+ }
+ }
+ }
+ free(inPlist);
+ free(outPlist);
+ } else {
+ syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__);
+ rc = -1;
+ }
+ return(rc);
+}
+
+/**
+ * zvm_smapi_imageDeactivate
+ * @zvm: z/VM driver information
+ *
+ * Deactivates a virtual image
+ */
+int
+zvm_smapi_imageDeactivate(zvm_driver_t *zvm)
+{
+ struct _inPlist {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[16];
+ } __attribute__ ((packed)) *inPlist;
+ struct _authUser {
+ int32_t lAuthUser;
+ char userId[0];
+ } __attribute__ ((packed)) *authUser;
+ struct _authPass {
+ int32_t lAuthPass;
+ char password[0];
+ } __attribute__ ((packed)) *authPass;
+ struct _image {
+ int32_t lTarget;
+ char target[0];
+ } __attribute__ ((packed)) *image;
+ struct _deactTime {
+ int32_t lForceTime;
+ char forceTime[5];
+ } __attribute__ ((__packed__)) *deactTime;
+ int32_t lInPlist;
+ struct _outPlist {
+ smapiOutHeader_t hdr;
+ int32_t nActive;
+ int32_t nInActive;
+ int32_t lFail;
+ char failArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep(zvm->delay);
+
+ lInPlist = sizeof(*inPlist) + sizeof(*authUser) + strlen(zvm->authUser) +
+ sizeof(*authPass) + strlen(zvm->authPass) + sizeof(*image) +
+ sizeof(*deactTime) + strlen(zvm->target);
+ inPlist = malloc(lInPlist);
+ if (inPlist != NULL) {
+ authUser = (void *) ((uintptr_t) inPlist + sizeof(*inPlist));
+ authPass = (void *) ((uintptr_t) authUser + sizeof(*authUser) +
+ strlen(zvm->authUser));
+ image = (void *) ((uintptr_t) authPass + sizeof(*authPass) +
+ strlen(zvm->authPass));
+ deactTime = (void *) ((intptr_t) image + sizeof(*image) +
+ strlen(zvm->target));
+ inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist);
+ inPlist->lFName = sizeof(inPlist->fName);
+ memcpy(inPlist->fName, Image_Deactivate, sizeof(inPlist->fName));
+ authUser->lAuthUser = strlen(zvm->authUser);
+ memcpy(authUser->userId, zvm->authUser, strlen(zvm->authUser));
+ authPass->lAuthPass = strlen(zvm->authPass);
+ memcpy(authPass->password, zvm->authPass, strlen(zvm->authPass));
+ image->lTarget = strlen(zvm->target);
+ memcpy(image->target, zvm->target, strlen(zvm->target));
+ deactTime->lForceTime = sizeof(deactTime->forceTime);
+ memcpy(deactTime->forceTime, "IMMED", sizeof(deactTime->forceTime));
+ if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ syslog(LOG_INFO, "Deactivation of %s successful",
+ zvm->target);
+ rc = 0;
+ } else {
+ if ((outPlist->hdr.rc == RCERR_IMAGEOP) &
+ ((outPlist->hdr.reason == RS_NOT_ACTIVE) |
+ (outPlist->hdr.reason == RS_BEING_DEACT))) {
+ syslog(LOG_INFO, "Deactivation of %s successful",
+ zvm->target);
+ rc = 0;
+ } else {
+ rc = outPlist->hdr.rc;
+ zvm->reason = outPlist->hdr.reason;
+ (void) zvm_smapi_reportError(inPlist, outPlist);
+ }
+ }
+ }
+ }
+ free(inPlist);
+ free(outPlist);
+ } else {
+ syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__);
+ rc = -1;
+ }
+ return(rc);
+}
+
+/**
+ * zvm_smapi_imageActivate
+ * @zvm: z/VM driver information
+ *
+ * Deactivates a virtual image
+ */
+int
+zvm_smapi_imageActivate(zvm_driver_t *zvm)
+{
+ struct _inPlist {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[14];
+ } __attribute__ ((packed)) *inPlist;
+ struct _authUser {
+ int32_t lAuthUser;
+ char userId[0];
+ } __attribute__ ((packed)) *authUser;
+ struct _authPass {
+ int32_t lAuthPass;
+ char password[0];
+ } __attribute__ ((packed)) *authPass;
+ struct _image {
+ int32_t lTarget;
+ char target[0];
+ } __attribute__ ((packed)) *image;
+ int32_t lInPlist;
+ struct _outPlist {
+ smapiOutHeader_t hdr;
+ int32_t nActive;
+ int32_t nInActive;
+ int32_t lFail;
+ char failArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep(zvm->delay);
+
+ lInPlist = sizeof(*inPlist) + sizeof(*authUser) + strlen(zvm->authUser) +
+ sizeof(*authPass) + strlen(zvm->authPass) + sizeof(*image) +
+ strlen(zvm->target);
+ inPlist = malloc(lInPlist);
+ if (inPlist != NULL) {
+ authUser = (void *) ((uintptr_t) inPlist + sizeof(*inPlist));
+ authPass = (void *) ((uintptr_t) authUser + sizeof(*authUser) +
+ strlen(zvm->authUser));
+ image = (void *) ((uintptr_t) authPass + sizeof(*authPass) +
+ strlen(zvm->authPass));
+ inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist);
+ inPlist->lFName = sizeof(inPlist->fName);
+ memcpy(inPlist->fName, Image_Activate, sizeof(inPlist->fName));
+ authUser->lAuthUser = strlen(zvm->authUser);
+ memcpy(authUser->userId, zvm->authUser, strlen(zvm->authUser));
+ authPass->lAuthPass = strlen(zvm->authPass);
+ memcpy(authPass->password, zvm->authPass, strlen(zvm->authPass));
+ image->lTarget = strlen(zvm->target);
+ memcpy(image->target, zvm->target, strlen(zvm->target));
+ if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ syslog(LOG_INFO, "Activation of %s successful",
+ zvm->target);
+ rc = 0;
+ } else {
+ if ((outPlist->hdr.rc == RCERR_IMAGEOP) &
+ (outPlist->hdr.reason == RS_ALREADY_ACTIVE)) {
+ syslog(LOG_INFO, "Activation of %s successful",
+ zvm->target);
+ rc = 0;
+ } else {
+ rc = outPlist->hdr.rc;
+ zvm->reason = outPlist->hdr.reason;
+ (void) zvm_smapi_reportError(inPlist, outPlist);
+ }
+ }
+ }
+ }
+ free(inPlist);
+ free(outPlist);
+ } else {
+ syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__);
+ rc = -1;
+ }
+ return(rc);
+}
+
+/**
+ * zvm_smapi_imageQuery
+ * @zvm: z/VM driver information
+ *
+ * Queries the state of a virtual image
+ */
+int
+zvm_smapi_imageQuery(zvm_driver_t *zvm)
+{
+ struct _inPlist {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[18];
+ int32_t lUser;
+ int32_t lPass;
+ int32_t lTarget;
+ char target[0];
+ } __attribute__ ((__packed__)) *inPlist;
+ int32_t lInPlist;
+ struct _outPlist {
+ smapiOutHeader_t hdr;
+ int32_t lNames;
+ char nameArray[0];
+ } *outPlist = NULL;
+ void *pOut = NULL;
+ int32_t lRsp;
+ uint32_t reqId;
+ int rc;
+
+ /*
+ * Implement any delay
+ */
+ if (zvm->delay > 0)
+ sleep(zvm->delay);
+
+ lInPlist = sizeof(*inPlist) + strlen(zvm->target);
+ inPlist = malloc(lInPlist);
+ if (inPlist != NULL) {
+ inPlist->lPlist = lInPlist - sizeof(inPlist->lPlist);
+ inPlist->lFName = sizeof(inPlist->fName);
+ memcpy(inPlist->fName, Image_Status_Query, sizeof(inPlist->fName));
+ inPlist->lUser = inPlist->lPass = 0;
+ inPlist->lTarget = strlen(zvm->target);
+ memcpy(inPlist->target, zvm->target, inPlist->lTarget);
+ if ((rc = zvm_smapi_send(zvm, inPlist, &reqId, lInPlist)) != -1) {
+ if ((rc = zvm_smapi_recv(zvm, &pOut, &lRsp)) != -1) {
+ outPlist = pOut;
+ if (outPlist->hdr.rc == 0) {
+ if (outPlist->hdr.reason == 0) {
+ syslog(LOG_INFO, "Node %s is active",
+ zvm->target);
+ rc = 0;
+ } else {
+ syslog(LOG_INFO, "Node %s is inactive",
+ zvm->target);
+ rc = 2;
+ }
+ } else {
+ rc = 1;
+ zvm->reason = outPlist->hdr.reason;
+ (void) zvm_smapi_reportError(inPlist, outPlist);
+ }
+ }
+ }
+ free(inPlist);
+ free(outPlist);
+ } else {
+ syslog(LOG_ERR, "%s - cannot allocate parameter list", __func__);
+ rc = -1;
+ }
+ return(rc);
+}
+
+/**
+ * zvm_smapi_send:
+ * @zvm: z/VM driver information
+ * @reqid: Returned request id
+ * @req: Request parameter list
+ * @lSend: Length of request
+ *
+ * Send a request to the SMAPI server and retrieve the request id
+ */
+int
+zvm_smapi_send(zvm_driver_t *zvm, void *req, uint32_t *reqId, int32_t lSend)
+{
+ int rc,
+ nFds;
+ fd_set readFds;
+ struct timeval timeout;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+ zvm->reason = -1;
+ if ((rc = zvm_smapi_open(zvm)) == 0) {
+ rc = send(zvm->sd,req,lSend,0);
+ if (rc != -1) {
+ FD_ZERO(&readFds);
+ FD_SET(zvm->sd,&readFds);
+ nFds = zvm->sd + 1;
+
+ if ((rc = select(nFds,&readFds,NULL,NULL,&timeout)) != -1) {
+ /*
+ * Get request ID
+ */
+ rc = recv(zvm->sd,reqId,sizeof(*reqId),0);
+ if (rc == -1)
+ syslog(LOG_ERR, "Error receiving from SMAPI - %m");
+ }
+ } else
+ syslog(LOG_ERR, "Error sending to SMAPI - %m");
+ }
+ return(rc);
+}
+
+/**
+ * zvm_smapi_recv:
+ * @zvm: z/VM driver information
+ * @req: Returned response parameter list
+ * @lRsp: Length of response
+ *
+ * Receive a response from the SMAPI server
+ */
+int
+zvm_smapi_recv(zvm_driver_t *zvm, void **rsp, int32_t *lRsp)
+{
+ int rc,
+ lRem = 0,
+ nFds;
+ void *pRecv = rsp;
+ fd_set readFds;
+ smapiOutHeader_t *out;
+ struct timeval timeout;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+ FD_ZERO(&readFds);
+ FD_SET(zvm->sd,&readFds);
+ nFds = zvm->sd + 1;
+
+ zvm->reason = -1;
+ if ((rc = select(nFds,&readFds,NULL,NULL,&timeout)) != -1) {
+ /*
+ * Get response length
+ */
+ if ((rc = recv(zvm->sd,lRsp,sizeof(*lRsp),0)) != -1) {
+ *lRsp = ntohl(*lRsp);
+ lRem = *lRsp;
+ if (*rsp == NULL)
+ *rsp = malloc(*lRsp + sizeof(out->outLen));
+ out = *rsp;
+ out->outLen = *lRsp;
+ pRecv = &out->reqId;
+ while (lRem > 0) {
+ if ((rc = recv(zvm->sd,pRecv,lRem,0)) != -1) {
+ lRem -= rc;
+ pRecv = (void *) ((uintptr_t) pRecv + rc);
+ } else
+ syslog(LOG_ERR, "Error receiving from SMAPI - %m");
+ (void) zvm_smapi_close(zvm);
+ return(rc);
+ }
+ zvm->reason = out->reason;
+ }
+ } else
+ syslog(LOG_ERR, "Error receiving from SMAPI - %m");
+
+ (void) zvm_smapi_close(zvm);
+
+ return(rc);
+}
+
+/**
+ * zvm_smapi_close:
+ * @zvm: z/VM driver information
+ *
+ * Close a connection with the z/VM SMAPI server
+ */
+int
+zvm_smapi_close(zvm_driver_t *zvm)
+{
+ close(zvm->sd);
+ return(0);
+}
+
+/**
+ * zvm_smapi_reportError
+ * @inHdr - Input parameter list header
+ * @outHdr - Output parameter list header
+ *
+ * Report an error from the SMAPI server
+ */
+static int
+zvm_smapi_reportError(void *inHdr, void *oHdr)
+{
+ struct _inParm {
+ int32_t lPlist;
+ int32_t lFName;
+ char fName[0];
+ } *inParm = inHdr;
+ smapiOutHeader_t *outHdr = oHdr;
+ char fName[64];
+
+ memset(fName, 0, sizeof(fName));
+ memcpy(fName, inParm->fName, inParm->lFName);
+ syslog(LOG_ERR, "%s - returned (%d,%d)",
+ fName, ntohl(outHdr->rc), ntohl(outHdr->reason));
+ return(-1);
+}
+
+
+/**
+ * trim - Trim spaces from string
+ * @str - Pointer to string
+ *
+ */
+static int
+trim(char *str)
+{
+ char *p;
+ int len;
+
+ if (!str)
+ return (0);
+
+ len = strlen (str);
+
+ while (len--) {
+ if (isspace (str[len])) {
+ str[len] = 0;
+ } else {
+ break;
+ }
+ }
+
+ for (p = str; *p && isspace (*p); p++);
+
+ memmove(str, p, strlen (p) + 1);
+
+ return (strlen (str));
+}
+
+/**
+ * get_options_stdin - get options from stdin
+ * @zvm - Pointer to driver information
+ *
+ */
+static int
+get_options_stdin (zvm_driver_t *zvm)
+{
+ char buf[1024],
+ *endPtr,
+ *opt,
+ *arg;
+ int32_t lSrvName,
+ lTarget;
+ int fence = ACT_OFFON;
+
+ while (fgets (buf, sizeof (buf), stdin) != 0) {
+ if (trim(buf) == 0) {
+ continue;
+ }
+ if (buf[0] == '#') {
+ continue;
+ }
+
+ opt = buf;
+
+ if ((arg = strchr(opt, '=')) != 0) {
+ *arg = 0;
+ arg++;
+ } else {
+ continue;
+ }
+
+ if (trim(arg) == 0)
+ continue;
+
+ if (!strcasecmp (opt, "action")) {
+ if (strcasecmp(arg, "reboot") == 0) {
+ fence = ACT_OFFON;
+ } else if (strcasecmp(arg, "off") == 0) {
+ fence = ACT_OFF;
+ } else if (strcasecmp(arg, "on") == 0) {
+ fence = ACT_ON;
+ } else if (strcasecmp(arg, "metadata") == 0) {
+ fence = ACT_METADATA;
+ } else if (strcasecmp(arg, "status") == 0) {
+ fence = ACT_STATUS;
+ } else if (strcasecmp(arg, "monitor") == 0) {
+ fence = ACT_MONITOR;
+ } else if (strcasecmp(arg, "list") == 0) {
+ fence = ACT_LIST;
+ } else {
+ fence = ACT_HELP;
+ }
+ } else if (!strcasecmp (opt, "ipaddr")) {
+ lSrvName = MIN(strlen(arg), sizeof(zvm->smapiSrv)-1);
+ memcpy(zvm->smapiSrv, arg, lSrvName);
+ continue;
+ } else if (!strcasecmp (opt, "login")) {
+ lSrvName = MIN(strlen(arg), sizeof(zvm->authUser)-1);
+ memcpy(zvm->authUser, arg, lSrvName);
+ continue;
+ } else if (!strcasecmp (opt, "passwd")) {
+ lSrvName = MIN(strlen(arg), sizeof(zvm->authPass)-1);
+ memcpy(zvm->authPass, arg, lSrvName);
+ continue;
+ } else if (!strcasecmp (opt, "port")) {
+ lTarget = MIN(strlen(arg), sizeof(zvm->target)-1);
+ strncpy(zvm->target, arg, lTarget);
+ continue;
+ } if (!strcasecmp (opt, "timeout")) {
+ zvm->timeOut = strtoul(arg, &endPtr, 10);
+ if (*endPtr != 0) {
+ syslog(LOG_WARNING, "Invalid timeout value specified %s "
+ "defaulting to %d",
+ arg, DEFAULT_TIMEOUT);
+ zvm->timeOut = DEFAULT_TIMEOUT;
+ }
+ } else if (!strcasecmp (opt, "help")) {
+ fence = ACT_HELP;
+ }
+ }
+ return(fence);
+}
+
+/**
+ * get_options - get options from the command line
+ * @argc - Count of arguments
+ * @argv - Array of character strings
+ * @zvm - Pointer to driver information
+ *
+ */
+static int
+get_options(int argc, char **argv, zvm_driver_t *zvm)
+{
+ int c,
+ fence = ACT_OFFON;
+ int32_t lSrvName,
+ lTarget;
+ char *endPtr;
+
+ while ((c = getopt_long(argc, argv, optString, longopts, NULL)) != -1) {
+ switch (c) {
+ case 'a' :
+ lSrvName = MIN(strlen(optarg), sizeof(zvm->smapiSrv)-1);
+ memcpy(zvm->smapiSrv, optarg, lSrvName);
+ break;
+ case 'n' :
+ lTarget = MIN(strlen(optarg), sizeof(zvm->target)-1);
+ memcpy(zvm->target, optarg, lTarget);
+ break;
+ case 'o' :
+ if (strcasecmp(optarg, "reboot") == 0) {
+ fence = ACT_OFFON;
+ } else if (strcasecmp(optarg, "off") == 0) {
+ fence = ACT_OFF;
+ } else if (strcasecmp(optarg, "on") == 0) {
+ fence = ACT_ON;
+ } else if (strcasecmp(optarg, "metadata") == 0) {
+ fence = ACT_METADATA;
+ } else if (strcasecmp(optarg, "status") == 0) {
+ fence = ACT_STATUS;
+ } else if (strcasecmp(optarg, "monitor") == 0) {
+ fence = ACT_MONITOR;
+ } else if (strcasecmp(optarg, "list") == 0) {
+ fence = ACT_LIST;
+ } else {
+ fence = ACT_HELP;
+ }
+ break;
+ case 'p' :
+ lSrvName = MIN(strlen(optarg), 8);
+ memcpy(zvm->authPass, optarg, lSrvName);
+ break;
+ case 'u' :
+ lSrvName = MIN(strlen(optarg), 8);
+ memcpy(zvm->authUser, optarg, lSrvName);
+ break;
+ case 't' :
+ zvm->timeOut = strtoul(optarg, &endPtr, 10);
+ if (*endPtr != 0) {
+ syslog(LOG_WARNING, "Invalid timeout value specified: %s - "
+ "defaulting to %d",
+ optarg, DEFAULT_TIMEOUT);
+ zvm->timeOut = DEFAULT_TIMEOUT;
+ }
+ break;
+ case 'd' :
+ zvm->delay = strtoul(optarg, &endPtr, 10);
+ if (*endPtr != 0) {
+ syslog(LOG_WARNING, "Invalid delay value specified: %s - "
+ "defaulting to %d",
+ optarg, DEFAULT_DELAY);
+ zvm->delay = DEFAULT_DELAY;
+ }
+ break;
+ default :
+ fence = ACT_HELP;
+ }
+ }
+ return(fence);
+}
+
+/**
+ * zvm_metadata - Show fence metadata
+ * @self - Path to this executable
+ *
+ */
+static int
+zvm_metadata()
+{
+ fprintf (stdout, "<?xml version=\"1.0\" ?>\n");
+ fprintf (stdout, "<resource-agent name=\"fence_zvmip\"");
+ fprintf (stdout, " shortdesc=\"Fence agent for use with z/VM Virtual Machines\">\n");
+ fprintf (stdout, "<longdesc>");
+ fprintf (stdout, "The fence_zvm agent is intended to be used with with z/VM SMAPI service via TCP/IP");
+ fprintf (stdout, "</longdesc>\n");
+ fprintf (stdout, "<vendor-url>http://www.ibm.com</vendor-url>\n");
+
+ fprintf (stdout, "<parameters>\n");
+
+ fprintf (stdout, "\t<parameter name=\"port\" unique=\"1\" required=\"1\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-n, --plug\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Name of the Virtual Machine to be fenced");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"ipaddr\" unique=\"1\" required=\"1\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-i, --ip\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "IP Name or Address of SMAPI Server");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"login\" unique=\"1\" required=\"1\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-u, --username\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Name of authorized SMAPI user");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"passwd\" unique=\"1\" required=\"1\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-p, --password\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Password of authorized SMAPI user");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"action\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-o, --action\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"off\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Fencing action");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"delay\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"--delay\" />\n");
+ fprintf (stdout, "\t\t<content type=\"string\" default=\"0\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Time to delay fencing action in seconds");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "\t<parameter name=\"usage\" unique=\"1\" required=\"0\">\n");
+ fprintf (stdout, "\t\t<getopt mixed=\"-h, --help\" />\n");
+ fprintf (stdout, "\t\t<content type=\"boolean\" />\n");
+ fprintf (stdout, "\t\t<shortdesc lang=\"en\">%s</shortdesc>\n",
+ "Print usage");
+ fprintf (stdout, "\t</parameter>\n");
+
+ fprintf (stdout, "</parameters>\n");
+
+ fprintf (stdout, "<actions>\n");
+ fprintf (stdout, "\t<action name=\"off\" />\n");
+ fprintf (stdout, "\t<action name=\"on\" automatic=\"0\" />\n");
+ fprintf (stdout, "\t<action name=\"list\" />\n");
+ fprintf (stdout, "\t<action name=\"metadata\" />\n");
+ fprintf (stdout, "\t<action name=\"monitor\" />\n");
+ fprintf (stdout, "\t<action name=\"status\" />\n");
+ fprintf (stdout, "\t<action name=\"reboot\" />\n");
+ fprintf (stdout, "</actions>\n");
+
+ fprintf (stdout, "</resource-agent>\n");
+
+ return(0);
+
+}
+
+/**
+ * usage - display command syntax and parameters
+ *
+ */
+static int
+usage()
+{
+ fprintf(stderr,"Usage: fence_zvmip [options]\n\n"
+ "\tWhere [options] =\n"
+ "\t-o --action [action] - \"off\", \"on\", \"list\", \"metadata\", "
+ "\"monitor\", \"reboot\", \"status\"\n"
+ "\t--delay [seconds] - Time to delay fencing action in seconds\n"
+ "\t-n --plug [target] - Name of virtual machine to fence\n"
+ "\t-a --ip [server] - IP Name/Address of SMAPI Server\n"
+ "\t-u --username [user] - Name of autorized SMAPI user\n"
+ "\t-p --password [pass] - Password of autorized SMAPI user\n"
+ "\t-t --timeout [secs] - Time to wait for fence in seconds - currently ignored\n"
+ "\t-h --help - Display this usage information\n");
+ return(1);
+}
+
+/**
+ * check_param - Check that mandatory parameters have been specified
+ * @zvm - Pointer to driver information
+ *
+ */
+static int
+check_parm(zvm_driver_t *zvm)
+{
+ int rc;
+
+ if (zvm->smapiSrv[0] != 0) {
+ if (zvm->target[0] != 0) {
+ if (zvm->authUser[0] != 0) {
+ if (zvm->authPass[0] != 0) {
+ rc = 0;
+ } else {
+ syslog(LOG_ERR, "Missing authorized password");
+ rc = 4;
+ }
+ } else {
+ syslog(LOG_ERR, "Missing authorized user name");
+ rc = 3;
+ }
+ } else {
+ syslog(LOG_ERR, "Missing fence target name");
+ rc = 2;
+ }
+ } else {
+ syslog(LOG_ERR, "Missing SMAPI server name");
+ rc = 1;
+ }
+ return(rc);
+}
+
+int
+main(int argc, char **argv)
+{
+ zvm_driver_t zvm;
+ int fence = 1,
+ rc = 0;
+
+ openlog ("fence_zvmip", LOG_CONS|LOG_PID, LOG_DAEMON);
+ memset(&zvm, 0, sizeof(zvm));
+ zvm.timeOut = DEFAULT_TIMEOUT;
+ zvm.delay = DEFAULT_DELAY;
+
+ if (argc > 1)
+ fence = get_options(argc, argv, &zvm);
+ else
+ fence = get_options_stdin(&zvm);
+
+ switch(fence) {
+ case ACT_OFFON : // OFFON
+ if ((rc = check_parm(&zvm)) == 0)
+ rc = zvm_smapi_imageRecycle(&zvm);
+ break;
+ case ACT_OFF : // OFF
+ if ((rc = check_parm(&zvm)) == 0)
+ rc = zvm_smapi_imageDeactivate(&zvm);
+ break;
+ case ACT_ON : // ON
+ if ((rc = check_parm(&zvm)) == 0)
+ rc = zvm_smapi_imageActivate(&zvm);
+ break;
+ case ACT_METADATA : // METADATA
+ rc = zvm_metadata();
+ break;
+ case ACT_STATUS : // STATUS
+ if ((rc = check_parm(&zvm)) == 0)
+ rc = zvm_smapi_imageQuery(&zvm);
+ break;
+ case ACT_MONITOR : // MONITOR
+ rc = 0;
+ break;
+ case ACT_LIST :
+ printf("N/A");
+ break;
+ case ACT_HELP :
+ rc = usage();
+ }
+ closelog();
+ return (rc);
+}
diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py
new file mode 100644
index 0000000..4f538e1
--- /dev/null
+++ b/agents/zvm/fence_zvmip.py
@@ -0,0 +1,226 @@
+#!@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
+
+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)
+
+ if "--ssl-secure" in options or "--ssl-insecure" in options:
+ import ssl
+ sock = socket.socket()
+ sslcx = ssl.create_default_context()
+ if "--ssl-insecure" in options:
+ sslcx.check_hostname = False
+ sslcx.verify_mode = ssl.CERT_NONE
+ conn = sslcx.wrap_socket(sock, server_hostname=options["--ip"])
+ else:
+ conn = socket.socket()
+ conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ conn.settimeout(float(options["--shell-timeout"]) or None)
+ try:
+ conn.connect(addr)
+ except socket.error as e:
+ logging.debug(e)
+ fail(EC_LOGIN_DENIED)
+
+ return conn
+
+def smapi_pack_string(string):
+ return struct.pack("!i%ds" % (len(string)), len(string), string.encode("UTF-8"))
+
+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
+
+ if options.get("--original-action", None) == "monitor":
+ (return_code, reason_code, images_active) = \
+ get_list_of_images(options, "Check_Authentication", None)
+
+ logging.debug("Check_Authenticate (%d,%d)", return_code, reason_code)
+ if return_code == 0:
+ return {}
+ else:
+ fail(EC_LOGIN_DENIED)
+
+ if options["--action"] == "list":
+ # '*' = list all active images
+ options["--plug"] = "*"
+
+ (return_code, reason_code, images_active) = \
+ get_list_of_images(options, "Image_Status_Query", options["--plug"])
+ logging.debug("Image_Status_Query results are (%d,%d)", return_code, reason_code)
+
+ if not options["--action"] == "list":
+ if (return_code == 0) and (reason_code == 0):
+ return "on"
+ elif (return_code == 0) and (reason_code == 12):
+ # We are running always with --missing-as-off because we can not check if image
+ # is defined or not (look at rhbz#1188750)
+ return "off"
+ else:
+ return "unknown"
+ else:
+ (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)
+
+ return dict([(i, ("", "on" if i in images_active else "off")) for i in images_defined])
+
+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)
+
+ if data_as_plug is None:
+ packet = prepare_smapi_command(options, command, [])
+ else:
+ packet = prepare_smapi_command(options, command, [data_as_plug])
+
+ conn.send(packet)
+
+ try:
+ request_id = struct.unpack("!i", conn.recv(INT4))[0]
+ (output_len, request_id, return_code, reason_code) = struct.unpack("!iiii", conn.recv(INT4 * 4))
+ except struct.error:
+ logging.debug(sys.exc_info())
+ fail_usage("Failed: Unable to connect to {} port: {} SSL: {} \n".format(options["--ip"], options["--ipport"], bool("--ssl" in options)))
+
+ images = set()
+
+ if output_len > 3*INT4:
+ recvflag = socket.MSG_WAITALL if "--ssl-secure" not in options and "--ssl-insecure" not in options else 0
+ array_len = struct.unpack("!i", conn.recv(INT4))[0]
+ data = ""
+
+ while True:
+ read_data = conn.recv(1024, recvflag).decode("UTF-8")
+ 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].encode("UTF-8"))[0]
+ parsed_len += INT4
+ image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len].encode("UTF-8"))[0].decode("UTF-8")
+ parsed_len += string_len
+ images.add(image_name)
+
+ conn.close()
+ return (return_code, reason_code, images)
+
+def define_new_opts():
+ all_opt["disable_ssl"] = {
+ "getopt" : "",
+ "longopt" : "disable-ssl",
+ "help" : "--disable-ssl Don't use SSL connection",
+ "required" : "0",
+ "shortdesc" : "Don't use SSL",
+ "order": 2
+ }
+
+def main():
+ device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off",
+ "inet4_only", "inet6_only", "ssl", "disable_ssl"]
+
+ atexit.register(atexit_handler)
+ define_new_opts()
+
+ all_opt["ssl"]["help"] = "-z, --ssl Use SSL connection with verifying certificate (Default)"
+
+ all_opt["ipport"]["default"] = "44444"
+ all_opt["shell_timeout"]["default"] = "5"
+ all_opt["missing_as_off"]["default"] = "1"
+ all_opt["ssl"]["default"] = "1"
+ options = check_input(device_opt, process_input(device_opt), other_conditions=True)
+
+ if "--disable-ssl" in options or options["--ssl"] == "0":
+ for k in ["--ssl", "--ssl-secure", "--ssl-insecure"]:
+ if k in options:
+ del options[k]
+
+ if len(options.get("--plug", "")) > 8:
+ fail_usage("Failed: Name of image can not be longer than 8 characters")
+
+ if options["--action"] == "validate-all":
+ sys.exit(0)
+
+ 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_CHARACTERISTICS
+
+Where XXXXXXX is the name of the virtual machine used in the authuser field of the request. This virtual machine also has to be authorized
+to access the system's directory manager.
+"""
+ 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()