diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:50:17 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:50:17 +0000 |
commit | 86ed03f8adee56c050c73018537371c230a664a6 (patch) | |
tree | eae3d04cdf1c49848e5a671327ab38297f4acb0d /agents/zvm | |
parent | Initial commit. (diff) | |
download | fence-agents-86ed03f8adee56c050c73018537371c230a664a6.tar.xz fence-agents-86ed03f8adee56c050c73018537371c230a664a6.zip |
Adding upstream version 4.12.1.upstream/4.12.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'agents/zvm')
-rw-r--r-- | agents/zvm/fence_zvm.c | 1056 | ||||
-rw-r--r-- | agents/zvm/fence_zvm.h | 583 | ||||
-rw-r--r-- | agents/zvm/fence_zvm_man_page | 88 | ||||
-rw-r--r-- | agents/zvm/fence_zvmip.c | 1001 | ||||
-rw-r--r-- | agents/zvm/fence_zvmip.py | 226 |
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() |