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>
30
#include <sys/types.h>
35
#include <clplumbing/cl_log.h>
36
#include <clplumbing/realtime.h>
37
#include <pils/plugin.h>
39
#include <libgen.h> /* Add it for compiling on OSX */
44
#include <lrm/raexec.h>
46
# define PIL_PLUGINTYPE RA_EXEC_TYPE
47
# define PIL_PLUGINTYPE_S "RAExec"
48
# define PIL_PLUGINLICENSE LICENSE_PUBDOM
49
# define PIL_PLUGINLICENSEURL URL_PUBDOM
51
# define PIL_PLUGIN ocf
52
# define PIL_PLUGIN_S "ocf"
54
* Are there multiple paths? Now according to OCF spec, the answer is 'no'.
55
* But actually or for future?
57
static const char * RA_PATH = OCF_RA_DIR;
59
/* The begin of exported function list */
60
static int execra(const char * rsc_id,
61
const char * rsc_type,
62
const char * provider,
66
static uniform_ret_execra_t map_ra_retvalue(int ret_execra,
67
const char * op_type, const char * std_output);
68
static int get_resource_list(GList ** rsc_info);
69
static char* get_resource_meta(const char* rsc_type, const char* provider);
70
static int get_provider_list(const char* ra_type, GList ** providers);
72
/* The end of exported function list */
74
/* The begin of internal used function & data list */
75
#define HADEBUGVAL "HA_debug"
77
static void add_OCF_prefix(GHashTable * params, GHashTable * new_params);
78
static void add_OCF_env_vars(GHashTable * env, const char * rsc_id,
79
const char * rsc_type, const char * provider);
80
static void add_prefix_foreach(gpointer key, gpointer value,
83
static void hash_to_str(GHashTable * , GString *);
84
static void hash_to_str_foreach(gpointer key, gpointer value,
87
static int raexec_setenv(GHashTable * env_params);
88
static void set_env(gpointer key, gpointer value, gpointer user_data);
90
static gboolean let_remove_eachitem(gpointer key, gpointer value,
92
static int get_providers(const char* class_path, const char* op_type,
94
static void merge_string_list(GList** old, GList* new);
95
static gint compare_str(gconstpointer a, gconstpointer b);
97
/* The end of internal function & data list */
99
/* Rource agent execution plugin operations */
100
static struct RAExecOps raops =
108
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
110
static const PILPluginImports* PluginImports;
111
static PILPlugin* OurPlugin;
112
static PILInterface* OurInterface;
113
static void* OurImports;
114
static void* interfprivate;
117
* Our plugin initialization and registration function
118
* It gets called when the plugin gets loaded.
121
PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports);
124
PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports)
126
/* Force the compiler to do a little type checking */
127
(void)(PILPluginInitFun)PIL_PLUGIN_INIT;
129
PluginImports = imports;
132
/* Register ourself as a plugin */
133
imports->register_plugin(us, &OurPIExports);
135
/* Register our interfaces */
136
return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S,
137
&raops, NULL, &OurInterface, &OurImports,
142
* The function to execute a RA.
145
execra(const char * rsc_id, const char * rsc_type, const char * provider,
146
const char * op_type, const int timeout, GHashTable * params)
148
uniform_ret_execra_t exit_value;
149
char ra_pathname[RA_MAX_NAME_LENGTH];
150
GHashTable * tmp_for_setenv;
151
GString * params_gstring;
152
char * inherit_debuglevel = NULL;
154
get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname);
156
/* Setup environment correctly */
157
tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal);
158
add_OCF_prefix(params, tmp_for_setenv);
159
add_OCF_env_vars(tmp_for_setenv, rsc_id, rsc_type, provider);
160
raexec_setenv(tmp_for_setenv);
161
g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL);
162
g_hash_table_destroy(tmp_for_setenv);
164
/* let this log show only high loglevel. */
165
inherit_debuglevel = getenv(HADEBUGVAL);
166
if ((inherit_debuglevel != NULL) && (atoi(inherit_debuglevel) > 1)) {
167
params_gstring = g_string_new("");
168
hash_to_str(params, params_gstring);
169
cl_log(LOG_DEBUG, "RA instance %s executing: OCF::%s %s. Parameters: "
170
"{%s}", rsc_id, rsc_type, op_type, params_gstring->str);
171
g_string_free(params_gstring, TRUE);
174
closefiles(); /* don't leak open files */
176
execl(ra_pathname, ra_pathname, op_type, (const char *)NULL);
177
cl_perror("(%s:%s:%d) execl failed for %s"
178
, __FILE__, __FUNCTION__, __LINE__, ra_pathname);
180
switch (errno) { /* see execve(2) */
181
case E2BIG: /* env to large */
182
case EACCES: /* permission denied (various errors) */
183
case EFAULT: /* address space issue */
184
case EINVAL: /* bad format */
185
case EMFILE: /* too many files open */
186
case EIO: /* I/O error */
187
case ELOOP: /* Too many symbolic links */
188
case ENAMETOOLONG: /* */
191
exit_value = EXECRA_EXEC_UNKNOWN_ERROR;
195
exit_value = EXECRA_NOT_INSTALLED;
202
static uniform_ret_execra_t
203
map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output)
205
/* Because the UNIFORM_RET_EXECRA is compatible with OCF standard,
206
* no actual mapping except validating, which ensure the return code
207
* will be in the range 0 to 7. Too strict?
209
if (ret_execra < 0 || ret_execra > 9) {
210
cl_log(LOG_WARNING, "mapped the invalid return code %d."
212
ret_execra = EXECRA_UNKNOWN_ERROR;
218
compare_str(gconstpointer a, gconstpointer b)
220
return strncmp(a,b,RA_MAX_NAME_LENGTH);
224
get_resource_list(GList ** rsc_info)
226
struct dirent **namelist;
229
char subdir[FILENAME_MAX+1];
231
if ( rsc_info == NULL ) {
232
cl_log(LOG_ERR, "Parameter error: get_resource_list");
236
if ( *rsc_info != NULL ) {
237
cl_log(LOG_ERR, "Parameter error: get_resource_list."\
238
"will cause memory leak.");
241
file_num = scandir(RA_PATH, &namelist, NULL, alphasort);
246
GList* ra_subdir = NULL;
248
if ('.' == namelist[file_num]->d_name[0]) {
249
free(namelist[file_num]);
253
stat(namelist[file_num]->d_name, &prop);
254
if (S_ISDIR(prop.st_mode)) {
255
free(namelist[file_num]);
259
snprintf(subdir,FILENAME_MAX,"%s/%s",
260
RA_PATH, namelist[file_num]->d_name);
262
get_runnable_list(subdir,&ra_subdir);
264
merge_string_list(rsc_info,ra_subdir);
266
while (NULL != (item = g_list_first(ra_subdir))) {
267
ra_subdir = g_list_remove_link(ra_subdir, item);
272
free(namelist[file_num]);
280
merge_string_list(GList** old, GList* new)
284
for( item=g_list_first(new); NULL!=item; item=g_list_next(item)){
285
if (!g_list_find_custom(*old, item->data,compare_str)){
286
newitem = g_strndup(item->data,RA_MAX_NAME_LENGTH);
287
*old = g_list_append(*old, newitem);
293
get_provider_list(const char* ra_type, GList ** providers)
296
ret = get_providers(RA_PATH, ra_type, providers);
298
cl_log(LOG_ERR, "scandir failed in OCF RA plugin");
304
get_resource_meta(const char* rsc_type, const char* provider)
306
const int BUFF_LEN=4096;
310
GString* g_str_tmp = NULL;
311
char ra_pathname[RA_MAX_NAME_LENGTH];
313
GHashTable * tmp_for_setenv;
314
struct timespec short_sleep = {0,200000000L}; /*20ms*/
316
get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname);
318
strncat(ra_pathname, " meta-data",RA_MAX_NAME_LENGTH-strlen(ra_pathname)-1);
319
tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal);
320
add_OCF_env_vars(tmp_for_setenv, "DUMMY_INSTANCE", rsc_type, provider);
321
raexec_setenv(tmp_for_setenv);
322
g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL);
323
g_hash_table_destroy(tmp_for_setenv);
325
file = popen(ra_pathname, "r");
327
cl_log(LOG_ERR, "%s: popen failed: %s", __FUNCTION__, strerror(errno));
331
g_str_tmp = g_string_new("");
333
read_len = fread(buff, 1, BUFF_LEN - 1, file);
335
*(buff+read_len) = '\0';
336
g_string_append(g_str_tmp, buff);
339
nanosleep(&short_sleep,NULL);
343
cl_log(LOG_ERR, "%s: pclose failed: %s", __FUNCTION__, strerror(errno));
345
if (0 == g_str_tmp->len) {
346
g_string_free(g_str_tmp, TRUE);
349
data = (char*)g_new(char, g_str_tmp->len+1);
350
data[0] = data[g_str_tmp->len] = 0;
351
strncpy(data, g_str_tmp->str, g_str_tmp->len);
353
g_string_free(g_str_tmp, TRUE);
359
add_OCF_prefix(GHashTable * env_params, GHashTable * new_env_params)
362
g_hash_table_foreach(env_params, add_prefix_foreach,
368
add_prefix_foreach(gpointer key, gpointer value, gpointer user_data)
370
const int MAX_LENGTH_OF_ENV = 50;
371
int prefix = STRLEN_CONST("OCF_RESKEY_");
372
GHashTable * new_hashtable = (GHashTable *) user_data;
374
int keylen = strnlen((char*)key, MAX_LENGTH_OF_ENV-prefix)+prefix+1;
376
newkey = g_new(gchar, keylen);
377
strncpy(newkey, "OCF_RESKEY_", keylen);
378
strncat(newkey, key, keylen-strlen(newkey)-1);
379
g_hash_table_insert(new_hashtable, (gpointer)newkey, g_strdup(value));
383
hash_to_str(GHashTable * params , GString * str)
386
g_hash_table_foreach(params, hash_to_str_foreach, str);
391
hash_to_str_foreach(gpointer key, gpointer value, gpointer user_data)
394
GString * str = (GString *)user_data;
396
snprintf(buffer_tmp, 60, "%s=%s ", (char *)key, (char *)value);
397
str = g_string_append(str, buffer_tmp);
401
let_remove_eachitem(gpointer key, gpointer value, gpointer user_data)
409
raexec_setenv(GHashTable * env_params)
412
g_hash_table_foreach(env_params, set_env, NULL);
418
set_env(gpointer key, gpointer value, gpointer user_data)
420
if (setenv(key, value, 1) != 0) {
421
cl_log(LOG_ERR, "setenv failed in raexecocf.");
426
get_providers(const char* class_path, const char* ra_type, GList ** providers)
428
struct dirent **namelist;
431
if ( providers == NULL ) {
432
cl_log(LOG_ERR, "Parameter error: get_providers");
436
if ( *providers != NULL ) {
437
cl_log(LOG_ERR, "Parameter error: get_providers."\
438
"will cause memory leak.");
442
file_num = scandir(class_path, &namelist, 0, alphasort);
446
char tmp_buffer[FILENAME_MAX+1];
450
if ('.' == namelist[file_num]->d_name[0]) {
451
free(namelist[file_num]);
454
snprintf(tmp_buffer,FILENAME_MAX,"%s/%s",
455
class_path, namelist[file_num]->d_name);
456
stat(tmp_buffer, &prop);
457
if (!S_ISDIR(prop.st_mode)) {
458
free(namelist[file_num]);
462
snprintf(tmp_buffer,FILENAME_MAX,"%s/%s/%s",
463
class_path, namelist[file_num]->d_name, ra_type);
465
if ( filtered(tmp_buffer) == TRUE ) {
466
*providers = g_list_append(*providers,
467
g_strdup(namelist[file_num]->d_name));
469
free(namelist[file_num]);
473
return g_list_length(*providers);
477
add_OCF_env_vars(GHashTable * env, const char * rsc_id,
478
const char * rsc_type, const char * provider)
481
cl_log(LOG_WARNING, "env should not be a NULL pointer.");
485
g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MAJOR"),
487
g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MINOR"),
489
g_hash_table_insert(env, g_strdup("OCF_ROOT"),
490
g_strdup(OCF_ROOT_DIR));
492
if ( rsc_id != NULL ) {
493
g_hash_table_insert(env, g_strdup("OCF_RESOURCE_INSTANCE"),
497
/* Currently the rsc_type=="the filename of the RA script/executable",
498
* It seems always correct even in the furture. ;-)
500
if ( rsc_type != NULL ) {
501
g_hash_table_insert(env, g_strdup("OCF_RESOURCE_TYPE"),
505
/* Notes: this is not added to specification yet. Sept 10,2004 */
506
if ( provider != NULL ) {
507
g_hash_table_insert(env, g_strdup("OCF_RESOURCE_PROVIDER"),