?? ibmhmc.c
字號:
/* * Stonith module for IBM pSeries Hardware Management Console (HMC) * * Author: Huang Zhen <zhenh@cn.ibm.com> * Support for HMC V4+ added by Dave Blaschke <debltc@us.ibm.com> * * Copyright (c) 2004 International Business Machines * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//* * * This code has been tested in following environment: * * Hardware Management Console (HMC): Release 3, Version 2.4 * - Both FullSystemPartition and LPAR Partition: * - p630 7028-6C4 two LPAR partitions * - p650 7038-6M2 one LPAR partition and FullSystemPartition * * Hardware Management Console (HMC): Version 4, Release 2.1 * - OP720 1000-6CA three LPAR partitions * * Note: Only SSH access to the HMC devices are supported. * * This command would make a nice status command: * * lshmc -r -F ssh * * The following V3 command will get the list of systems we control and their * mode: * * lssyscfg -r sys -F name:mode --all * * 0 indicates full system partition * 255 indicates the system is partitioned * * The following V4 command will get the list of systems we control: * * lssyscfg -r sys -F name * * The following V3 command will get the list of partitions for a given managed * system running partitioned: * * lssyscfg -m managed-system -r lpar -F name --all * * Note that we should probably only consider partitions whose boot mode * is normal (1). (that's my guess, anyway...) * * The following V4 command will get the list of partitions for a given managed * system running partitioned: * * lssyscfg -m managed-system -r lpar -F name * * The following V3 commands provide the reset actions: * * FULL SYSTEM: * on: chsysstate -m %1 -r sys -o on -n %1 -c full * off: chsysstate -m %1 -r sys -o off -n %1 -c full -b norm * reset:chsysstate -m %1 -r sys -o reset -n %1 -c full -b norm * * Partitioned SYSTEM: * on: chsysstate -m %1 -r lpar -o on -n %2 * off: reset_partition -m %1 -p %2 -t hard * reset:do off action above, followed by on action... * * where %1 is managed-system, %2 is-lpar name * * The following V4 commands provide the reset actions: * * on: chsysstate -m %1 -r lpar -o on -n %2 -f %3 * off: chsysstate -m %1 -r lpar -o shutdown -n %2 --immed * reset:chsysstate -m %1 -r lpar -o shutdown -n %2 --immed --restart * * where %1 is managed-system, %2 is lpar-name, %3 is profile-name * * Of course, to do all this, we need to track which partition name goes with * which managed system's name, and which systems on the HMC are partitioned * and which ones aren't... */ #include <portability.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <libintl.h>#include <sys/wait.h>#include <glib.h>#include <stonith/stonith.h>#include <pils/plugin.h>#ifndef SSH_CMD# define SSH_CMD "ssh"#endif#ifndef HMCROOT# define HMCROOT "hscroot"#endif#define PIL_PLUGINTYPE STONITH_TYPE#define PIL_PLUGINTYPE_S STONITH_TYPE_S#define PIL_PLUGIN ibmhmc#define PIL_PLUGIN_S "ibmhmc"#define PIL_PLUGINLICENSE LICENSE_LGPL#define PIL_PLUGINLICENSEURL URL_LGPL#define LOG PluginImports->log#define MALLOC PluginImports->alloc#define STRDUP PluginImports->mstrdup#define FREE PluginImports->mfree#define EXPECT_TOK OurImports->ExpectToken#define STARTPROC OurImports->StartProcess#define MAX_HOST_NAME_LEN (256*4)#define MAX_CMD_LEN 1024#define FULLSYSTEMPARTITION "FullSystemPartition"#define MAX_POWERON_RETRY 10#define WHITESPACE " \t\n\r\f"#define STATE_UNKNOWN -1#define STATE_OFF 0#define STATE_ON 1#define STATE_INVALID 2#define HMCURL "http://publib-b.boulder.ibm.com/Redbooks.nsf/RedbookAbstracts/SG247038.html"static void * ibmhmc_new(void);static void ibmhmc_destroy(Stonith *);static int ibmhmc_set_config_file(Stonith *, const char * cfgname);static int ibmhmc_set_config_info(Stonith *, const char * info);static const char * ibmhmc_getinfo(Stonith * s, int InfoType);static int ibmhmc_status(Stonith * );static int ibmhmc_reset_req(Stonith* s,int request,const char* host);static char ** ibmhmc_hostlist(Stonith *);static void ibmhmc_free_hostlist(char **);static void ibmhmc_closepi(PILPlugin*pi);static PIL_rc ibmhmc_closeintf(PILInterface* pi, void* pd);static struct stonith_ops ibmhmcOps ={ ibmhmc_new, /* Create new STONITH object */ ibmhmc_destroy, /* Destroy STONITH object */ ibmhmc_set_config_file, /* set configuration from file */ ibmhmc_set_config_info, /* Get configuration from file */ ibmhmc_getinfo, /* Return STONITH info string */ ibmhmc_status, /* Return STONITH device status */ ibmhmc_reset_req, /* Request a reset */ ibmhmc_hostlist, /* Return list of supported hosts */ ibmhmc_free_hostlist /* free above list */};PIL_PLUGIN_BOILERPLATE("1.0", Debug, ibmhmc_closepi);static const PILPluginImports* PluginImports;static PILPlugin* OurPlugin;static PILInterface* OurInterface;static StonithImports* OurImports;static void* interfprivate;PIL_rcPIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);PIL_rcPIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports){ /* Force the compiler to do a little type checking */ (void)(PILPluginInitFun)PIL_PLUGIN_INIT; PluginImports = imports; OurPlugin = us; /* Register ourself as a plugin */ imports->register_plugin(us, &OurPIExports); /* Register our interface implementation */ return imports->register_interface(us, PIL_PLUGINTYPE_S , PIL_PLUGIN_S , &ibmhmcOps , ibmhmc_closeintf /*close */ , &OurInterface , (void*)&OurImports , &interfprivate); }struct HMCDevice { const char * HMCid; GList* hostlist; char * hmc; int hmcver; char ** mansyspats;};static const char * HMCid = "HMCDevice-Stonith";static const char * NOTibmhmcID = "HMC device has been destroyed";static int get_hmc_hostlist(struct HMCDevice* dev);static void free_hmc_hostlist(struct HMCDevice* dev);static int get_hmc_mansyspats(struct HMCDevice* dev, const char* mansyspats);static void free_hmc_mansyspats(struct HMCDevice* dev);static char* do_shell_cmd(const char* cmd, int* status);static int check_hmc_status(const char* hmc);static int get_num_tokens(char *str);static gboolean pattern_match(char **patterns, char *string);#define ISHMCDEV(i) (((i) != NULL && (i)->pinfo != NULL) \ && ((struct HMCDevice *)(i->pinfo))->HMCid == HMCid)#ifndef MALLOCT #define MALLOCT(t) ((t *)(MALLOC(sizeof(t)))) #endif#define N_(text) (text)#define _(text) dgettext(ST_TEXTDOMAIN, text)static voidibmhmc_closepi(PILPlugin*pi){}static PIL_rcibmhmc_closeintf(PILInterface* pi, void* pd){ return PIL_OK;}static intibmhmc_status(Stonith *s){ struct HMCDevice* dev; if (!ISHMCDEV(s)) { PILCallLog(LOG, PIL_CRIT, "invalid argument to %s" , __FUNCTION__); return(S_OOPS); } dev = (struct HMCDevice*) s->pinfo; return check_hmc_status(dev->hmc);}/* * Return the list of hosts configured for this HMC device */static char **ibmhmc_hostlist(Stonith *s){ int j; struct HMCDevice* dev; int numnames = 0; char** ret = NULL; GList* node = NULL; if (!ISHMCDEV(s)) { PILCallLog(LOG, PIL_CRIT, "invalid argument to %s" , __FUNCTION__); return(NULL); } dev = (struct HMCDevice*) s->pinfo; /* refresh the hostlist */ free_hmc_hostlist(dev); if (S_OK != get_hmc_hostlist(dev)){ PILCallLog(LOG, PIL_CRIT, "unable to obtain list of managed " " systems in %s", __FUNCTION__); return NULL; } numnames = g_list_length(dev->hostlist); if (numnames < 0) { PILCallLog(LOG, PIL_CRIT, "unconfigured stonith object in %s" , __FUNCTION__); return(NULL); } ret = (char **)MALLOC((numnames+1)*sizeof(char*)); if (ret == NULL) { PILCallLog(LOG, PIL_CRIT, "out of memory"); return ret; } memset(ret, 0, (numnames+1)*sizeof(char*)); for (node = g_list_first(dev->hostlist), j = 0 ; NULL != node ; j++, node = g_list_next(node)) { char* host = strchr((char*)node->data, '/'); ret[j] = STRDUP(++host); } return ret;}static voidibmhmc_free_hostlist (char** hlist){ char** hl = hlist; if (hl == NULL) { return; } while (*hl) { FREE(*hl); *hl = NULL; ++hl; } FREE(hlist); hlist = NULL;}/* * Parse the config information, and stash it away... */static intibmhmc_parse_config_info(struct HMCDevice* dev, const char * info){ char get_hmcver[MAX_CMD_LEN]; char firstchar; int firstnum; char* output = NULL; int status; char *pch; char *infocopy; /* -p or -F option with args "ipaddr [managedsyspat]..." */ pch = infocopy = STRDUP(info); if (pch == NULL) { PILCallLog(LOG, PIL_CRIT, "out of memory"); return S_OOPS; } /* skip over ipaddr and null-terminate */ pch += strcspn(pch, WHITESPACE); *pch = EOS; /* skip over white-space up to next token */ pch++; pch += strspn(pch, WHITESPACE); if (get_hmc_mansyspats(dev, pch) != S_OK) { FREE(infocopy); return S_OOPS; } dev->hmc = STRDUP(infocopy); FREE(infocopy); /* check whether the HMC has ssh command enabled */ if (check_hmc_status(dev->hmc) != S_OK) { PILCallLog(LOG, PIL_CRIT, "HMC %s does not have remote " "command execution using the ssh facility enabled", dev->hmc); return S_BADCONFIG; } /* get the HMC's version info */ snprintf(get_hmcver, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s lshmc -v | grep RM", dev->hmc); if (Debug) { PILCallLog(LOG, PIL_DEBUG, "%s: get_hmcver=%s" , __FUNCTION__, get_hmcver); } output = do_shell_cmd(get_hmcver, &status); if (Debug) { PILCallLog(LOG, PIL_DEBUG, "%s: output=%s\n", __FUNCTION__ , output ? output : "(nil)"); } if (output == NULL) { return S_BADCONFIG; } /* parse the HMC's version info (i.e. "*RM V4R2.1" or "*RM R3V2.6") */ if ((sscanf(output, "*RM %c%1d", &firstchar, &firstnum) == 2) && ((firstchar == 'V') || (firstchar == 'R'))) { dev->hmcver = firstnum; if(Debug){ PILCallLog(LOG, PIL_DEBUG, "%s: HMC %s version is %d" , __FUNCTION__, dev->hmc, dev->hmcver); } }else{ PILCallLog(LOG, PIL_CRIT, "%s: unable to determine HMC %s " " version", __FUNCTION__, dev->hmc); FREE(output); return S_BADCONFIG; } FREE(output); if (S_OK != get_hmc_hostlist(dev)){ PILCallLog(LOG, PIL_CRIT, "unable to obtain list of managed " " systems in %s", __FUNCTION__); return S_BADCONFIG; } return S_OK;}/* * Reset the given host, and obey the request type. * We should reset without power cycle for the non-partitioned case */static intibmhmc_reset_req(Stonith * s, int request, const char * host){ GList* node = NULL; struct HMCDevice* dev = NULL; char off_cmd[MAX_CMD_LEN]; char on_cmd[MAX_CMD_LEN]; char reset_cmd[MAX_CMD_LEN]; gchar** names = NULL; int i; int is_lpar = FALSE; int status; char* pch; char* output = NULL; char state_cmd[MAX_CMD_LEN]; int state = STATE_UNKNOWN; if (!ISHMCDEV(s) || (NULL == host)) { PILCallLog(LOG, PIL_CRIT, "invalid argument to %s" , __FUNCTION__); return(S_OOPS); } dev = (struct HMCDevice*) s->pinfo; for (node = g_list_first(dev->hostlist) ; NULL != node ; node = g_list_next(node)) { if(Debug){ PILCallLog(LOG, PIL_DEBUG, "%s: node->data=%s\n" , __FUNCTION__, (char*)node->data); } if ((pch = strchr((char*)node->data, '/')) != NULL && 0 == strcasecmp(++pch, host)) { break; } } if (!node) { PILCallLog(LOG, PIL_CRIT , "Host %s is not configured in this STONITH module. " "Please check your configuration information.", host); return (S_OOPS); } names = g_strsplit((char*)node->data, "/", 2); /* names[0] will be the name of managed system */ /* names[1] will be the name of the lpar partition */ if(Debug){ PILCallLog(LOG, PIL_DEBUG, "%s: names[0]=%s, names[1]=%s\n" , __FUNCTION__, names[0], names[1]); } if (dev->hmcver < 4) { if (0 == strcasecmp(names[1], FULLSYSTEMPARTITION)) { is_lpar = FALSE; snprintf(off_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s chsysstate" " -r sys -m %s -o off -n %s -c full" , dev->hmc, dev->hmc, names[0]); snprintf(on_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s chsysstate" " -r sys -m %s -o on -n %s -c full -b norm" , dev->hmc, names[0], names[0]); snprintf(reset_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s chsysstate" " -r sys -m %s -o reset -n %s -c full -b norm" , dev->hmc, names[0], names[0]); *state_cmd = 0; }else{ is_lpar = TRUE; snprintf(off_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s reset_partition" " -m %s -p %s -t hard" , dev->hmc, names[0], names[1]); snprintf(on_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s chsysstate" " -r lpar -m %s -o on -n %s" , dev->hmc, names[0], names[1]); *reset_cmd = 0; snprintf(state_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s lssyscfg" " -r lpar -m %s -F state -n %s" , dev->hmc, names[0], names[1]); } }else{ is_lpar = TRUE; snprintf(off_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s chsysstate" " -m %s -r lpar -o shutdown -n \"%s\" --immed" , dev->hmc, names[0], names[1]); snprintf(on_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s lssyscfg" " -m %s -r lpar -F \"default_profile\"" " --filter \"lpar_names=%s\"" , dev->hmc, names[0], names[1]); output = do_shell_cmd(on_cmd, &status); if (output == NULL) { PILCallLog(LOG, PIL_CRIT, "command %s failed", on_cmd); return (S_OOPS); } if ((pch = strchr(output, '\n')) != NULL) { *pch = 0; } snprintf(on_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s chsysstate" " -m %s -r lpar -o on -n %s -f %s" , dev->hmc, names[0], names[1], output); FREE(output); output = NULL; snprintf(reset_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s chsysstate" " -m %s -r lpar -o shutdown -n %s --immed --restart" , dev->hmc, names[0], names[1]); snprintf(state_cmd, MAX_CMD_LEN , SSH_CMD " -l " HMCROOT " %s lssyscfg" " -m %s -r lpar -F state --filter \"lpar_names=%s\"" , dev->hmc, names[0], names[1]); } g_strfreev(names); if(Debug){ LOG(PIL_DEBUG, "%s: off_cmd=%s, on_cmd=%s," "reset_cmd=%s, state_cmd=%s\n" , __FUNCTION__, off_cmd, on_cmd, reset_cmd, state_cmd); } output = do_shell_cmd(state_cmd, &status); if (output == NULL) { PILCallLog(LOG, PIL_CRIT, "command %s failed", on_cmd); return S_OOPS; } if ((pch = strchr(output, '\n')) != NULL) { *pch = 0; } if (strcmp(output, "Running") == 0 || strcmp(output, "Starting") == 0 || strcmp(output, "Open Firmware") == 0) { state = STATE_ON; }else if (strcmp(output, "Shutting Down") == 0 || strcmp(output, "Not Activated") == 0 || strcmp(output, "Ready") == 0) { state = STATE_OFF;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -