2
* This program is free software; you can redistribute it and/or
3
* modify it under the terms of the GNU General Public
4
* License as published by the Free Software Foundation; either
5
* version 2.1 of the License, or (at your option) any later version.
7
* This software is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
* General Public License for more details.
12
* You should have received a copy of the GNU General Public
13
* License along with this library; if not, write to the Free Software
14
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
* Author: Sun Jiang Dong <sunjd@cn.ibm.com>
18
* Copyright (c) 2004 International Business Machines
20
* This code implements the Resource Agent Plugin Module for LSB style.
21
* It's a part of Local Resource Manager. Currently it's used by lrmd only.
24
#include <lha_internal.h>
29
#include <sys/types.h>
36
#include <clplumbing/cl_log.h>
37
#include <pils/plugin.h>
38
#include <lrm/raexec.h>
40
#define PIL_PLUGINTYPE RA_EXEC_TYPE
41
#define PIL_PLUGIN heartbeat
42
#define PIL_PLUGINTYPE_S "RAExec"
43
#define PIL_PLUGIN_S "heartbeat"
44
#define PIL_PLUGINLICENSE LICENSE_PUBDOM
45
#define PIL_PLUGINLICENSEURL URL_PUBDOM
47
static const char * RA_PATH = HB_RA_DIR;
49
static const char meta_data_template[] =
50
"<?xml version=\"1.0\"?>\n"
51
"<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
52
"<resource-agent name=\"%s\">\n"
53
"<version>1.0</version>\n"
54
"<longdesc lang=\"en\">\n"
57
"<shortdesc lang=\"en\">%s</shortdesc>\n"
59
"<parameter name=\"1\" unique=\"1\" required=\"0\">\n"
60
"<longdesc lang=\"en\">\n"
61
"This argument will be passed as the first argument to the "
62
"heartbeat resource agent (assuming it supports one)\n"
64
"<shortdesc lang=\"en\">argv[1]</shortdesc>\n"
65
"<content type=\"string\" default=\" \" />\n"
67
"<parameter name=\"2\" unique=\"1\" required=\"0\">\n"
68
"<longdesc lang=\"en\">\n"
69
"This argument will be passed as the second argument to the "
70
"heartbeat resource agent (assuming it supports one)\n"
72
"<shortdesc lang=\"en\">argv[2]</shortdesc>\n"
73
"<content type=\"string\" default=\" \" />\n"
75
"<parameter name=\"3\" unique=\"1\" required=\"0\">\n"
76
"<longdesc lang=\"en\">\n"
77
"This argument will be passed as the third argument to the "
78
"heartbeat resource agent (assuming it supports one)\n"
80
"<shortdesc lang=\"en\">argv[3]</shortdesc>\n"
81
"<content type=\"string\" default=\" \" />\n"
83
"<parameter name=\"4\" unique=\"1\" required=\"0\">\n"
84
"<longdesc lang=\"en\">\n"
85
"This argument will be passed as the fourth argument to the "
86
"heartbeat resource agent (assuming it supports one)\n"
88
"<shortdesc lang=\"en\">argv[4]</shortdesc>\n"
89
"<content type=\"string\" default=\" \" />\n"
91
"<parameter name=\"5\" unique=\"1\" required=\"0\">\n"
92
"<longdesc lang=\"en\">\n"
93
"This argument will be passed as the fifth argument to the "
94
"heartbeat resource agent (assuming it supports one)\n"
96
"<shortdesc lang=\"en\">argv[5]</shortdesc>\n"
97
"<content type=\"string\" default=\" \" />\n"
101
"<action name=\"start\" timeout=\"15\" />\n"
102
"<action name=\"stop\" timeout=\"15\" />\n"
103
"<action name=\"status\" timeout=\"15\" />\n"
104
"<action name=\"monitor\" timeout=\"15\" interval=\"15\" start-delay=\"15\" />\n"
105
"<action name=\"meta-data\" timeout=\"5\" />\n"
107
"<special tag=\"heartbeart\">\n"
109
"</resource-agent>\n";
111
/* The begin of exported function list */
112
static int execra(const char * rsc_id,
113
const char * rsc_type,
114
const char * provider,
115
const char * op_type,
117
GHashTable * params);
119
static uniform_ret_execra_t map_ra_retvalue(int ret_execra
120
, const char * op_type, const char * std_output);
121
static int get_resource_list(GList ** rsc_info);
122
static char* get_resource_meta(const char* rsc_type, const char* provider);
123
static int get_provider_list(const char* ra_type, GList ** providers);
125
/* The end of exported function list */
127
/* The begin of internal used function & data list */
128
#define HADEBUGVAL "HA_debug"
129
#define MAX_PARAMETER_NUM 40
130
typedef char * RA_ARGV[MAX_PARAMETER_NUM];
132
static const int MAX_LENGTH_OF_RSCNAME = 40,
133
MAX_LENGTH_OF_OPNAME = 40;
135
static int prepare_cmd_parameters(const char * rsc_type, const char * op_type,
136
GHashTable * params, RA_ARGV params_argv);
137
/* The end of internal function & data list */
139
/* Rource agent execution plugin operations */
140
static struct RAExecOps raops =
148
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
150
static const PILPluginImports* PluginImports;
151
static PILPlugin* OurPlugin;
152
static PILInterface* OurInterface;
153
static void* OurImports;
154
static void* interfprivate;
155
static int idebuglevel = 0;
158
* Our plugin initialization and registration function
159
* It gets called when the plugin gets loaded.
162
PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports);
165
PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports)
167
/* Force the compiler to do a little type checking */
168
(void)(PILPluginInitFun)PIL_PLUGIN_INIT;
170
PluginImports = imports;
173
/* Register ourself as a plugin */
174
imports->register_plugin(us, &OurPIExports);
176
if (getenv(HADEBUGVAL) != NULL && atoi(getenv(HADEBUGVAL)) > 0 ) {
177
idebuglevel = atoi(getenv(HADEBUGVAL));
178
cl_log(LOG_DEBUG, "LRM debug level set to %d", idebuglevel);
181
/* Register our interfaces */
182
return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S,
183
&raops, NULL, &OurInterface, &OurImports,
188
* Real work starts here ;-)
192
execra( const char * rsc_id, const char * rsc_type, const char * provider,
193
const char * op_type, const int timeout, GHashTable * params)
196
char ra_pathname[RA_MAX_NAME_LENGTH];
197
uniform_ret_execra_t exit_value;
198
GString * debug_info;
199
char * optype_tmp = NULL;
202
/* How to generate the meta-data? There is nearly no value
203
* information in meta-data build up in current way.
204
* Should directly add meta-data to the script itself?
206
if ( 0 == STRNCMP_CONST(op_type, "meta-data") ) {
207
printf("%s", get_resource_meta(rsc_type, provider));
211
/* To simulate the 'monitor' operation with 'status'.
212
* Now suppose there is no 'monitor' operation for heartbeat scripts.
214
if ( 0 == STRNCMP_CONST(op_type, "monitor") ) {
215
optype_tmp = g_strdup("status");
217
optype_tmp = g_strdup(op_type);
220
/* Prepare the call parameter */
221
if (0 > prepare_cmd_parameters(rsc_type, optype_tmp, params, params_argv)) {
222
cl_log(LOG_ERR, "HB RA: Error of preparing parameters");
228
get_ra_pathname(RA_PATH, rsc_type, NULL, ra_pathname);
230
/* let this log show only high loglevel. */
231
if (idebuglevel > 1) {
232
debug_info = g_string_new("");
234
g_string_append(debug_info, params_argv[index_tmp]);
235
g_string_append(debug_info, " ");
236
} while (params_argv[++index_tmp] != NULL);
237
debug_info->str[debug_info->len-1] = '\0';
239
cl_log(LOG_DEBUG, "RA instance %s executing: heartbeat::%s"
240
, rsc_id, debug_info->str);
242
g_string_free(debug_info, TRUE);
245
closefiles(); /* don't leak open files */
246
execv(ra_pathname, params_argv);
247
cl_perror("(%s:%s:%d) execv failed for %s"
248
, __FILE__, __FUNCTION__, __LINE__, ra_pathname);
251
case ENOENT: /* No such file or directory */
252
case EISDIR: /* Is a directory */
253
exit_value = EXECRA_NOT_INSTALLED;
256
exit_value = EXECRA_EXEC_UNKNOWN_ERROR;
262
prepare_cmd_parameters(const char * rsc_type, const char * op_type,
263
GHashTable * params_ht, RA_ARGV params_argv)
272
ht_size = g_hash_table_size(params_ht);
274
if ( ht_size+3 > MAX_PARAMETER_NUM ) {
275
cl_log(LOG_ERR, "Too many parameters");
279
/* Now suppose the parameter format stored in Hashtabe is as like as
280
* key="1", value="-Wl,soname=test"
281
* Moreover, the key is supposed as a string transfered from an integer.
282
* It may be changed in the future.
284
/* Notice: if ht_size==0, no actual arguments except op_type */
285
for (index = 1; index <= ht_size; index++ ) {
286
snprintf(buf_tmp, sizeof(buf_tmp), "%d", index);
287
value_tmp = g_hash_table_lookup(params_ht, buf_tmp);
288
/* suppose the key is consecutive */
289
if ( value_tmp == NULL ) {
290
/* cl_log(LOG_WARNING, "Parameter ordering error in"\
291
"prepare_cmd_parameters, raexeclsb.c");
292
cl_log(LOG_WARNING, "search key=%s.", buf_tmp);
296
params_argv[param_num] = g_strdup((char *)value_tmp);
299
tmp_len = strnlen(rsc_type, MAX_LENGTH_OF_RSCNAME);
300
params_argv[0] = g_strndup(rsc_type, tmp_len);
301
/* Add operation code as the last argument */
302
tmp_len = strnlen(op_type, MAX_LENGTH_OF_OPNAME);
303
params_argv[param_num+1] = g_strndup(op_type, tmp_len);
304
/* Add the teminating NULL pointer */
305
params_argv[param_num+2] = NULL;
309
static uniform_ret_execra_t
310
map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output)
313
/* Now there is no formal related specification for Heartbeat RA
314
* scripts. Temporarily deal as LSB init script.
316
/* Except op_type equals 'status', the UNIFORM_RET_EXECRA is compatible
319
const char * stop_pattern1 = "*stopped*",
320
* stop_pattern2 = "*not*running*",
321
* running_pattern1 = "*running*",
322
* running_pattern2 = "*OK*";
323
char * lower_std_output = NULL;
325
if(ret_execra == EXECRA_NOT_INSTALLED) {
329
if ( 0 == STRNCMP_CONST(op_type, "status")
330
|| 0 == STRNCMP_CONST(op_type, "monitor")) {
331
if (std_output == NULL ) {
332
cl_log(LOG_WARNING, "No status output from the (hb) resource agent.");
333
return EXECRA_NOT_RUNNING;
337
cl_log(LOG_DEBUG, "RA output was: [%s]", std_output);
340
lower_std_output = g_ascii_strdown(std_output, -1);
342
if ( TRUE == g_pattern_match_simple(stop_pattern1
343
, lower_std_output) || TRUE ==
344
g_pattern_match_simple(stop_pattern2
345
, lower_std_output) ) {
348
, "RA output [%s] matched stopped pattern"
354
ret_execra = EXECRA_NOT_RUNNING; /* stopped */
355
} else if ( TRUE == g_pattern_match_simple(running_pattern1
356
, lower_std_output) || TRUE ==
357
g_pattern_match_simple(running_pattern2
361
, "RA output [%s] matched running"
362
" pattern [%s] or [%s]"
363
, std_output, running_pattern1
366
ret_execra = EXECRA_OK; /* running */
368
/* It didn't say it was running - must be stopped */
369
cl_log(LOG_DEBUG, "RA output [%s] didn't match any pattern"
371
ret_execra = EXECRA_NOT_RUNNING; /* stopped */
373
g_free(lower_std_output);
375
/* For non-status operation return code */
376
if (ret_execra < 0) {
377
ret_execra = EXECRA_UNKNOWN_ERROR;
383
get_resource_list(GList ** rsc_info)
385
return get_runnable_list(RA_PATH, rsc_info);
389
get_resource_meta(const char* rsc_type, const char* provider)
393
meta_data = g_string_new("");
394
g_string_sprintf( meta_data, meta_data_template, rsc_type
395
, rsc_type, rsc_type);
396
return meta_data->str;
399
get_provider_list(const char* ra_type, GList ** providers)
401
if ( providers == NULL ) {
402
cl_log(LOG_ERR, "%s:%d: Parameter error: providers==NULL"
403
, __FUNCTION__, __LINE__);
407
if ( *providers != NULL ) {
408
cl_log(LOG_ERR, "%s:%d: Parameter error: *providers==NULL."
409
"This will cause memory leak."
410
, __FUNCTION__, __LINE__);
413
/* Now temporarily make it fixed */
414
*providers = g_list_append(*providers, g_strdup("heartbeat"));
416
return g_list_length(*providers);