diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:40:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:40:13 +0000 |
commit | e9be59e1502a41bab9891d96d753102a7dafef0b (patch) | |
tree | c3b2da87c414881f4b53d0964f407c83492d813e /lib/plugins/lrm/raexechb.c | |
parent | Initial commit. (diff) | |
download | cluster-glue-upstream.tar.xz cluster-glue-upstream.zip |
Adding upstream version 1.0.12.upstream/1.0.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/plugins/lrm/raexechb.c')
-rw-r--r-- | lib/plugins/lrm/raexechb.c | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/lib/plugins/lrm/raexechb.c b/lib/plugins/lrm/raexechb.c new file mode 100644 index 0000000..f9f1eb9 --- /dev/null +++ b/lib/plugins/lrm/raexechb.c @@ -0,0 +1,416 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 software 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 + * General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * File: raexechb.c + * Author: Sun Jiang Dong <sunjd@cn.ibm.com> + * Copyright (c) 2004 International Business Machines + * + * This code implements the Resource Agent Plugin Module for LSB style. + * It's a part of Local Resource Manager. Currently it's used by lrmd only. + */ + +#include <lha_internal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <errno.h> +#include <dirent.h> +#include <libgen.h> +#include <glib.h> +#include <clplumbing/cl_log.h> +#include <pils/plugin.h> +#include <lrm/raexec.h> + +#define PIL_PLUGINTYPE RA_EXEC_TYPE +#define PIL_PLUGIN heartbeat +#define PIL_PLUGINTYPE_S "RAExec" +#define PIL_PLUGIN_S "heartbeat" +#define PIL_PLUGINLICENSE LICENSE_PUBDOM +#define PIL_PLUGINLICENSEURL URL_PUBDOM + +static const char * RA_PATH = HB_RA_DIR; + +static const char meta_data_template[] = +"<?xml version=\"1.0\"?>\n" +"<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n" +"<resource-agent name=\"%s\">\n" +"<version>1.0</version>\n" +"<longdesc lang=\"en\">\n" +"%s" +"</longdesc>\n" +"<shortdesc lang=\"en\">%s</shortdesc>\n" +"<parameters>\n" +"<parameter name=\"1\" unique=\"1\" required=\"0\">\n" +"<longdesc lang=\"en\">\n" +"This argument will be passed as the first argument to the " +"heartbeat resource agent (assuming it supports one)\n" +"</longdesc>\n" +"<shortdesc lang=\"en\">argv[1]</shortdesc>\n" +"<content type=\"string\" default=\" \" />\n" +"</parameter>\n" +"<parameter name=\"2\" unique=\"1\" required=\"0\">\n" +"<longdesc lang=\"en\">\n" +"This argument will be passed as the second argument to the " +"heartbeat resource agent (assuming it supports one)\n" +"</longdesc>\n" +"<shortdesc lang=\"en\">argv[2]</shortdesc>\n" +"<content type=\"string\" default=\" \" />\n" +"</parameter>\n" +"<parameter name=\"3\" unique=\"1\" required=\"0\">\n" +"<longdesc lang=\"en\">\n" +"This argument will be passed as the third argument to the " +"heartbeat resource agent (assuming it supports one)\n" +"</longdesc>\n" +"<shortdesc lang=\"en\">argv[3]</shortdesc>\n" +"<content type=\"string\" default=\" \" />\n" +"</parameter>\n" +"<parameter name=\"4\" unique=\"1\" required=\"0\">\n" +"<longdesc lang=\"en\">\n" +"This argument will be passed as the fourth argument to the " +"heartbeat resource agent (assuming it supports one)\n" +"</longdesc>\n" +"<shortdesc lang=\"en\">argv[4]</shortdesc>\n" +"<content type=\"string\" default=\" \" />\n" +"</parameter>\n" +"<parameter name=\"5\" unique=\"1\" required=\"0\">\n" +"<longdesc lang=\"en\">\n" +"This argument will be passed as the fifth argument to the " +"heartbeat resource agent (assuming it supports one)\n" +"</longdesc>\n" +"<shortdesc lang=\"en\">argv[5]</shortdesc>\n" +"<content type=\"string\" default=\" \" />\n" +"</parameter>\n" +"</parameters>\n" +"<actions>\n" +"<action name=\"start\" timeout=\"15\" />\n" +"<action name=\"stop\" timeout=\"15\" />\n" +"<action name=\"status\" timeout=\"15\" />\n" +"<action name=\"monitor\" timeout=\"15\" interval=\"15\" start-delay=\"15\" />\n" +"<action name=\"meta-data\" timeout=\"5\" />\n" +"</actions>\n" +"<special tag=\"heartbeart\">\n" +"</special>\n" +"</resource-agent>\n"; + +/* The begin of exported function list */ +static int execra(const char * rsc_id, + const char * rsc_type, + const char * provider, + const char * op_type, + const int timeout, + GHashTable * params); + +static uniform_ret_execra_t map_ra_retvalue(int ret_execra + , const char * op_type, const char * std_output); +static int get_resource_list(GList ** rsc_info); +static char* get_resource_meta(const char* rsc_type, const char* provider); +static int get_provider_list(const char* ra_type, GList ** providers); + +/* The end of exported function list */ + +/* The begin of internal used function & data list */ +#define MAX_PARAMETER_NUM 40 +typedef char * RA_ARGV[MAX_PARAMETER_NUM]; + +static const int MAX_LENGTH_OF_RSCNAME = 40, + MAX_LENGTH_OF_OPNAME = 40; + +static int prepare_cmd_parameters(const char * rsc_type, const char * op_type, + GHashTable * params, RA_ARGV params_argv); +/* The end of internal function & data list */ + +/* Rource agent execution plugin operations */ +static struct RAExecOps raops = +{ execra, + map_ra_retvalue, + get_resource_list, + get_provider_list, + get_resource_meta +}; + +PIL_PLUGIN_BOILERPLATE2("1.0", Debug) + +static const PILPluginImports* PluginImports; +static PILPlugin* OurPlugin; +static PILInterface* OurInterface; +static void* OurImports; +static void* interfprivate; +static int idebuglevel = 0; + +/* + * Our plugin initialization and registration function + * It gets called when the plugin gets loaded. + */ +PIL_rc +PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports); + +PIL_rc +PIL_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); + + if (getenv(HADEBUGVAL) != NULL && atoi(getenv(HADEBUGVAL)) > 0 ) { + idebuglevel = atoi(getenv(HADEBUGVAL)); + cl_log(LOG_DEBUG, "LRM debug level set to %d", idebuglevel); + } + + /* Register our interfaces */ + return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, + &raops, NULL, &OurInterface, &OurImports, + interfprivate); +} + +/* + * Real work starts here ;-) + */ + +static int +execra( const char * rsc_id, const char * rsc_type, const char * provider, + const char * op_type, const int timeout, GHashTable * params) +{ + RA_ARGV params_argv; + char ra_pathname[RA_MAX_NAME_LENGTH]; + uniform_ret_execra_t exit_value; + GString * debug_info; + char * optype_tmp = NULL; + int index_tmp = 0; + + /* How to generate the meta-data? There is nearly no value + * information in meta-data build up in current way. + * Should directly add meta-data to the script itself? + */ + if ( 0 == STRNCMP_CONST(op_type, "meta-data") ) { + printf("%s", get_resource_meta(rsc_type, provider)); + exit(0); + } + + /* To simulate the 'monitor' operation with 'status'. + * Now suppose there is no 'monitor' operation for heartbeat scripts. + */ + if ( 0 == STRNCMP_CONST(op_type, "monitor") ) { + optype_tmp = g_strdup("status"); + } else { + optype_tmp = g_strdup(op_type); + } + + /* Prepare the call parameter */ + if (0 > prepare_cmd_parameters(rsc_type, optype_tmp, params, params_argv)) { + cl_log(LOG_ERR, "HB RA: Error of preparing parameters"); + g_free(optype_tmp); + return -1; + } + g_free(optype_tmp); + + get_ra_pathname(RA_PATH, rsc_type, NULL, ra_pathname); + + /* let this log show only high loglevel. */ + if (idebuglevel > 1) { + debug_info = g_string_new(""); + do { + g_string_append(debug_info, params_argv[index_tmp]); + g_string_append(debug_info, " "); + } while (params_argv[++index_tmp] != NULL); + debug_info->str[debug_info->len-1] = '\0'; + + cl_log(LOG_DEBUG, "RA instance %s executing: heartbeat::%s" + , rsc_id, debug_info->str); + + g_string_free(debug_info, TRUE); + } + + closefiles(); /* don't leak open files */ + execv(ra_pathname, params_argv); + cl_perror("(%s:%s:%d) execv failed for %s" + , __FILE__, __FUNCTION__, __LINE__, ra_pathname); + + switch (errno) { + case ENOENT: /* No such file or directory */ + case EISDIR: /* Is a directory */ + exit_value = EXECRA_NOT_INSTALLED; + break; + default: + exit_value = EXECRA_EXEC_UNKNOWN_ERROR; + } + exit(exit_value); +} + +static int +prepare_cmd_parameters(const char * rsc_type, const char * op_type, + GHashTable * params_ht, RA_ARGV params_argv) +{ + int tmp_len, index; + int ht_size = 0; + int param_num = 0; + char buf_tmp[20]; + void * value_tmp; + + if (params_ht) { + ht_size = g_hash_table_size(params_ht); + } + if ( ht_size+3 > MAX_PARAMETER_NUM ) { + cl_log(LOG_ERR, "Too many parameters"); + return -1; + } + + /* Now suppose the parameter format stored in Hashtabe is as like as + * key="1", value="-Wl,soname=test" + * Moreover, the key is supposed as a string transfered from an integer. + * It may be changed in the future. + */ + /* Notice: if ht_size==0, no actual arguments except op_type */ + for (index = 1; index <= ht_size; index++ ) { + snprintf(buf_tmp, sizeof(buf_tmp), "%d", index); + value_tmp = g_hash_table_lookup(params_ht, buf_tmp); + /* suppose the key is consecutive */ + if ( value_tmp == NULL ) { +/* cl_log(LOG_WARNING, "Parameter ordering error in"\ + "prepare_cmd_parameters, raexeclsb.c"); + cl_log(LOG_WARNING, "search key=%s.", buf_tmp); +*/ continue; + } + param_num ++; + params_argv[param_num] = g_strdup((char *)value_tmp); + } + + tmp_len = strnlen(rsc_type, MAX_LENGTH_OF_RSCNAME); + params_argv[0] = g_strndup(rsc_type, tmp_len); + /* Add operation code as the last argument */ + tmp_len = strnlen(op_type, MAX_LENGTH_OF_OPNAME); + params_argv[param_num+1] = g_strndup(op_type, tmp_len); + /* Add the teminating NULL pointer */ + params_argv[param_num+2] = NULL; + return 0; +} + +static uniform_ret_execra_t +map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output) +{ + + /* Now there is no formal related specification for Heartbeat RA + * scripts. Temporarily deal as LSB init script. + */ + /* Except op_type equals 'status', the UNIFORM_RET_EXECRA is compatible + with LSB standard. + */ + const char * stop_pattern1 = "*stopped*", + * stop_pattern2 = "*not*running*", + * running_pattern1 = "*running*", + * running_pattern2 = "*OK*"; + char * lower_std_output = NULL; + + if(ret_execra == EXECRA_NOT_INSTALLED) { + return ret_execra; + } + + if ( 0 == STRNCMP_CONST(op_type, "status") + || 0 == STRNCMP_CONST(op_type, "monitor")) { + if (std_output == NULL ) { + cl_log(LOG_WARNING, "No status output from the (hb) resource agent."); + return EXECRA_NOT_RUNNING; + } + + if (idebuglevel) { + cl_log(LOG_DEBUG, "RA output was: [%s]", std_output); + } + + lower_std_output = g_ascii_strdown(std_output, -1); + + if ( TRUE == g_pattern_match_simple(stop_pattern1 + , lower_std_output) || TRUE == + g_pattern_match_simple(stop_pattern2 + , lower_std_output) ) { + if (idebuglevel) { + cl_log(LOG_DEBUG + , "RA output [%s] matched stopped pattern" + " [%s] or [%s]" + , std_output + , stop_pattern1 + , stop_pattern2); + } + ret_execra = EXECRA_NOT_RUNNING; /* stopped */ + } else if ( TRUE == g_pattern_match_simple(running_pattern1 + , lower_std_output) || TRUE == + g_pattern_match_simple(running_pattern2 + , std_output) ) { + if (idebuglevel) { + cl_log(LOG_DEBUG + , "RA output [%s] matched running" + " pattern [%s] or [%s]" + , std_output, running_pattern1 + , running_pattern2); + } + ret_execra = EXECRA_OK; /* running */ + } else { + /* It didn't say it was running - must be stopped */ + cl_log(LOG_DEBUG, "RA output [%s] didn't match any pattern" + , std_output); + ret_execra = EXECRA_NOT_RUNNING; /* stopped */ + } + g_free(lower_std_output); + } + /* For non-status operation return code */ + if (ret_execra < 0) { + ret_execra = EXECRA_UNKNOWN_ERROR; + } + return ret_execra; +} + +static int +get_resource_list(GList ** rsc_info) +{ + return get_runnable_list(RA_PATH, rsc_info); +} + +static char* +get_resource_meta(const char* rsc_type, const char* provider) +{ + GString * meta_data; + + meta_data = g_string_new(""); + g_string_sprintf( meta_data, meta_data_template, rsc_type + , rsc_type, rsc_type); + return meta_data->str; +} +static int +get_provider_list(const char* ra_type, GList ** providers) +{ + if ( providers == NULL ) { + cl_log(LOG_ERR, "%s:%d: Parameter error: providers==NULL" + , __FUNCTION__, __LINE__); + return -2; + } + + if ( *providers != NULL ) { + cl_log(LOG_ERR, "%s:%d: Parameter error: *providers==NULL." + "This will cause memory leak." + , __FUNCTION__, __LINE__); + } + + /* Now temporarily make it fixed */ + *providers = g_list_append(*providers, g_strdup("heartbeat")); + + return g_list_length(*providers); +} |