Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4639254
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
152 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/admin/cibadmin.c b/crm/admin/cibadmin.c
index 4d076062e3..483ed049e6 100644
--- a/crm/admin/cibadmin.c
+++ b/crm/admin/cibadmin.c
@@ -1,585 +1,585 @@
-/* $Id: cibadmin.c,v 1.13 2004/12/09 14:45:00 andrew Exp $ */
+/* $Id: cibadmin.c,v 1.14 2004/12/16 14:34:17 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/uids.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ctrl.h>
#include <crm/common/ipc.h>
#include <crm/cib.h>
#include <getopt.h>
#include <ha_msg.h> /* someone complaining about _ha_msg_mod not being found */
#include <crm/dmalloc_wrapper.h>
int exit_code = cib_ok;
int message_timer_id = -1;
int message_timeout_ms = 30*1000;
GMainLoop *mainloop = NULL;
const char *crm_system_name = "cibadmin";
IPC_Channel *crmd_channel = NULL;
const char *host = NULL;
void usage(const char *cmd, int exit_status);
enum cib_errors do_init(void);
int do_work(const char *xml_text, int command_options, xmlNodePtr *output);
gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data);
xmlNodePtr handleCibMod(const char *xml);
gboolean admin_message_timeout(gpointer data);
void cib_connection_destroy(gpointer user_data);
void cibadmin_op_callback(
const struct ha_msg *msg, int call_id, int rc, xmlNodePtr output);
int command_options = 0;
const char *cib_action = NULL;
typedef struct str_list_s
{
int num_items;
char *value;
struct str_list_s *next;
} str_list_t;
char *id = NULL;
char *this_msg_reference = NULL;
char *obj_type = NULL;
char *clear = NULL;
char *status = NULL;
char *migrate_from = NULL;
char *migrate_res = NULL;
char *subtype = NULL;
char *reset = NULL;
int request_id = 0;
int operation_status = 0;
const char *sys_to = NULL;
cib_t *the_cib = NULL;
#define OPTARGS "V?i:o:QDUCEX:t:Srwlsh:MB"
int
main(int argc, char **argv)
{
int option_index = 0;
int argerr = 0;
int flag;
int level = 0;
char *xml_text = NULL;
xmlNodePtr output = NULL;
static struct option long_options[] = {
/* Top-level Options */
{CRM_OP_CIB_ERASE, 0, 0, 'E'},
{CRM_OP_CIB_QUERY, 0, 0, 'Q'},
{CRM_OP_CIB_CREATE, 0, 0, 'C'},
{CRM_OP_CIB_REPLACE, 0, 0, 'R'},
{CRM_OP_CIB_UPDATE, 0, 0, 'U'},
{CRM_OP_CIB_DELETE, 0, 0, 'D'},
{CRM_OP_CIB_BUMP, 0, 0, 'B'},
{CRM_OP_CIB_SYNC, 0, 0, 'S'},
{CRM_OP_CIB_SLAVE, 0, 0, 'r'},
{CRM_OP_CIB_MASTER, 0, 0, 'w'},
{CRM_OP_CIB_ISMASTER,0, 0, 'M'},
{"local", 0, 0, 'l'},
{"sync-call", 0, 0, 's'},
{"host", 0, 0, 'h'},
{"xml", 1, 0, 'X'},
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"reference", 1, 0, 0},
{"timeout", 1, 0, 't'},
/* common options */
{XML_ATTR_ID, 1, 0, 'i'},
{"obj_type", 1, 0, 'o'},
{0, 0, 0, 0}
};
if(argc < 2) {
usage(crm_system_name, LSB_EXIT_EINVAL);
}
/* Redirect messages from glib functions to our handler */
g_log_set_handler(NULL,
G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
| G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
| G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
| G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL,
cl_glib_msg_handler, NULL);
/* and for good measure... */
g_log_set_always_fatal((GLogLevelFlags)0);
cl_log_set_entity(crm_system_name);
cl_log_set_facility(LOG_USER);
while (1) {
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
if (flag == -1)
break;
switch(flag) {
case 0:
printf("option %s",
long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
if (safe_str_eq("reference", long_options[option_index].name)) {
this_msg_reference = crm_strdup(optarg);
} else {
printf("Long option (--%s) is not (yet?) properly supported\n",
long_options[option_index].name);
++argerr;
}
break;
case 't':
message_timeout_ms = atoi(optarg);
if(message_timeout_ms < 1) {
message_timeout_ms = 30*1000;
}
break;
case 'E':
cib_action = crm_strdup(CRM_OP_CIB_ERASE);
break;
case 'Q':
cib_action = crm_strdup(CRM_OP_CIB_QUERY);
break;
case 'S':
cib_action = crm_strdup(CRM_OP_CIB_SYNC);
break;
case 'U':
cib_action = crm_strdup(CRM_OP_CIB_UPDATE);
break;
case 'R':
cib_action = crm_strdup(CRM_OP_CIB_REPLACE);
break;
case 'C':
cib_action = crm_strdup(CRM_OP_CIB_CREATE);
break;
case 'D':
cib_action = crm_strdup(CRM_OP_CIB_DELETE);
break;
case 'M':
cib_action = crm_strdup(CRM_OP_CIB_ISMASTER);
command_options |= cib_scope_local;
break;
case 'B':
cib_action = crm_strdup(CRM_OP_CIB_BUMP);
break;
case 'r':
cib_action = crm_strdup(CRM_OP_CIB_SLAVE);
break;
case 'w':
cib_action = crm_strdup(CRM_OP_CIB_MASTER);
command_options |= cib_scope_local;
break;
case 'V':
level = get_crm_log_level();
command_options = command_options | cib_verbose;
cl_log_enable_stderr(TRUE);
set_crm_log_level(level+1);
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'i':
crm_verbose("Option %c => %s", flag, optarg);
id = crm_strdup(optarg);
break;
case 'o':
crm_verbose("Option %c => %s", flag, optarg);
obj_type = crm_strdup(optarg);
break;
case 'X':
xml_text = crm_strdup(optarg);
break;
case 'h':
host = crm_strdup(optarg);
break;
case 'l':
command_options |= cib_scope_local;
break;
case 's':
command_options |= cib_sync_call;
break;
default:
printf("Argument code 0%o (%c)"
" is not (?yet?) supported\n",
flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
if (optind > argc) {
++argerr;
}
if(cib_action == NULL) {
usage(crm_system_name, cib_operation);
}
if (argerr) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
exit_code = do_init();
if(exit_code != cib_ok) {
crm_err("Init failed, could not perform requested operations");
fprintf(stderr, "Init failed, could not perform requested operations\n");
return -exit_code;
}
exit_code = do_work(xml_text, command_options, &output);
if (exit_code > 0) {
/* wait for the reply by creating a mainloop and running it until
* the callbacks are invoked...
*/
IPC_Channel *ch = the_cib->cmds->channel(the_cib);
request_id = exit_code;
if(ch == NULL) {
crm_err("Connection to CIB is corrupt");
return 2;
}
mainloop = g_main_new(FALSE);
crm_debug("Setting operation timeout to %dms",
message_timeout_ms);
message_timer_id = Gmain_timeout_add(
message_timeout_ms, admin_message_timeout, NULL);
crm_debug("%s waiting for reply from the local CIB",
crm_system_name);
crm_info("Starting mainloop");
g_main_run(mainloop);
} else if(exit_code < 0) {
crm_err("Call failed: %s", cib_error2string(exit_code));
- fprintf(stderr, "Call failed: %s", cib_error2string(exit_code));
+ fprintf(stderr, "Call failed: %s\n",
+ cib_error2string(exit_code));
operation_status = exit_code;
-
}
if(output != NULL) {
char *buffer = dump_xml_formatted(output);
fprintf(stdout, "%s", crm_str(buffer));
crm_free(buffer);
}
crm_debug("%s exiting normally", crm_system_name);
return -exit_code;
}
xmlNodePtr
handleCibMod(const char *xml)
{
const char *attr_name = NULL;
const char *attr_value = NULL;
xmlNodePtr fragment = NULL;
xmlNodePtr cib_object = NULL;
if(xml == NULL) {
cib_object = file2xml(stdin);
} else {
cib_object = string2xml(xml);
}
if(cib_object == NULL) {
return NULL;
}
attr_name = XML_ATTR_ID;
attr_value = xmlGetProp(cib_object, attr_name);
if(attr_name == NULL || strlen(attr_name) == 0) {
crm_err("No value for %s specified.", attr_name);
return NULL;
}
crm_trace("Object creation complete");
/* create the cib request */
fragment = create_cib_fragment(cib_object, NULL);
return fragment;
}
int
do_work(const char *xml_text, int call_options, xmlNodePtr *output)
{
/* construct the request */
xmlNodePtr msg_data = NULL;
char *obj_type_parent = NULL;
obj_type_parent = cib_pluralSection(obj_type);
if(strcmp(CRM_OP_CIB_QUERY, cib_action) == 0) {
crm_verbose("Querying the CIB for section: %s",
obj_type_parent);
return the_cib->cmds->query_from(
the_cib, host, obj_type_parent, output, call_options);
} else if (strcmp(CRM_OP_CIB_ERASE, cib_action) == 0) {
crm_trace("CIB Erase op in progress");
return the_cib->cmds->erase(the_cib, output, call_options);
} else if (strcmp(CRM_OP_CIB_CREATE, cib_action) == 0) {
enum cib_errors rc = cib_ok;
crm_trace("Performing %s op...", cib_action);
msg_data = handleCibMod(xml_text);
rc = the_cib->cmds->create(
the_cib, obj_type_parent, msg_data, output, call_options);
free_xml(msg_data);
return rc;
} else if (strcmp(CRM_OP_CIB_UPDATE, cib_action) == 0) {
enum cib_errors rc = cib_ok;
crm_trace("Performing %s op...", cib_action);
msg_data = handleCibMod(xml_text);
rc = the_cib->cmds->modify(
the_cib, obj_type_parent, msg_data, output, call_options);
free_xml(msg_data);
return rc;
} else if (strcmp(CRM_OP_CIB_DELETE, cib_action) == 0) {
enum cib_errors rc = cib_ok;
crm_trace("Performing %s op...", cib_action);
msg_data = handleCibMod(xml_text);
rc = the_cib->cmds->delete(
the_cib, obj_type_parent, msg_data, output, call_options);
free_xml(msg_data);
return rc;
} else if (strcmp(CRM_OP_CIB_SYNC, cib_action) == 0) {
crm_trace("Performing %s op...", cib_action);
return the_cib->cmds->sync_from(
the_cib, host, obj_type_parent, call_options);
} else if (strcmp(CRM_OP_CIB_SLAVE, cib_action) == 0
&& (call_options ^ cib_scope_local) ) {
crm_trace("Performing %s op on all nodes...", cib_action);
return the_cib->cmds->set_slave_all(the_cib, call_options);
} else if (strcmp(CRM_OP_CIB_MASTER, cib_action) == 0) {
crm_trace("Performing %s op on all nodes...", cib_action);
return the_cib->cmds->set_master(the_cib, call_options);
} else if(cib_action != NULL) {
crm_trace("Passing \"%s\" to variant_op...", cib_action);
return the_cib->cmds->variant_op(
the_cib, cib_action, host, obj_type_parent,
NULL, output, call_options);
} else {
crm_err("You must specify an operation");
}
return cib_operation;
}
enum cib_errors
do_init(void)
{
enum cib_errors rc = cib_ok;
/* docs say only do this once, but in their code they do it every time! */
xmlInitParser();
the_cib = cib_new();
rc = the_cib->cmds->signon(the_cib, cib_command);
if(rc != cib_ok) {
crm_err("Signon to CIB failed: %s",
cib_error2string(rc));
fprintf(stderr, "Signon to CIB failed: %s\n",
cib_error2string(rc));
} else {
rc = the_cib->cmds->set_op_callback(
the_cib, cibadmin_op_callback);
if(rc != cib_ok) {
crm_err("Failed to set callback: %s",
cib_error2string(rc));
fprintf(stderr,"Failed to set callback: %s\n",
cib_error2string(rc));
}
}
return rc;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status != 0 ? stderr : stdout;
fprintf(stream, "usage: %s [-?Vio] command\n"
"\twhere necessary, XML data will be expected using -X"
" or on STDIN if -X isnt specified\n", cmd);
fprintf(stream, "Options\n");
fprintf(stream, "\t--%s (-%c) <id>\tid of the object being operated on\n",
XML_ATTR_ID, 'i');
fprintf(stream, "\t--%s (-%c) <type>\tobject type being operated on\n",
"obj_type", 'o');
fprintf(stream, "\t--%s (-%c)\tturn on debug info."
" additional instance increase verbosity\n", "verbose", 'V');
fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?');
fprintf(stream, "\nCommands\n");
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ERASE, 'E');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_QUERY, 'Q');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_CREATE, 'C');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_REPLACE,'R');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_UPDATE, 'U');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_DELETE, 'D');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_BUMP, 'B');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_ISMASTER,'M');
fprintf(stream, "\t--%s (-%c)\t\n", CRM_OP_CIB_SYNC, 'S');
fprintf(stream, "\nXML data\n");
fprintf(stream, "\t--%s (-%c) <string>\t\n", "xml", 'X');
fprintf(stream, "\nAdvanced Options\n");
fprintf(stream, "\t--%s (-%c)\tsend command to specified host."
" Applies to %s and %s commands only\n", "host", 'h',
CRM_OP_CIB_QUERY, CRM_OP_CIB_SYNC);
fprintf(stream, "\t--%s (-%c)\tcommand only takes effect locally"
" on the specified host\n", "local", 'l');
fprintf(stream, "\t--%s (-%c)\twait for call to complete before"
" returning\n", "sync-call", 's');
fflush(stream);
exit(exit_status);
}
gboolean
admin_message_timeout(gpointer data)
{
if(safe_str_eq(cib_action, CRM_OP_CIB_SLAVE)) {
exit_code = cib_ok;
fprintf(stdout, "CIB service(s) are in slave mode.\n");
} else {
exit_code = cib_reply_failed;
fprintf(stderr,
"No messages received in %d seconds.. aborting\n",
(int)message_timeout_ms/1000);
crm_err("No messages received in %d seconds",
(int)message_timeout_ms/1000);
}
g_main_quit(mainloop);
return FALSE;
}
void
cib_connection_destroy(gpointer user_data)
{
crm_err("Connection to the CIB terminated... exiting");
g_main_quit(mainloop);
return;
}
void cibadmin_op_callback(
const struct ha_msg *msg, int call_id, int rc, xmlNodePtr output)
{
char *xml_text = NULL;
crm_info("our callback was invoked");
cl_log_message(msg);
exit_code = rc;
xml_text = dump_xml_formatted(output);
if(safe_str_eq(cib_action, CRM_OP_CIB_ISMASTER)
&& rc == cib_not_master) {
crm_info("Local CIB is _not_ the master instance\n");
fprintf(stderr, "Local CIB is _not_ the master instance\n");
} else if(safe_str_eq(cib_action, CRM_OP_CIB_ISMASTER)
&& rc == cib_ok) {
crm_info("Local CIB _is_ the master instance\n");
fprintf(stderr, "Local CIB _is_ the master instance\n");
} else if(rc != 0) {
- crm_warn("Call %s failed (%d): %s",
+ crm_warn("Call %s failed (%d): %s\n",
cib_action, rc, cib_error2string(rc));
fprintf(stderr, "Call %s failed (%d): %s\n",
cib_action, rc, cib_error2string(rc));
fprintf(stdout, "%s\n", xml_text);
} else if(output == NULL) {
crm_info("Call passed");
} else {
crm_info("Call passed");
fprintf(stdout, "%s\n", xml_text);
}
crm_free(xml_text);
if(call_id == request_id) {
g_main_quit(mainloop);
} else {
crm_info("Message was not the response we were looking for (%d vs. %d", call_id, request_id);
}
}
diff --git a/crm/cib/callbacks.c b/crm/cib/callbacks.c
index 2037f4f59c..ba41102288 100644
--- a/crm/cib/callbacks.c
+++ b/crm/cib/callbacks.c
@@ -1,788 +1,928 @@
-/* $Id: callbacks.c,v 1.5 2004/12/14 14:43:02 andrew Exp $ */
+/* $Id: callbacks.c,v 1.6 2004/12/16 14:34:18 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/uids.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ctrl.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <cibio.h>
#include <callbacks.h>
#include <cibmessages.h>
#include <crm/dmalloc_wrapper.h>
+gint cib_GCompareFunc(gconstpointer a, gconstpointer b);
+gboolean cib_msg_timeout(gpointer data);
+void cib_GHFunc(gpointer key, gpointer value, gpointer user_data);
+
int next_client_id = 0;
gboolean cib_is_master = FALSE;
GHashTable *client_list = NULL;
extern const char *cib_our_uname;
extern ll_cluster_t *hb_conn;
/* technically bump does modify the cib...
* but we want to split the "bump" from the "sync"
*/
cib_operation_t cib_server_ops[] = {
{NULL, FALSE, FALSE, FALSE, FALSE, cib_process_default},
{CRM_OP_NOOP, FALSE, FALSE, FALSE, FALSE, cib_process_default},
{CRM_OP_RETRIVE_CIB, FALSE, FALSE, FALSE, FALSE, cib_process_query},
{CRM_OP_CIB_SLAVE, FALSE, TRUE, FALSE, FALSE, cib_process_readwrite},
{CRM_OP_CIB_SLAVEALL,TRUE, TRUE, FALSE, FALSE, cib_process_readwrite},
{CRM_OP_CIB_MASTER, FALSE, TRUE, FALSE, FALSE, cib_process_readwrite},
{CRM_OP_CIB_ISMASTER,FALSE, TRUE, FALSE, FALSE, cib_process_readwrite},
{CRM_OP_CIB_BUMP, FALSE, TRUE, TRUE, FALSE, cib_process_bump},
{CRM_OP_CIB_REPLACE, TRUE, TRUE, TRUE, TRUE, cib_process_replace},
{CRM_OP_CIB_CREATE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CRM_OP_CIB_UPDATE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CRM_OP_JOINACK, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CRM_OP_SHUTDOWN_REQ,TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CRM_OP_CIB_DELETE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CRM_OP_CIB_QUERY, FALSE, FALSE, TRUE, FALSE, cib_process_query},
{CRM_OP_QUIT, FALSE, TRUE, FALSE, FALSE, cib_process_quit},
{CRM_OP_PING, FALSE, FALSE, FALSE, FALSE, cib_process_ping},
{CRM_OP_CIB_ERASE, TRUE, TRUE, TRUE, FALSE, cib_process_erase}
};
int send_via_callback_channel(struct ha_msg *msg, const char *token);
enum cib_errors cib_process_command(
const struct ha_msg *request, struct ha_msg **reply, gboolean privileged);
gboolean cib_common_callback(
IPC_Channel *channel, gpointer user_data, gboolean privileged);
enum cib_errors cib_get_operation_id(const struct ha_msg* msg, int *operation);
gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client);
gboolean
cib_client_connect(IPC_Channel *channel, gpointer user_data)
{
gboolean auth_failed = FALSE;
gboolean can_connect = TRUE;
gboolean (*client_callback)(IPC_Channel *channel, gpointer user_data) = NULL;
cib_client_t *new_client = NULL;
crm_debug("Connecting channel");
if (channel == NULL) {
crm_err("Channel was NULL");
can_connect = FALSE;
} else if (channel->ch_status == IPC_DISCONNECT) {
crm_err("Channel was disconnected");
can_connect = FALSE;
} else if(user_data == NULL) {
crm_err("user_data must contain channel name");
can_connect = FALSE;
} else {
- crm_malloc(new_client, sizeof(crmd_client_t));
+ crm_malloc(new_client, sizeof(cib_client_t));
new_client->id = NULL;
new_client->callback_id = NULL;
new_client->source = NULL;
new_client->channel = channel;
new_client->channel_name = user_data;
+ new_client->delegated_calls = NULL;
+ crm_debug("Created channel %p for channel %s",
+ new_client, new_client->channel_name);
+
client_callback = NULL;
/* choose callback and do auth based on channel_name */
if(safe_str_eq(new_client->channel_name, "cib_callback")) {
client_callback = cib_null_callback;
} else {
uuid_t client_id;
uuid_generate(client_id);
crm_malloc(new_client->id, sizeof(char)*36);
uuid_unparse(client_id, new_client->id);
new_client->id[35] = EOS;
uuid_generate(client_id);
crm_malloc(new_client->callback_id, sizeof(char)*30);
uuid_unparse(client_id, new_client->callback_id);
new_client->callback_id[35] = EOS;
client_callback = cib_ro_callback;
if(safe_str_eq(new_client->channel_name, "cib_rw")) {
client_callback = cib_rw_callback;
}
}
}
if(auth_failed) {
crm_err("Connection to %s channel failed authentication",
(char *)user_data);
can_connect = FALSE;
}
if(can_connect == FALSE) {
if(new_client) {
crm_free(new_client->id);
crm_free(new_client->callback_id);
}
crm_free(new_client);
return FALSE;
}
channel->ops->set_recv_qlen(channel, 100);
channel->ops->set_send_qlen(channel, 100);
if(client_callback != NULL) {
new_client->source = G_main_add_IPC_Channel(
G_PRIORITY_LOW, channel, FALSE, client_callback,
new_client, default_ipc_connection_destroy);
}
if(client_callback != cib_null_callback) {
/* send msg to client with uuid to use when signing up for
* callback channel
*/
struct ha_msg *reg_msg = ha_msg_new(3);
ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(reg_msg, F_CIB_CLIENTID, new_client->id);
ha_msg_add(
reg_msg, F_CIB_CALLBACK_TOKEN, new_client->callback_id);
msg2ipcchan(reg_msg, channel);
ha_msg_del(reg_msg);
/* make sure we can find ourselves later for sync calls
* redirected to the master instance
*/
g_hash_table_insert(client_list, new_client->id, new_client);
}
crm_info("Channel %s connected for client %s",
new_client->channel_name, new_client->id);
return TRUE;
}
gboolean
cib_rw_callback(IPC_Channel *channel, gpointer user_data)
{
return cib_common_callback(channel, user_data, TRUE);
}
gboolean
cib_ro_callback(IPC_Channel *channel, gpointer user_data)
{
return cib_common_callback(channel, user_data, FALSE);
}
gboolean
cib_null_callback(IPC_Channel *channel, gpointer user_data)
{
struct ha_msg *op_request = NULL;
cib_client_t *cib_client = user_data;
cib_client_t *hash_client = NULL;
const char *type = NULL;
const char *uuid_ticket = NULL;
if(cib_client == NULL) {
crm_err("Discarding IPC message from unknown source"
" on callback channel.");
return FALSE;
}
while(channel->ops->is_message_pending(channel)) {
if (channel->ch_status == IPC_DISCONNECT) {
/* The message which was pending for us is that
* the IPC status is now IPC_DISCONNECT
*/
break;
}
op_request = msgfromIPC_noauth(channel);
type = cl_get_string(op_request, F_CIB_OPERATION);
if(safe_str_neq(type, CRM_OP_REGISTER) ) {
crm_warn("Discarding IPC message from %s on callback channel",
cib_client->id);
ha_msg_del(op_request);
continue;
}
uuid_ticket = cl_get_string(op_request, F_CIB_CALLBACK_TOKEN);
hash_client = g_hash_table_lookup(client_list, uuid_ticket);
if(hash_client != NULL) {
crm_err("Duplicate registration request... disconnecting");
ha_msg_del(op_request);
return FALSE;
}
cib_client->id = crm_strdup(uuid_ticket);
g_hash_table_insert(client_list, cib_client->id, cib_client);
crm_info("Registered %s on %s channel",
cib_client->id, cib_client->channel_name);
ha_msg_del(op_request);
op_request = ha_msg_new(2);
ha_msg_add(op_request, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id);
msg2ipcchan(op_request, channel);
ha_msg_del(op_request);
}
return cib_process_disconnect(channel, cib_client);
}
gboolean
cib_common_callback(
IPC_Channel *channel, gpointer user_data, gboolean privileged)
{
int rc = cib_ok;
int lpc = 0;
int call_type = 0;
int call_options = 0;
const char *op = NULL;
const char *host = NULL;
struct ha_msg *op_request = NULL;
struct ha_msg *op_reply = NULL;
cib_client_t *cib_client = user_data;
if(cib_client == NULL) {
crm_err("Receieved call from unknown source. Discarding.");
return FALSE;
}
crm_verbose("Callback for %s on %s channel",
cib_client->id, cib_client->channel_name);
while(channel->ops->is_message_pending(channel)) {
if (channel->ch_status == IPC_DISCONNECT) {
/* The message which was pending for us is that
* the IPC status is now IPC_DISCONNECT */
break;
}
op_request = msgfromIPC(channel);
if (op_request == NULL) {
perror("Receive failure:");
break;
}
crm_verbose("Processing IPC message from %s on %s channel",
cib_client->id, cib_client->channel_name);
cl_log_message(op_request);
lpc++;
if(ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id) != HA_OK) {
crm_err("Couldnt add F_CIB_CLIENTID to message");
rc = cib_msg_field_add;
}
if(rc == cib_ok) {
ha_msg_value_int(
op_request, F_CIB_CALLOPTS, &call_options);
crm_trace("Call options: %.8lx", (long)call_options);
host = cl_get_string(op_request, F_CIB_HOST);
crm_trace("Destination host: %s", host);
op = cl_get_string(op_request, F_CIB_OPERATION);
crm_trace("Retrieved command: %s", op);
rc = cib_get_operation_id(op_request, &call_type);
crm_trace("Command offset: %d", call_type);
}
if(rc == cib_ok
&& cib_server_ops[call_type].needs_privileges
&& privileged == FALSE) {
rc = cib_not_authorized;
}
if(rc != cib_ok) {
/* TODO: construct error reply */
crm_err("Pre-processing of command failed: %s",
cib_error2string(rc));
} else if(host == NULL && cib_is_master
&& !(call_options & cib_scope_local)) {
crm_info("Processing master %s op locally", op);
rc = cib_process_command(
op_request, &op_reply, privileged);
} else if((host == NULL && (call_options & cib_scope_local))
|| safe_str_eq(host, cib_our_uname)) {
crm_info("Processing %s op locally", op);
rc = cib_process_command(
op_request, &op_reply, privileged);
} else if(host != NULL) {
crm_info("Forwarding %s op to %s", op, host);
ha_msg_add(op_request, F_CIB_DELEGATED, cib_our_uname);
hb_conn->llc_ops->send_ordered_nodemsg(
hb_conn, op_request, host);
- ha_msg_del(op_request);
+
+ if(call_options & cib_discard_reply) {
+ ha_msg_del(op_request);
+
+ } else if(call_options & cib_sync_call) {
+ /* keep track of the request so we can time it
+ * out if required
+ */
+ crm_debug("Registering call from %s as delegated", cib_client->id);
+ cib_client->delegated_calls = g_list_append(
+ cib_client->delegated_calls,
+ op_request);
+ } else {
+ ha_msg_del(op_request);
+ }
continue;
} else {
/* send via HA to other nodes */
crm_info("Forwarding %s op to master instance", op);
ha_msg_add(op_request, F_CIB_DELEGATED, cib_our_uname);
hb_conn->llc_ops->sendclustermsg(hb_conn, op_request);
- ha_msg_del(op_request);
+ if(call_options & cib_discard_reply) {
+ ha_msg_del(op_request);
+
+ } else if(call_options & cib_sync_call) {
+ /* keep track of the request so we can time it
+ * out if required
+ */
+ crm_debug("Registering call from %s as delegated", cib_client->id);
+ cib_client->delegated_calls = g_list_append(
+ cib_client->delegated_calls,
+ op_request);
+ } else {
+ ha_msg_del(op_request);
+ }
continue;
}
if(op_reply == NULL) {
crm_trace("No reply is required for op %s", op);
} else if(call_options & cib_sync_call) {
crm_info("Sending sync reply %p to %s op", op_reply,op);
if(msg2ipcchan(op_reply, channel) != HA_OK) {
rc = cib_reply_failed;
}
} else {
/* send reply via client's callback channel */
crm_info("Sending async reply %p to %s op", op_reply, op);
rc = send_via_callback_channel(
op_reply, cib_client->callback_id);
}
if(rc == cib_ok
&& cib_server_ops[call_type].modifies_cib
&& !(call_options & cib_scope_local)) {
/* send via HA to other nodes */
crm_info("Forwarding %s op to all instances", op);
ha_msg_add(op_request, F_CIB_GLOBAL_UPDATE, "true");
hb_conn->llc_ops->sendclustermsg(hb_conn, op_request);
} else {
if(call_options & cib_scope_local ) {
crm_debug("Request not broadcast : local scope");
}
if(cib_server_ops[call_type].modifies_cib == FALSE) {
crm_debug("Request not broadcast : R/O call");
}
if(rc != cib_ok) {
crm_debug("Request not broadcast : call failed : %s",
cib_error2string(rc));
}
}
ha_msg_del(op_request);
ha_msg_del(op_reply);
}
crm_verbose("Processed %d messages", lpc);
return cib_process_disconnect(channel, cib_client);
}
enum cib_errors
cib_process_command(const struct ha_msg *request, struct ha_msg **reply,
gboolean privileged)
{
xmlNodePtr input = NULL;
const char *input_s = NULL;
char *output_s = NULL;
xmlNodePtr output = NULL;
int call_type = 0;
int call_options = 0;
enum cib_errors rc = cib_ok;
const char *op = NULL;
const char *call_id = NULL;
const char *section = NULL;
/* Start processing the request... */
op = cl_get_string(request, F_CIB_OPERATION);
call_id = cl_get_string(request, F_CIB_CALLID);
ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
crm_trace("Processing call id: %s", call_id);
rc = cib_get_operation_id(request, &call_type);
if(rc == cib_ok &&
cib_server_ops[call_type].needs_privileges
&& privileged == FALSE) {
/* abort */
rc = cib_not_authorized;
}
if(rc == cib_ok && cib_server_ops[call_type].needs_section) {
crm_trace("Unpacking section");
section = cl_get_string(request, F_CIB_SECTION);
}
if(rc == cib_ok && cib_server_ops[call_type].needs_data) {
crm_trace("Unpacking data in %s", F_CIB_CALLDATA);
input_s = cl_get_string(request, F_CIB_CALLDATA);
if(input_s != NULL) {
crm_trace("Converting to xmlNodePtr");
input = string2xml(input_s);
if(input == NULL) {
crm_err("Invalid XML input");
rc = CIBRES_CORRUPT;
}
}
}
if(rc == cib_ok) {
rc = cib_server_ops[call_type].fn(
op, call_options, section, input, &output);
}
if(call_options & cib_discard_reply || reply == NULL) {
if(reply) *reply = NULL;
return rc;
}
/* make the basic reply */
*reply = ha_msg_new(8);
ha_msg_add(*reply, F_TYPE, "cib");
ha_msg_add(*reply, F_CIB_OPERATION, op);
ha_msg_add(*reply, F_CIB_CALLID, call_id);
ha_msg_add_int(*reply, F_CIB_RC, rc);
{
const char *tmp = cl_get_string(request, F_CIB_CLIENTID);
ha_msg_add(*reply, F_CIB_CLIENTID, tmp);
tmp = cl_get_string(request, F_CIB_CALLOPTS);
ha_msg_add(*reply, F_CIB_CALLOPTS, tmp);
tmp = cl_get_string(request, F_CIB_CALLID);
ha_msg_add(*reply, F_CIB_CALLID, tmp);
}
/* attach the output if necessary */
output_s = dump_xml_unformatted(output);
if(output != NULL && output_s == NULL) {
crm_err("Currupt output in reply to \"%s\" op",op);
rc = cib_output_data;
} else if(output_s != NULL
&& ha_msg_add(*reply, F_CIB_CALLDATA, output_s) != HA_OK) {
rc = cib_msg_field_add;
}
crm_free(output_s);
free_xml(output);
free_xml(input);
return rc;
}
int
send_via_callback_channel(struct ha_msg *msg, const char *token)
{
cib_client_t *hash_client = NULL;
+ GList *list_item = NULL;
crm_debug("Delivering msg %p to client %s", msg, token);
if(msg == NULL) {
crm_err("No message to send");
return cib_reply_failed;
} else if(token == NULL) {
crm_err("No client id token, cant send message");
return cib_missing;
}
-
+
hash_client = g_hash_table_lookup(client_list, token);
if(hash_client == NULL) {
crm_err("Cannot find client for token %s", token);
return cib_client_gone;
} else if(hash_client->channel == NULL) {
crm_err("Cannot find channel for client %s", token);
return cib_client_corrupt;
}
+ list_item = g_list_find_custom(
+ hash_client->delegated_calls, msg, cib_GCompareFunc);
+
+ if(list_item != NULL) {
+ /* remove it - no need to time it out */
+ struct ha_msg *orig_msg = list_item->data;
+ crm_debug("Removing msg from delegated list");
+ hash_client->delegated_calls = g_list_remove(
+ hash_client->delegated_calls, orig_msg);
+ ha_msg_del(orig_msg);
+ }
+
crm_debug("Delivering reply to client %s", token);
if(msg2ipcchan(msg, hash_client->channel) != HA_OK) {
crm_err("Delivery of reply to client %s failed", token);
return cib_reply_failed;
}
return cib_ok;
}
+gint cib_GCompareFunc(gconstpointer a, gconstpointer b)
+{
+ const struct ha_msg *a_msg = a;
+ const struct ha_msg *b_msg = b;
+
+ int msg_a_id = 0;
+ int msg_b_id = 0;
+
+ ha_msg_value_int(a_msg, F_CIB_CALLID, &msg_a_id);
+ ha_msg_value_int(b_msg, F_CIB_CALLID, &msg_b_id);
+
+ if(msg_a_id == msg_b_id) {
+ return 0;
+ } else if(msg_a_id < msg_b_id) {
+ return -1;
+ }
+ return 1;
+}
+
+
+gboolean
+cib_msg_timeout(gpointer data)
+{
+ crm_trace("Checking if any clients have timed out messages");
+ g_hash_table_foreach(client_list, cib_GHFunc, NULL);
+ return TRUE;
+}
+
+
+void
+cib_GHFunc(gpointer key, gpointer value, gpointer user_data)
+{
+ cib_client_t *client = value;
+
+ GListPtr list = client->delegated_calls;
+ struct ha_msg *msg = NULL;
+
+
+ while(list != NULL) {
+ struct ha_msg *reply = ha_msg_new(4);
+ int seen = 0;
+ int timeout = 5; /* 1 iteration == 1 seconds */
+
+ msg = list->data;
+ ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen);
+ ha_msg_value_int(msg, F_CIB_TIMEOUT, &timeout);
+
+ crm_trace("Timeout %d, seen %d", timeout, seen);
+ if(timeout > 0 && seen < timeout) {
+ int seen2 = 0;
+ crm_trace("Updating seen count for msg from client %s",
+ client->id);
+ seen++;
+ ha_msg_mod_int(msg, F_CIB_SEENCOUNT, seen);
+ ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen2);
+ list = list->next;
+ continue;
+ }
+
+ crm_warn("Sending operation timeout msg to client %s",
+ client->id);
+
+ ha_msg_add(reply, F_TYPE, "cib");
+ ha_msg_add(reply, F_CIB_OPERATION,
+ cl_get_string(msg, F_CIB_OPERATION));
+ ha_msg_add(reply, F_CIB_CALLID,
+ cl_get_string(msg, F_CIB_CALLID));
+ ha_msg_add_int(reply, F_CIB_RC, cib_master_timeout);
+
+ msg2ipcchan(reply, client->channel);
+
+ list = list->next;
+ client->delegated_calls = g_list_remove(
+ client->delegated_calls, msg);
+
+ ha_msg_del(reply);
+ ha_msg_del(msg);
+ }
+}
+
gboolean
cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client)
{
if (channel->ch_status == IPC_DISCONNECT && cib_client != NULL) {
- crm_info("Cleaning up after %s channel disconnect from client %s",
- cib_client->channel_name, cib_client->id);
+ crm_info("Cleaning up after %s channel disconnect from client (%p) %s",
+ cib_client->channel_name, cib_client, cib_client->id);
g_hash_table_remove(client_list, cib_client->id);
if(cib_client->source != NULL) {
- G_main_del_IPC_Channel(cib_client->source);
+ crm_debug("deleting the IPC Channel");
+ G_main_del_IPC_Channel(cib_client->source);
cib_client->source = NULL;
}
+ crm_debug("Freeing the cib client");
+ crm_debug("Freeing the cib client %s", cib_client->id);
/* crm_free(cib_client->callback_id); */
-/* crm_free(cib_client->id); */
- crm_free(cib_client);
+ crm_free(cib_client->id);
+ crm_free(cib_client);
+ crm_debug("Freed the cib client");
return FALSE;
} else if (channel->ch_status == IPC_DISCONNECT) {
crm_warn("Unknown client disconnected");
return FALSE;
}
return TRUE;
}
gboolean
cib_ha_dispatch(IPC_Channel *channel, gpointer user_data)
{
int lpc = 0;
ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data;
while(hb_cluster->llc_ops->msgready(hb_cluster)) {
lpc++;
/* invoke the callbacks but dont block */
hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
}
crm_trace("%d HA messages dispatched", lpc);
if (channel && (channel->ch_status == IPC_DISCONNECT)) {
crm_crit("Lost connection to heartbeat service... exiting");
exit(100);
return FALSE;
}
return TRUE;
}
void
cib_peer_callback(const struct ha_msg* msg, void* private_data)
{
int is_done = 1;
int call_type = 0;
int call_options = 0;
gboolean process = TRUE;
gboolean needs_reply = TRUE;
gboolean local_notify = FALSE;
enum cib_errors rc = cib_ok;
struct ha_msg *op_reply = NULL;
const char *originator = cl_get_string(msg, F_ORIG);
const char *request_to = cl_get_string(msg, F_CIB_HOST);
const char *reply_to = cl_get_string(msg, F_CIB_ISREPLY);
const char *update = cl_get_string(msg, F_CIB_GLOBAL_UPDATE);
const char *delegated = cl_get_string(msg, F_CIB_DELEGATED);
const char *client_id = NULL;
if(safe_str_eq(originator, cib_our_uname)) {
- crm_debug("Discarding message from ourselves");
+ crm_debug("Discarding message %s from ourselves",
+ cl_get_string(msg, F_SEQ));
return;
}
if(cib_get_operation_id(msg, &call_type) != cib_ok) {
- crm_err("Invalid operation... discarding msg");
+ crm_err("Invalid operation... discarding msg %s",
+ cl_get_string(msg, F_SEQ));
return;
}
+ crm_trace("%s Processing msg %s",
+ cib_our_uname, cl_get_string(msg, F_SEQ));
+
if(request_to != NULL && strlen(request_to) == 0) {
request_to = NULL;
}
if(cib_server_ops[call_type].modifies_cib
|| (reply_to == NULL && cib_is_master)
|| request_to != NULL) {
is_done = 0;
}
crm_info("Processing message from peer to %s...", request_to);
cl_log_message(msg);
if(safe_str_eq(update, "true")
&& safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Processing global update that originated from us");
needs_reply = FALSE;
local_notify = TRUE;
} else if(safe_str_eq(update, "true")) {
crm_debug("Processing global update");
needs_reply = FALSE;
} else if(request_to != NULL
&& safe_str_eq(request_to, cib_our_uname)) {
crm_debug("Processing request sent to us");
} else if(delegated != NULL && cib_is_master == TRUE) {
crm_debug("Processing request sent to master instance");
} else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Forward reply sent from %s to local clients",
originator);
process = FALSE;
needs_reply = FALSE;
local_notify = TRUE;
} else if(delegated != NULL) {
crm_debug("Ignoring msg for master instance");
return;
} else if(request_to != NULL) {
/* this is for a specific instance and we're not it */
crm_debug("Ignoring msg for instance on %s", request_to);
return;
} else if(reply_to == NULL && cib_is_master == FALSE) {
/* this is for the master instance and we're not it */
crm_debug("Ignoring reply to %s", reply_to);
return;
} else {
crm_warn("Nothing for us to do?");
return;
}
ha_msg_value_int(msg, F_CIB_CALLOPTS, &call_options);
crm_trace("Retrieved call options: %d", call_options);
if(process) {
crm_debug("Performing local processing");
rc = cib_process_command(msg, &op_reply, TRUE);
}
if(local_notify) {
/* send callback to originating child */
cib_client_t *client_obj = NULL;
crm_trace("find the client");
if(process == FALSE) {
op_reply = ha_msg_copy(msg);
}
-
client_id = cl_get_string(msg, F_CIB_CLIENTID);
if(client_id != NULL) {
client_obj = g_hash_table_lookup(
client_list, client_id);
} else {
crm_err("No client to sent the response to."
" F_CIB_CLIENTID not set.");
}
crm_debug("Sending callback to originator of delegated request");
if(client_obj != NULL) {
if(is_done == 0) {
crm_debug("Sending local modify response");
} else {
crm_debug("Sending master response");
}
if(call_options & cib_sync_call) {
- crm_debug("Sending sync response: %d", call_options);
- msg2ipcchan(op_reply, client_obj->channel);
+ crm_debug("Sending sync response: %d",
+ call_options);
+
+ send_via_callback_channel(
+ op_reply, client_obj->id);
+/* msg2ipcchan(op_reply, client_obj->channel); */
} else {
crm_debug("Sending async response");
send_via_callback_channel(
op_reply, client_obj->callback_id);
}
} else {
crm_warn("Client %s may have left us", client_id);
}
if(process == FALSE) {
ha_msg_del(op_reply);
}
}
if(needs_reply == FALSE) {
/* nothing more to do...
* this was a non-originating slave update
*/
crm_debug("Completed slave update");
return;
}
crm_trace("add the originator to message");
ha_msg_add(op_reply, F_CIB_ISREPLY, originator);
/* from now on we are the server */
if(rc == cib_ok && cib_server_ops[call_type].modifies_cib
&& !(call_options & cib_scope_local)) {
/* this (successful) call modified the CIB _and_ the
* change needs to be broadcast...
* send via HA to other nodes
*/
crm_debug("Sending update request to everyone");
hb_conn->llc_ops->sendclustermsg(hb_conn, op_reply);
} else {
/* send reply via HA to originating node */
crm_debug("Sending request result to originator only");
hb_conn->llc_ops->send_ordered_nodemsg(
hb_conn, op_reply, originator);
}
return;
}
enum cib_errors
cib_get_operation_id(const struct ha_msg* msg, int *operation)
{
int lpc = 0;
int max_msg_types = DIMOF(cib_server_ops);
const char *op = cl_get_string(msg, F_CIB_OPERATION);
for (lpc = 0; lpc < max_msg_types; lpc++) {
if (safe_str_eq(op, cib_server_ops[lpc].operation)) {
*operation = lpc;
return cib_ok;
}
}
crm_err("Operation %s is not valid", op);
*operation = -1;
return cib_operation;
}
diff --git a/crm/cib/callbacks.h b/crm/cib/callbacks.h
index d29d69bbec..345a9650d7 100644
--- a/crm/cib/callbacks.h
+++ b/crm/cib/callbacks.h
@@ -1,66 +1,67 @@
-/* $Id: callbacks.h,v 1.1 2004/12/05 16:14:07 andrew Exp $ */
+/* $Id: callbacks.h,v 1.2 2004/12/16 14:34:18 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <hb_api.h>
#include <clplumbing/ipc.h>
#include <clplumbing/GSource.h>
#include <crm/crm.h>
#include <crm/cib.h>
extern gboolean cib_is_master;
extern GHashTable *client_list;
typedef struct cib_client_s
{
char *id;
char *callback_id;
const char *channel_name;
IPC_Channel *channel;
GCHSource *source;
+ GList *delegated_calls;
} cib_client_t;
typedef struct cib_operation_s
{
const char* operation;
gboolean modifies_cib;
gboolean needs_privileges;
gboolean needs_section;
gboolean needs_data;
enum cib_errors (*fn)(
const char *, int, const char *, xmlNodePtr, xmlNodePtr*);
} cib_operation_t;
extern cib_operation_t cib_server_ops[];
extern gboolean cib_client_connect(IPC_Channel *channel, gpointer user_data);
extern gboolean cib_null_callback (IPC_Channel *channel, gpointer user_data);
extern gboolean cib_rw_callback (IPC_Channel *channel, gpointer user_data);
extern gboolean cib_ro_callback (IPC_Channel *channel, gpointer user_data);
extern gboolean cib_ha_dispatch (IPC_Channel *channel, gpointer user_data);
extern void cib_peer_callback(const struct ha_msg* msg, void* private_data);
diff --git a/crm/cib/main.c b/crm/cib/main.c
index d7d33abd3b..1b158cf897 100644
--- a/crm/cib/main.c
+++ b/crm/cib/main.c
@@ -1,318 +1,310 @@
-/* $Id: main.c,v 1.4 2004/12/15 16:19:42 andrew Exp $ */
+/* $Id: main.c,v 1.5 2004/12/16 14:34:18 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/uids.h>
#include <clplumbing/coredumps.h>
+#include <clplumbing/Gmain_timeout.h>
/* #include <ocf/oc_event.h> */
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ctrl.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <cibio.h>
#include <callbacks.h>
#include <crm/dmalloc_wrapper.h>
/* #define REALTIME_SUPPORT 0 */
#define PID_FILE WORKING_DIR"/"CRM_SYSTEM_CIB".pid"
#define DAEMON_LOG DEVEL_DIR"/"CRM_SYSTEM_CIB".log"
#define DAEMON_DEBUG DEVEL_DIR"/"CRM_SYSTEM_CIB".debug"
GMainLoop* mainloop = NULL;
const char* crm_system_name = CRM_SYSTEM_CIB;
const char *cib_our_uname = NULL;
void usage(const char* cmd, int exit_status);
int init_start(void);
gboolean cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name);
void cib_shutdown(int nsig);
void cib_ha_connection_destroy(gpointer user_data);
gboolean startCib(const char *filename);
+extern gboolean cib_msg_timeout(gpointer data);
ll_cluster_t *hb_conn = NULL;
#define OPTARGS "skrhV"
int
main(int argc, char ** argv)
{
int req_comms_restart = FALSE;
int req_restart = FALSE;
int req_status = FALSE;
int req_stop = FALSE;
int argerr = 0;
int flag;
#ifdef DEVEL_DIR
mkdir(DEVEL_DIR, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
/* Redirect messages from glib functions to our handler */
g_log_set_handler(NULL,
G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
| G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
| G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
| G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL,
cl_glib_msg_handler, NULL);
/* and for good measure... */
g_log_set_always_fatal((GLogLevelFlags)0);
cl_log_set_entity (crm_system_name);
cl_log_set_facility (LOG_LOCAL7);
cl_log_set_logfile (DAEMON_LOG);
cl_log_set_debugfile(DAEMON_DEBUG);
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
CL_SIGNAL(SIGTERM, cib_shutdown);
client_list = g_hash_table_new(&g_str_hash, &g_str_equal);
while ((flag = getopt(argc, argv, OPTARGS)) != EOF) {
switch(flag) {
case 'V':
alter_debug(DEBUG_INC);
break;
case 's': /* Status */
req_status = TRUE;
break;
case 'r': /* Restart */
req_restart = TRUE;
break;
case 'c': /* Restart */
req_comms_restart = TRUE;
break;
case 'h': /* Help message */
usage(crm_system_name, LSB_EXIT_OK);
break;
default:
++argerr;
break;
}
}
set_crm_log_level(LOG_TRACE);
cl_set_corerootdir(DEVEL_DIR);
cl_enable_coredumps(1);
cl_cdtocoredir();
if (optind > argc) {
++argerr;
}
if (argerr) {
usage(crm_system_name,LSB_EXIT_GENERIC);
}
/* read local config file */
if (req_status){
return init_status(PID_FILE, crm_system_name);
}
if (req_stop){
return init_stop(PID_FILE);
}
if (req_restart) {
init_stop(PID_FILE);
}
return init_start();
}
int
init_start(void)
{
gboolean was_error = FALSE;
-#ifdef REALTIME_SUPPORT
- static int crm_realtime = 1;
-#endif
hb_conn = ll_cluster_new("heartbeat");
cib_register_ha(hb_conn, CRM_SYSTEM_CIB);
if(startCib(CIB_FILENAME) == FALSE){
crm_crit("Cannot start CIB... terminating");
exit(1);
}
was_error = init_server_ipc_comms(
crm_strdup("cib_callback"), cib_client_connect,
default_ipc_connection_destroy);
was_error = was_error || init_server_ipc_comms(
crm_strdup("cib_ro"), cib_client_connect,
default_ipc_connection_destroy);
was_error = was_error || init_server_ipc_comms(
crm_strdup("cib_rw"), cib_client_connect,
default_ipc_connection_destroy);
if(was_error == FALSE) {
/* Create the mainloop and run it... */
mainloop = g_main_new(FALSE);
crm_info("Starting %s mainloop", crm_system_name);
-#ifdef REALTIME_SUPPORT
- if (crm_realtime == 1) {
- cl_enable_realtime();
-
- } else if (crm_realtime == 0) {
- cl_disable_realtime();
- }
- cl_make_realtime(SCHED_RR, 5, 64, 64);
-#endif
+ Gmain_timeout_add(1000, cib_msg_timeout, NULL);
+
g_main_run(mainloop);
return_to_orig_privs();
} else {
crm_err("Couldnt start all communication channels, exiting.");
}
return 0;
}
void
usage(const char* cmd, int exit_status)
{
FILE* stream;
stream = exit_status ? stderr : stdout;
fprintf(stream, "usage: %s [-srkh]"
"[-c configure file]\n", cmd);
/* fprintf(stream, "\t-d\tsets debug level\n"); */
/* fprintf(stream, "\t-s\tgets daemon status\n"); */
/* fprintf(stream, "\t-r\trestarts daemon\n"); */
/* fprintf(stream, "\t-k\tstops daemon\n"); */
/* fprintf(stream, "\t-h\thelp message\n"); */
fflush(stream);
exit(exit_status);
}
gboolean
cib_register_ha(ll_cluster_t *hb_cluster, const char *client_name)
{
int facility;
if(safe_val3(NULL, hb_cluster, llc_ops, errmsg) == NULL) {
crm_crit("cluster errmsg function unavailable");
}
crm_info("Signing in with Heartbeat");
if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) {
crm_err("Cannot sign on with heartbeat: %s",
hb_cluster->llc_ops->errmsg(hb_cluster));
return FALSE;
}
/* change the logging facility to the one used by heartbeat daemon */
crm_info("Switching to Heartbeat logger");
if (( facility =
hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) {
cl_log_set_facility(facility);
}
crm_verbose("Facility: %d", facility);
crm_debug("Be informed of CIB messages");
if (HA_OK != hb_cluster->llc_ops->set_msg_callback(
hb_cluster, T_CIB, cib_peer_callback, hb_cluster)){
crm_err("Cannot set msg callback: %s",
hb_cluster->llc_ops->errmsg(hb_cluster));
return FALSE;
}
crm_debug("Finding our node name");
if ((cib_our_uname =
hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) {
crm_err("get_mynodeid() failed");
return FALSE;
}
crm_info("FSA Hostname: %s", cib_our_uname);
crm_debug("Adding channel to mainloop");
G_main_add_IPC_Channel(
G_PRIORITY_HIGH, hb_cluster->llc_ops->ipcchan(hb_cluster),
FALSE, cib_ha_dispatch, hb_cluster /* userdata */,
cib_ha_connection_destroy);
return TRUE;
}
void
cib_ha_connection_destroy(gpointer user_data)
{
}
void
cib_shutdown(int nsig)
{
static int shuttingdown = 0;
CL_SIGNAL(nsig, cib_shutdown);
if (!shuttingdown) {
shuttingdown = 1;
}
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
exit(LSB_EXIT_OK);
}
}
gboolean
startCib(const char *filename)
{
xmlNodePtr cib = readCibXmlFile(filename);
if (initializeCib(cib)) {
crm_info("CIB Initialization completed successfully");
} else {
/* free_xml(cib); */
crm_warn("CIB Initialization failed, "
"starting with an empty default.");
activateCibXml(createEmptyCib(), filename);
}
return TRUE;
}
diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c
index e7f7bda373..341a3efe5e 100644
--- a/crm/crmd/callbacks.c
+++ b/crm/crmd/callbacks.c
@@ -1,518 +1,518 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#include <sys/param.h>
#include <crm/crm.h>
#include <string.h>
#include <crmd_fsa.h>
#include <libxml/tree.h>
#include <heartbeat.h>
#include <hb_api.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <crm/dmalloc_wrapper.h>
FILE *msg_in_strm = NULL;
FILE *msg_ipc_strm = NULL;
xmlNodePtr find_xml_in_hamessage(const struct ha_msg* msg);
void crmd_ha_connection_destroy(gpointer user_data);
void
crmd_ha_msg_callback(const struct ha_msg* msg, void* private_data)
{
const char *to = NULL;
char *xml_text = NULL;
xmlNodePtr root_xml_node = NULL;
const char *from = ha_msg_value(msg, F_ORIG);
const char *seq = ha_msg_value(msg, F_SEQ);
const char *type = ha_msg_value(msg, F_TYPE);
#ifdef MSG_LOG
if(msg_in_strm == NULL) {
msg_in_strm = fopen(DEVEL_DIR"/inbound.log", "w");
}
#endif
if(from == NULL) {
crm_err("Value of %s was NULL", F_ORIG);
} else if(safe_str_eq(from, fsa_our_uname)) {
if(safe_str_eq(type, T_CRM)) {
#ifdef MSG_LOG
fprintf(msg_in_strm,
"Discarded %s message [F_SEQ=%s] from ourselves.\n",
T_CRM, seq);
fflush(msg_in_strm);
#endif
return;
}
}
root_xml_node = find_xml_in_hamessage(msg);
to = xmlGetProp(root_xml_node, XML_ATTR_HOSTTO);
#ifdef MSG_LOG
xml_text = dump_xml_formatted(root_xml_node);
fprintf(msg_in_strm, "[%s (%s:%s)]\t%s\n", crm_str(from),
seq,
ha_msg_value(msg, F_TYPE),
xml_text
);
fflush(msg_in_strm);
crm_free(xml_text);
#endif
if(to != NULL && strlen(to) > 0 && strcmp(to, fsa_our_uname) != 0) {
#ifdef MSG_LOG
fprintf(msg_in_strm,
"Discarding message [F_SEQ=%s] for someone else", seq);
#endif
return;
}
set_xml_property_copy(root_xml_node, XML_ATTR_HOSTFROM, from);
set_xml_property_copy(root_xml_node, "F_SEQ", seq);
register_fsa_input(C_HA_MESSAGE, I_ROUTER, root_xml_node);
s_crmd_fsa(C_HA_MESSAGE);
free_xml(root_xml_node);
return;
}
/*
* Apparently returning TRUE means "stay connected, keep doing stuff".
* Returning FALSE means "we're all done, close the connection"
*/
gboolean
crmd_ipc_msg_callback(IPC_Channel *client, gpointer user_data)
{
int lpc = 0;
char *buffer = NULL;
IPC_Message *msg = NULL;
gboolean hack_return_good = TRUE;
xmlNodePtr root_xml_node;
crmd_client_t *curr_client = (crmd_client_t*)user_data;
crm_verbose("Processing IPC message from %s",
curr_client->table_key);
#ifdef MSG_LOG
if(msg_ipc_strm == NULL) {
msg_ipc_strm = fopen(DEVEL_DIR"/inbound.ipc.log", "w");
}
#endif
while(client->ops->is_message_pending(client)) {
if (client->ch_status == IPC_DISCONNECT) {
/* The message which was pending for us is that
* the IPC status is now IPC_DISCONNECT */
break;
}
if (client->ops->recv(client, &msg) != IPC_OK) {
perror("Receive failure:");
#ifdef MSG_LOG
fprintf(msg_ipc_strm, "[%s] [receive failure]\n",
curr_client->table_key);
fflush(msg_in_strm);
#endif
return !hack_return_good;
}
if (msg == NULL) {
#ifdef MSG_LOG
fprintf(msg_ipc_strm, "[%s] [__nothing__]\n",
curr_client->table_key);
fflush(msg_in_strm);
#endif
crm_err("No message this time");
continue;
}
lpc++;
buffer = (char*)msg->msg_body;
crm_verbose("Processing xml from %s [text=%s]\n",
curr_client->table_key, buffer);
#ifdef MSG_LOG
fprintf(msg_ipc_strm, "[%s] [text=%s]\n",
curr_client->table_key, buffer);
fflush(msg_in_strm);
#endif
root_xml_node = find_xml_in_ipcmessage(msg, FALSE);
if (root_xml_node != NULL) {
crmd_authorize_message(
root_xml_node, msg, curr_client);
} else {
crm_info("IPC Message was not valid... discarding.");
}
free_xml(root_xml_node);
msg->msg_done(msg);
msg = NULL;
buffer = NULL;
root_xml_node = NULL;
}
crm_verbose("Processed %d messages", lpc);
if (client->ch_status == IPC_DISCONNECT) {
crm_info("received HUP from %s",
curr_client->table_key);
if (curr_client != NULL) {
struct crm_subsystem_s *the_subsystem = NULL;
if (curr_client->sub_sys == NULL) {
crm_warn("Client hadn't registered with us yet");
} else if (strcmp(CRM_SYSTEM_PENGINE,
curr_client->sub_sys) == 0) {
the_subsystem = pe_subsystem;
} else if (strcmp(CRM_SYSTEM_TENGINE,
curr_client->sub_sys) == 0) {
the_subsystem = te_subsystem;
} else if (strcmp(CRM_SYSTEM_CIB,
curr_client->sub_sys) == 0){
the_subsystem = cib_subsystem;
}
if(the_subsystem != NULL) {
cleanup_subsystem(the_subsystem);
} /* else that was a transient client */
if (curr_client->table_key != NULL) {
/*
* Key is destroyed below:
* curr_client->table_key
* Value is cleaned up by:
* G_main_del_IPC_Channel
*/
g_hash_table_remove(
ipc_clients, curr_client->table_key);
}
if(curr_client->client_source != NULL) {
gboolean det = G_main_del_IPC_Channel(
curr_client->client_source);
crm_verbose("crm_client was %s detached",
det?"successfully":"not");
}
crm_free(curr_client->table_key);
crm_free(curr_client->sub_sys);
crm_free(curr_client->uuid);
crm_free(curr_client);
}
return !hack_return_good;
}
return hack_return_good;
}
void
-lrm_op_callback (lrm_op_t* op)
+lrm_op_callback(lrm_op_t* op)
{
/* todo: free op->rsc */
crm_debug("received callback");
register_fsa_input(C_LRM_OP_CALLBACK, I_LRM_EVENT, op);
s_crmd_fsa(C_LRM_OP_CALLBACK);
}
void
crmd_ha_status_callback(
const char *node, const char * status, void* private_data)
{
xmlNodePtr update = NULL;
xmlNodePtr fragment = NULL;
crm_debug("received callback");
crm_notice("Status update: Node %s now has status [%s]\n",node,status);
if(AM_I_DC == FALSE) {
crm_debug("Got nstatus callback in non-DC mode");
return;
} else if(safe_str_neq(status, DEADSTATUS)) {
crm_debug("nstatus callback was not for a dead node");
return;
}
/* this node is taost */
update = create_node_state(
node, node, status, NULL, NULL, NULL, NULL);
set_xml_property_copy(
update, XML_CIB_ATTR_CLEAR_SHUTDOWN, XML_BOOLEAN_TRUE);
fragment = create_cib_fragment(update, NULL);
crm_xml_debug(fragment, "Node status update");
update_local_cib(fragment, TRUE);
free_xml(fragment);
free_xml(update);
}
void
crmd_client_status_callback(const char * node, const char * client,
const char * status, void * private)
{
const char *join = NULL;
const char *extra = NULL;
xmlNodePtr update = NULL;
xmlNodePtr fragment = NULL;
crm_debug("received callback");
set_bit_inplace(fsa_input_register, R_PEER_DATA);
if(safe_str_eq(status, JOINSTATUS)){
status = ONLINESTATUS;
extra = XML_CIB_ATTR_CLEAR_SHUTDOWN;
} else if(safe_str_eq(status, LEAVESTATUS)){
status = OFFLINESTATUS;
join = CRMD_JOINSTATE_DOWN;
extra = XML_CIB_ATTR_CLEAR_SHUTDOWN;
}
crm_notice("Status update: Client %s/%s now has status [%s]\n",
node, client, status);
if(AM_I_DC == FALSE) {
crm_debug("Got client status callback in non-DC mode");
return;
}
update = create_node_state(
node, node, NULL, NULL, status, join, NULL);
set_xml_property_copy(update, extra, XML_BOOLEAN_TRUE);
fragment = create_cib_fragment(update, NULL);
crm_xml_debug(fragment, "Client status update");
update_local_cib(fragment, TRUE);
free_xml(fragment);
free_xml(update);
}
xmlNodePtr
find_xml_in_hamessage(const struct ha_msg* msg)
{
const char *xml;
xmlDocPtr doc;
xmlNodePtr root;
if (msg == NULL) {
crm_info("**** ha_crm_msg_callback called on a NULL message");
return NULL;
}
#if 0
crm_debug("[F_TYPE=%s]", ha_msg_value(msg, F_TYPE));
crm_debug("[F_ORIG=%s]", ha_msg_value(msg, F_ORIG));
crm_debug("[F_TO=%s]", ha_msg_value(msg, F_TO));
crm_debug("[F_COMMENT=%s]", ha_msg_value(msg, F_COMMENT));
crm_debug("[F_XML=%s]", ha_msg_value(msg, "xml"));
/* crm_debug("[F_=%s]", ha_msg_value(ha_msg, F_)); */
#endif
if (strcmp(T_CRM, ha_msg_value(msg, F_TYPE)) != 0) {
crm_info("Received a (%s) message by mistake.",
ha_msg_value(msg, F_TYPE));
return NULL;
}
xml = ha_msg_value(msg, "xml");
if (xml == NULL) {
crm_info("No XML attached to this message.");
return NULL;
}
doc = xmlParseMemory(xml, strlen(xml));
if (doc == NULL) {
crm_info("XML Buffer was not valid.");
return NULL;
}
root = xmlDocGetRootElement(doc);
if (root == NULL) {
crm_info("Root node was NULL.");
return NULL;
}
return root;
}
gboolean lrm_dispatch(int fd, gpointer user_data)
{
int rc = 0;
ll_lrm_t *lrm = (ll_lrm_t*)user_data;
crm_debug("received callback");
rc = lrm->lrm_ops->rcvmsg(lrm, FALSE);
return TRUE;
}
/* #define MAX_EMPTY_CALLBACKS 20 */
/* int empty_callbacks = 0; */
gboolean
crmd_ha_msg_dispatch(IPC_Channel *channel, gpointer user_data)
{
int lpc = 0;
ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data;
while(hb_cluster->llc_ops->msgready(hb_cluster)) {
lpc++;
/* invoke the callbacks but dont block */
hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
}
crm_trace("%d HA messages dispatched", lpc);
if (channel && (channel->ch_status == IPC_DISCONNECT)) {
crm_crit("Lost connection to heartbeat service.");
return FALSE;
}
return TRUE;
}
void
crmd_ha_connection_destroy(gpointer user_data)
{
crm_crit("Heartbeat has left us");
/* this is always an error */
/* feed this back into the FSA */
register_fsa_input(C_HA_DISCONNECT, I_ERROR, NULL);
s_crmd_fsa(C_HA_DISCONNECT);
}
gboolean
crmd_client_connect(IPC_Channel *client_channel, gpointer user_data)
{
if (client_channel == NULL) {
crm_err("Channel was NULL");
} else if (client_channel->ch_status == IPC_DISCONNECT) {
crm_err("Channel was disconnected");
} else {
crmd_client_t *blank_client = NULL;
crm_debug("Channel connected");
crm_malloc(blank_client, sizeof(crmd_client_t));
if (blank_client == NULL) {
return FALSE;
}
client_channel->ops->set_recv_qlen(client_channel, 100);
client_channel->ops->set_send_qlen(client_channel, 100);
blank_client->client_channel = client_channel;
blank_client->sub_sys = NULL;
blank_client->uuid = NULL;
blank_client->table_key = NULL;
blank_client->client_source =
G_main_add_IPC_Channel(
G_PRIORITY_LOW, client_channel,
FALSE, crmd_ipc_msg_callback,
blank_client, default_ipc_connection_destroy);
}
return TRUE;
}
gboolean ccm_dispatch(int fd, gpointer user_data)
{
int rc = 0;
oc_ev_t *ccm_token = (oc_ev_t*)user_data;
crm_debug("received callback");
rc = oc_ev_handle_event(ccm_token);
if(0 == rc) {
return TRUE;
} else {
crm_err("CCM connection appears to have failed: rc=%d.", rc);
register_fsa_input(C_CCM_CALLBACK, I_ERROR, NULL);
s_crmd_fsa(C_CCM_CALLBACK);
return FALSE;
}
}
void
crmd_ccm_msg_callback(
oc_ed_t event, void *cookie, size_t size, const void *data)
{
struct crmd_ccm_data_s *event_data = NULL;
crm_debug("received callback");
if(data != NULL) {
crm_malloc(event_data, sizeof(struct crmd_ccm_data_s));
if(event_data != NULL) {
event_data->event = &event;
event_data->oc = copy_ccm_oc_data(
(const oc_ev_membership_t *)data);
crm_debug("Sending callback to the FSA");
register_fsa_input(
C_CCM_CALLBACK, I_CCM_EVENT,
(void*)event_data);
s_crmd_fsa(C_CCM_CALLBACK);
event_data->event = NULL;
event_data->oc = NULL;
crm_free(event_data);
}
} else {
crm_info("CCM Callback with NULL data... "
"I dont /think/ this is bad");
}
oc_ev_callback_done(cookie);
return;
}
diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c
index 5d74adc491..06aa1ce32e 100644
--- a/crm/crmd/lrm.c
+++ b/crm/crmd/lrm.c
@@ -1,828 +1,836 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#include <sys/param.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> /* for access */
#include <clplumbing/cl_signal.h>
#include <errno.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <lrm/raexec.h>
#include <crm/dmalloc_wrapper.h>
gboolean stop_all_resources(void);
gboolean build_suppported_RAs(
xmlNodePtr metadata_list, xmlNodePtr xml_agent_list);
gboolean build_active_RAs(xmlNodePtr rsc_list);
void do_update_resource(lrm_rsc_t *rsc, lrm_op_t *op);
enum crmd_fsa_input do_lrm_rsc_op(
lrm_rsc_t *rsc, char *rid, const char *operation, xmlNodePtr msg);
enum crmd_fsa_input do_fake_lrm_op(gpointer data);
GHashTable *xml2list(xmlNodePtr parent, const char **attr_path, int depth);
GHashTable *monitors = NULL;
int num_lrm_register_fails = 0;
int max_lrm_register_fails = 30;
const char *rsc_path[] =
{
"msg_data",
"rsc_op",
"resource",
"instance_attributes",
"rsc_parameters"
};
enum crmd_rscstate {
crmd_rscstate_NULL,
crmd_rscstate_START,
crmd_rscstate_START_PENDING,
crmd_rscstate_START_OK,
crmd_rscstate_START_FAIL,
crmd_rscstate_STOP,
crmd_rscstate_STOP_PENDING,
crmd_rscstate_STOP_OK,
crmd_rscstate_STOP_FAIL,
crmd_rscstate_MON,
crmd_rscstate_MON_PENDING,
crmd_rscstate_MON_OK,
crmd_rscstate_MON_FAIL,
crmd_rscstate_GENERIC_PENDING,
crmd_rscstate_GENERIC_OK,
crmd_rscstate_GENERIC_FAIL
};
void free_lrm_op(lrm_op_t *op);
const char *crmd_rscstate2string(enum crmd_rscstate state);
const char *
crmd_rscstate2string(enum crmd_rscstate state)
{
switch(state) {
case crmd_rscstate_NULL:
return NULL;
case crmd_rscstate_START:
return CRMD_RSCSTATE_START;
case crmd_rscstate_START_PENDING:
return CRMD_RSCSTATE_START_PENDING;
case crmd_rscstate_START_OK:
return CRMD_RSCSTATE_START_OK;
case crmd_rscstate_START_FAIL:
return CRMD_RSCSTATE_START_FAIL;
case crmd_rscstate_STOP:
return CRMD_RSCSTATE_STOP;
case crmd_rscstate_STOP_PENDING:
return CRMD_RSCSTATE_STOP_PENDING;
case crmd_rscstate_STOP_OK:
return CRMD_RSCSTATE_STOP_OK;
case crmd_rscstate_STOP_FAIL:
return CRMD_RSCSTATE_STOP_FAIL;
case crmd_rscstate_MON:
return CRMD_RSCSTATE_MON;
case crmd_rscstate_MON_PENDING:
return CRMD_RSCSTATE_MON_PENDING;
case crmd_rscstate_MON_OK:
return CRMD_RSCSTATE_MON_OK;
case crmd_rscstate_MON_FAIL:
return CRMD_RSCSTATE_MON_FAIL;
case crmd_rscstate_GENERIC_PENDING:
return CRMD_RSCSTATE_GENERIC_PENDING;
case crmd_rscstate_GENERIC_OK:
return CRMD_RSCSTATE_GENERIC_OK;
case crmd_rscstate_GENERIC_FAIL:
return CRMD_RSCSTATE_GENERIC_FAIL;
}
return "<unknown>";
}
/* A_LRM_CONNECT */
enum crmd_fsa_input
do_lrm_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
enum crmd_fsa_input failed = I_FAIL;
int ret = HA_OK;
if(action & A_LRM_DISCONNECT) {
fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn);
/* TODO: Clean up the hashtable */
}
if(action & A_LRM_CONNECT) {
crm_trace("LRM: connect...");
monitors = g_hash_table_new(g_str_hash, g_str_equal);
fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM);
if(NULL == fsa_lrm_conn) {
return failed;
}
crm_trace("LRM: sigon...");
ret = fsa_lrm_conn->lrm_ops->signon(
fsa_lrm_conn, CRM_SYSTEM_CRMD);
if(ret != HA_OK) {
if(++num_lrm_register_fails < max_lrm_register_fails) {
crm_warn("Failed to sign on to the LRM %d"
" (%d max) times",
num_lrm_register_fails,
max_lrm_register_fails);
startTimer(wait_timer);
crmd_fsa_stall();
return I_NULL;
} else {
crm_err("Failed to sign on to the LRM %d"
" (max) times", num_lrm_register_fails);
return failed;
}
}
crm_trace("LRM: set_lrm_callback...");
ret = fsa_lrm_conn->lrm_ops->set_lrm_callback(
fsa_lrm_conn, lrm_op_callback);
if(ret != HA_OK) {
crm_err("Failed to set LRM callbacks");
return failed;
}
/* TODO: create a destroy handler that causes
* some recovery to happen
*/
G_main_add_fd(G_PRIORITY_LOW,
fsa_lrm_conn->lrm_ops->inputfd(fsa_lrm_conn),
FALSE,
lrm_dispatch, fsa_lrm_conn,
default_ipc_connection_destroy);
set_bit_inplace(fsa_input_register, R_LRM_CONNECTED);
}
if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) {
crm_err("Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
return I_NULL;
}
gboolean
build_suppported_RAs(xmlNodePtr metadata_list, xmlNodePtr xml_agent_list)
{
GList *types = NULL;
GList *classes = NULL;
const char *version = NULL;
const char *ra_data = NULL;
/* GHashTable *metadata = NULL; */
xmlNodePtr xml_agent = NULL;
xmlNodePtr xml_metadata = NULL;
xmlNodePtr tmp = NULL;
classes = fsa_lrm_conn->lrm_ops->get_rsc_class_supported(fsa_lrm_conn);
slist_iter(
class, char, classes, lpc,
types = fsa_lrm_conn->lrm_ops->get_rsc_type_supported(
fsa_lrm_conn, class);
slist_iter(
type, char, types, llpc,
version = "1";
xml_agent = create_xml_node(
xml_agent_list, "lrm_agent");
set_xml_property_copy(xml_agent, "class", class);
set_xml_property_copy(xml_agent, XML_ATTR_TYPE, type);
/* ra_data = g_hashtable_lookup(metadata, type); */
if(ra_data != NULL) {
xml_metadata = create_xml_node(
xml_metadata, "agent_metadata");
set_xml_property_copy(
xml_metadata, "class", class);
set_xml_property_copy(
xml_metadata, XML_ATTR_TYPE, type);
tmp = string2xml(ra_data);
if(tmp != NULL) {
xmlAddChild(xml_metadata, tmp);
}
/* extract version */
}
set_xml_property_copy(xml_agent, "version", version);
)
g_list_free(types);
);
g_list_free(classes);
return TRUE;
}
gboolean
stop_all_resources(void)
{
GList *op_list = NULL;
GList *lrm_list = NULL;
state_flag_t cur_state = 0;
const char *this_op = NULL;
lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn);
slist_iter(
rid, char, lrm_list, lpc,
/* GHashTable* params; */
lrm_rsc_t *the_rsc =
fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
crm_info("Processing lrm_rsc_t entry %s", rid);
if(the_rsc == NULL) {
crm_err("NULL resource returned from the LRM");
continue;
}
op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state);
crm_verbose("\tcurrent state:%s\n",
cur_state==LRM_RSC_IDLE?"Idle":"Busy");
slist_iter(
op, lrm_op_t, op_list, llpc,
this_op = op->op_type;
crm_debug("Processing op %s for %s (status=%d, rc=%d)",
op->op_type, the_rsc->id,
op->op_status, op->rc);
if(safe_str_neq(this_op, CRMD_RSCSTATE_STOP)){
do_lrm_rsc_op(the_rsc, the_rsc->id,
CRMD_RSCSTATE_STOP, NULL);
}
break;
);
);
return TRUE;
}
gboolean
build_active_RAs(xmlNodePtr rsc_list)
{
GList *op_list = NULL;
GList *lrm_list = NULL;
gboolean found_op = FALSE;
state_flag_t cur_state = 0;
const char *this_op = NULL;
char *tmp = NULL;
lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn);
slist_iter(
rid, char, lrm_list, lpc,
/* GHashTable* params; */
lrm_rsc_t *the_rsc =
fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
xmlNodePtr xml_rsc = create_xml_node(
rsc_list, XML_LRM_TAG_RESOURCE);
crm_info("Processing lrm_rsc_t entry %s", rid);
if(the_rsc == NULL) {
crm_err("NULL resource returned from the LRM");
continue;
}
set_xml_property_copy(xml_rsc, XML_ATTR_ID, the_rsc->id);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_TARGET, fsa_our_uname);
op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state);
crm_verbose("\tcurrent state:%s\n",
cur_state==LRM_RSC_IDLE?"Idle":"Busy");
slist_iter(
op, lrm_op_t, op_list, llpc,
this_op = op->op_type;
crm_debug("Processing op %s for %s (status=%d, rc=%d)",
op->op_type, the_rsc->id, op->op_status, op->rc);
if(op->rc != 0
|| safe_str_neq(this_op, CRMD_RSCSTATE_MON)){
set_xml_property_copy(
xml_rsc,
XML_LRM_ATTR_RSCSTATE,
op->user_data);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_LASTOP, this_op);
tmp = crm_itoa(op->rc);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_RC, tmp);
crm_free(tmp);
tmp = crm_itoa(op->op_status);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_OPSTATUS, tmp);
crm_free(tmp);
/* we only want the last one */
found_op = TRUE;
break;
} else {
set_xml_property_copy(
xml_rsc,
XML_LRM_ATTR_RSCSTATE,
CRMD_RSCSTATE_START_OK);
set_xml_property_copy(
xml_rsc,
XML_LRM_ATTR_LASTOP,
CRMD_RSCSTATE_START);
tmp = crm_itoa(op->rc);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_RC, tmp);
crm_free(tmp);
set_xml_property_copy(
xml_rsc, XML_LRM_ATTR_OPSTATUS, "0");
/* we only want the last one */
found_op = TRUE;
break;
}
);
if(found_op == FALSE) {
crm_err("Could not properly determin last op"
" for %s from %d entries", the_rsc->id,
g_list_length(op_list));
}
g_list_free(op_list);
);
g_list_free(lrm_list);
return TRUE;
}
xmlNodePtr
do_lrm_query(gboolean is_replace)
{
xmlNodePtr xml_result= NULL;
xmlNodePtr xml_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
xmlNodePtr xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM);
xmlNodePtr rsc_list = create_xml_node(xml_data,XML_LRM_TAG_RESOURCES);
xmlNodePtr xml_agent_list = create_xml_node(xml_data, "lrm_agents");
xmlNodePtr xml_metadata_list = create_xml_node(xml_data, "metatdata");
/* Build a list of supported agents and metadata */
build_suppported_RAs(xml_metadata_list, xml_agent_list);
/* Build a list of active (not always running) resources */
build_active_RAs(rsc_list);
if(is_replace) {
set_xml_property_copy(xml_state, "replace", XML_CIB_TAG_LRM);
}
set_uuid(xml_state, XML_ATTR_UUID, fsa_our_uname);
set_xml_property_copy(xml_state, XML_ATTR_UNAME, fsa_our_uname);
xml_result = create_cib_fragment(xml_state, NULL);
crm_xml_debug(xml_state, "Current state of the LRM");
return xml_result;
}
/* A_LRM_INVOKE */
enum crmd_fsa_input
do_lrm_invoke(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input,
fsa_data_t *msg_data)
{
enum crmd_fsa_input next_input = I_NULL;
xmlNodePtr msg;
const char *operation = NULL;
char rid[64];
const char *id_from_cib = NULL;
const char *crm_op = NULL;
lrm_rsc_t *rsc = NULL;
msg = (xmlNodePtr)msg_data->data;
operation = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -3, XML_LRM_ATTR_TASK, TRUE);
/* xmlNodePtr tmp = find_xml_node_nested(msg, rsc_path, DIMOF(rsc_path) -3); */
/* operation = xmlGetProp(tmp, XML_LRM_ATTR_TASK); */
if(operation == NULL) {
crm_err("No value for %s in message at level %d.",
XML_LRM_ATTR_TASK, DIMOF(rsc_path) -3);
return I_NULL;
}
id_from_cib = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_ID, TRUE);
if(id_from_cib == NULL) {
crm_err("No value for %s in message at level %d.",
XML_ATTR_ID, DIMOF(rsc_path) -2);
return I_NULL;
}
/* only the first 16 chars are used by the LRM */
strncpy(rid, id_from_cib, 64);
rid[63] = 0;
crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE);
rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
if(crm_op != NULL && safe_str_eq(crm_op, "lrm_query")) {
xmlNodePtr data, reply;
data = do_lrm_query(FALSE);
reply = create_reply(msg, data);
relay_message(reply, TRUE);
free_xml(data);
free_xml(reply);
} else if(operation != NULL) {
next_input = do_lrm_rsc_op(rsc, rid, operation, msg);
} else {
next_input = I_ERROR;
}
return next_input;
}
enum crmd_fsa_input
do_lrm_rsc_op(
lrm_rsc_t *rsc, char *rid, const char *operation, xmlNodePtr msg)
{
lrm_op_t* op = NULL;
int call_id = 0;
int action_timeout = 0;
const char *class = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -2, "class", TRUE);
const char *type = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_TYPE, TRUE);
const char *timeout = get_xml_attr_nested(
msg, rsc_path, DIMOF(rsc_path) -2, "timeout", FALSE);
if(rsc == NULL) {
/* add it to the list */
crm_verbose("adding rsc %s before operation", rid);
fsa_lrm_conn->lrm_ops->add_rsc(
fsa_lrm_conn, rid, class, type, NULL, NULL);
rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid);
}
if(rsc == NULL) {
crm_err("Could not add resource to LRM");
return I_FAIL;
}
if(timeout) {
action_timeout = atoi(timeout);
if(action_timeout < 0) {
action_timeout = 0;
}
}
/* stop the monitor before stopping the resource */
if(safe_str_eq(operation, CRMD_RSCSTATE_STOP)) {
gpointer foo = g_hash_table_lookup(monitors, rsc->id);
call_id = GPOINTER_TO_INT(foo);
if(call_id > 0) {
crm_debug("Stopping status op for %s", rsc->id);
rsc->ops->cancel_op(rsc, call_id);
g_hash_table_remove(monitors, rsc->id);
/* TODO: Clean up key */
} else {
crm_warn("No monitor operation found for %s", rsc->id);
/* TODO: we probably need to look up the LRM to find it */
}
}
/* now do the op */
crm_info("Performing op %s on %s", operation, rid);
crm_malloc(op, sizeof(lrm_op_t));
op->op_type = crm_strdup(operation);
op->params = xml2list(msg, rsc_path, DIMOF(rsc_path));
op->timeout = action_timeout;
op->interval = 0;
op->user_data = NULL;
op->target_rc = EVERYTIME;
if(safe_str_eq(CRMD_RSCSTATE_START, operation)) {
op->user_data = crm_strdup(CRMD_RSCSTATE_START_OK);
} else if(safe_str_eq(CRMD_RSCSTATE_STOP, operation)) {
op->user_data = crm_strdup(CRMD_RSCSTATE_STOP_OK);
} else {
crm_warn("Using status \"complete\" for op \"%s\""
"... this is still in the experimental stage.",
operation);
op->user_data = crm_strdup(CRMD_RSCSTATE_GENERIC_OK);
}
op->user_data_len = 1+strlen(op->user_data);
call_id = rsc->ops->perform_op(rsc, op);
free_lrm_op(op);
if(call_id <= 0) {
crm_err("Operation %s on %s failed", operation, rid);
return I_FAIL;
}
if(safe_str_eq(operation, CRMD_RSCSTATE_START)) {
/* initiate the monitor action */
crm_malloc(op, sizeof(lrm_op_t));
op->op_type = crm_strdup(CRMD_RSCSTATE_MON);
op->params = NULL;
op->user_data = crm_strdup(CRMD_RSCSTATE_MON_OK);
op->timeout = 0;
op->interval = 9000;
op->target_rc = CHANGED;
op->user_data_len = 1+strlen(op->user_data);
call_id = rsc->ops->perform_op(rsc, op);
free_lrm_op(op);
if (call_id > 0) {
crm_debug("Adding monitor op for %s", rsc->id);
g_hash_table_insert(
monitors, strdup(rsc->id),
GINT_TO_POINTER(call_id));
} else {
crm_err("Monitor op for %s did not have a call id",
rsc->id);
}
}
return I_NULL;
}
void
free_lrm_op(lrm_op_t *op)
{
crm_free(op->user_data);
crm_free(op->op_type);
crm_free(op);
}
GHashTable *
xml2list(xmlNodePtr parent, const char**attr_path, int depth)
{
xmlNodePtr node_iter = NULL;
xmlNodePtr nvpair_list = NULL;
GHashTable *nvpair_hash =
g_hash_table_new(&g_str_hash, &g_str_equal);
if(parent != NULL) {
nvpair_list = find_xml_node_nested(parent, attr_path, depth);
}
while(nvpair_list != NULL){
node_iter = nvpair_list->children;
while(node_iter != NULL) {
const char *key = xmlGetProp(
node_iter, XML_NVPAIR_ATTR_NAME);
const char *value = xmlGetProp(
node_iter, XML_NVPAIR_ATTR_VALUE);
crm_verbose("Added %s=%s", key, value);
g_hash_table_insert (nvpair_hash,
crm_strdup(key),
crm_strdup(value));
node_iter = node_iter->next;
}
nvpair_list=nvpair_list->next;
}
return nvpair_hash;
}
void
do_update_resource(lrm_rsc_t *rsc, lrm_op_t* op)
{
/*
<status>
<nodes_status id=uname>
<lrm>
<lrm_resources>
<lrm_resource id=>
</...>
*/
xmlNodePtr update, iter;
char *tmp = NULL;
xmlNodePtr fragment;
int len = 0;
char *fail_state = NULL;
-
if(op == NULL || rsc == NULL) {
crm_err("Either resouce or op was not specified");
return;
}
+
+ crm_info("Updating resouce %s after op %s", rsc->id, op->op_type);
update = create_xml_node(NULL, XML_CIB_TAG_STATE);
set_uuid(update, XML_ATTR_UUID, fsa_our_uname);
set_xml_property_copy(update, XML_ATTR_UNAME, fsa_our_uname);
iter = create_xml_node(update, XML_CIB_TAG_LRM);
iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES);
iter = create_xml_node(iter, "lrm_resource");
set_xml_property_copy(iter, XML_ATTR_ID, rsc->id);
set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, op->op_type);
len = strlen(op->op_type);
len += strlen("_failed_");
crm_malloc(fail_state, sizeof(char)*len);
if(fail_state != NULL) {
sprintf(fail_state, "%s_failed", op->op_type);
}
switch(op->op_status) {
case LRM_OP_CANCELLED:
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
crm_err("An LRM operation failed"
" or was aborted");
set_xml_property_copy(
iter, XML_LRM_ATTR_RSCSTATE, fail_state);
break;
case LRM_OP_DONE:
set_xml_property_copy(
iter, XML_LRM_ATTR_RSCSTATE,
op->user_data);
break;
}
crm_free(fail_state);
tmp = crm_itoa(op->rc);
set_xml_property_copy(iter, XML_LRM_ATTR_RC, tmp);
crm_free(tmp);
tmp = crm_itoa(op->op_status);
set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATUS, tmp);
crm_free(tmp);
set_xml_property_copy(iter, XML_LRM_ATTR_TARGET, fsa_our_uname);
fragment = create_cib_fragment(update, NULL);
-
- fsa_cib_conn->cmds->modify(
- fsa_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL,
- cib_discard_reply);
+
+ {
+ int rc = cib_ok;
+ rc = fsa_cib_conn->cmds->modify(
+ fsa_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL,
+ cib_sync_call);
+ if(rc != cib_ok) {
+ crm_err("Resource state update failed: %s",
+ cib_error2string(rc));
+ }
+ }
free_xml(fragment);
free_xml(update);
}
enum crmd_fsa_input
do_lrm_event(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input cur_input,
fsa_data_t *msg_data)
{
lrm_op_t* op = NULL;
lrm_rsc_t* rsc = NULL;
if(msg_data->fsa_cause != C_LRM_OP_CALLBACK) {
return I_FAIL;
}
op = (lrm_op_t*)msg_data->data;
rsc = op->rsc;
- crm_debug("Processing %d event for %s/%s",
- op->op_status, op->op_type, rsc->id);
+ crm_info("Processing %d event for %s/%s",
+ op->op_status, op->op_type, rsc->id);
switch(op->op_status) {
case LRM_OP_ERROR:
case LRM_OP_CANCELLED:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
crm_err("An LRM operation failed"
" or was aborted");
/* fall through */
case LRM_OP_DONE:
do_update_resource(rsc, op);
break;
}
return I_NULL;
}
diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c
index ea9353c97f..cebc0f073b 100644
--- a/crm/tengine/tengine.c
+++ b/crm/tengine/tengine.c
@@ -1,604 +1,602 @@
-/* $Id: tengine.c,v 1.36 2004/11/12 17:14:34 andrew Exp $ */
+/* $Id: tengine.c,v 1.37 2004/12/16 14:34:19 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <heartbeat.h>
#include <clplumbing/Gmain_timeout.h>
#include <lrm/lrm_api.h>
gboolean graph_complete = FALSE;
GListPtr graph = NULL;
IPC_Channel *crm_ch = NULL;
uint transition_timeout = 30*1000; /* 30 seconds */
uint transition_fuzz_timeout = 0;
uint default_transition_timeout = 30*1000; /* 30 seconds */
uint next_transition_timeout = 30*1000; /* 30 seconds */
void fire_synapse(synapse_t *synapse);
gboolean initiate_action(action_t *action);
gboolean confirm_synapse(synapse_t *synapse, int action_id);
void process_trigger(int action_id);
void check_synapse_triggers(synapse_t *synapse, int action_id);
gboolean in_transition = FALSE;
te_timer_t *transition_timer = NULL;
te_timer_t *transition_fuzz_timer = NULL;
int transition_counter = 0;
gboolean
initialize_graph(void)
{
if(transition_timer == NULL) {
crm_malloc(transition_timer, sizeof(te_timer_t));
transition_timer->timeout = 10;
transition_timer->source_id = -1;
transition_timer->reason = timeout_timeout;
transition_timer->action = NULL;
} else {
stop_te_timer(transition_timer);
}
if(transition_fuzz_timer == NULL) {
crm_malloc(transition_fuzz_timer, sizeof(te_timer_t));
transition_fuzz_timer->timeout = 10;
transition_fuzz_timer->source_id = -1;
transition_fuzz_timer->reason = timeout_fuzz;
transition_fuzz_timer->action = NULL;
} else {
stop_te_timer(transition_fuzz_timer);
}
while(g_list_length(graph) > 0) {
synapse_t *synapse = g_list_nth_data(graph, 0);
while(g_list_length(synapse->actions) > 0) {
action_t *action = g_list_nth_data(synapse->actions,0);
synapse->actions = g_list_remove(
synapse->actions, action);
if(action->timer->source_id > 0) {
crm_debug("Removing timer for action: %d",
action->id);
g_source_remove(action->timer->source_id);
}
free_xml(action->xml);
crm_free(action->timer);
crm_free(action);
}
while(g_list_length(synapse->inputs) > 0) {
action_t *action = g_list_nth_data(synapse->inputs, 0);
synapse->inputs =
g_list_remove(synapse->inputs, action);
free_xml(action->xml);
crm_free(action);
}
graph = g_list_remove(graph, synapse);
crm_free(synapse);
}
graph = NULL;
return TRUE;
}
/*
* returns the ID of the action if a match is found
* returns -1 if a match was not found
* returns -2 if a match was found but the action failed (and was
* not allowed to)
*/
int
match_graph_event(action_t *action, xmlNodePtr event)
{
const char *allow_fail = NULL;
const char *this_action = NULL;
const char *this_node = NULL;
const char *this_rsc = NULL;
const char *event_node;
const char *event_rsc;
const char *rsc_state;
const char *event_action;
const char *event_rc;
const char *op_status;
action_t *match = NULL;
int op_status_i = -3;
if(event == NULL) {
crm_trace("Ignoring NULL event");
return -1;
}
event_node = xmlGetProp(event, XML_LRM_ATTR_TARGET);
event_action = xmlGetProp(event, XML_LRM_ATTR_LASTOP);
event_rsc = xmlGetProp(event, XML_ATTR_ID);
event_rc = xmlGetProp(event, XML_LRM_ATTR_RC);
rsc_state = xmlGetProp(event, XML_LRM_ATTR_RSCSTATE);
op_status = xmlGetProp(event, XML_LRM_ATTR_OPSTATUS);
if(op_status != NULL) {
op_status_i = atoi(op_status);
}
this_action = xmlGetProp(action->xml, XML_LRM_ATTR_TASK);
this_node = xmlGetProp(action->xml, XML_LRM_ATTR_TARGET);
this_rsc = xmlGetProp(action->xml, XML_LRM_ATTR_RSCID);
crm_devel("matching against: <%s task=%s node=%s rsc_id=%s/>",
action->xml->name, this_action, this_node, this_rsc);
if(safe_str_neq(this_node, event_node)) {
crm_devel("node mismatch: %s", event_node);
} else if(safe_str_neq(this_action, event_action)) {
crm_devel("action mismatch: %s", event_action);
} else if(safe_str_eq(action->xml->name, "rsc_op")) {
crm_devel("rsc_op");
if(safe_str_eq(this_rsc, event_rsc)) {
match = action;
} else {
crm_devel("bad rsc (%s) != (%s)", this_rsc, event_rsc);
}
} else if(safe_str_eq(action->xml->name, "crm_event")) {
crm_devel("crm_event");
match = action;
} else {
crm_devel("no match");
}
if(match == NULL) {
crm_debug("didnt match current action");
return -1;
}
crm_debug("matched");
/* stop this event's timer if it had one */
stop_te_timer(match->timer);
/* Process OP status */
allow_fail = xmlGetProp(match->xml, "allow_fail");
switch(op_status_i) {
case LRM_OP_DONE:
break;
case LRM_OP_ERROR:
case LRM_OP_TIMEOUT:
case LRM_OP_NOTSUPPORTED:
if(safe_str_neq(allow_fail, XML_BOOLEAN_TRUE)) {
crm_err("Action %s to %s on %s resulted in"
" failure... aborting transition.",
event_action, event_rsc, event_node);
send_abort("Action failed", match->xml);
return -2;
}
break;
case LRM_OP_CANCELLED:
/* do nothing?? */
crm_warn("Dont know what to do for cancelled ops yet");
break;
default:
crm_err("Unsupported action result: %d", op_status_i);
send_abort("Unsupport action result", match->xml);
return -2;
}
crm_devel("Action %d was successful, looking for next action",
match->id);
match->complete = TRUE;
return match->id;
}
gboolean
process_graph_event(xmlNodePtr event)
{
int action_id = -1;
int op_status_i = 0;
const char *op_status = xmlGetProp(event, XML_LRM_ATTR_OPSTATUS);
next_transition_timeout = transition_timeout;
if(op_status != NULL) {
op_status_i = atoi(op_status);
}
if(op_status_i == -1) {
/* just information that the action was sent */
crm_trace("Ignoring TE initiated updates");
return TRUE;
}
slist_iter(
synapse, synapse_t, graph, lpc,
/* lookup event */
slist_iter(
action, action_t, synapse->actions, lpc2,
action_id = match_graph_event(action, event);
if(action_id != -1) {
break;
}
);
if(action_id != -1) {
break;
}
);
if(action_id > -1) {
crm_xml_devel(event, "Event found");
} else if(action_id == -2) {
crm_xml_info(event, "Event found but failed");
} else if(event != NULL) {
/* unexpected event, trigger a pe-recompute */
/* possibly do this only for certain types of actions */
send_abort("Event not matched", event);
return FALSE;
/* } else { we dont care, a transition is starting */
}
process_trigger(action_id);
if(graph_complete) {
/* allow some slack until we are pretty sure nothing
* else is happening
*/
crm_info("Transition complete");
print_state(TRUE);
if(transition_fuzz_timer->timeout > 0) {
crm_info("Allowing the system to stabilize for %d ms"
" before S_IDLE transition",
transition_fuzz_timer->timeout);
start_te_timer(transition_fuzz_timer);
} else {
send_success("complete");
}
} else {
/* restart the transition timer again */
crm_info("Transition not yet complete");
print_state(TRUE);
transition_timer->timeout = next_transition_timeout;
start_te_timer(transition_timer);
}
return TRUE;
}
gboolean
initiate_action(action_t *action)
{
gboolean ret = FALSE;
xmlNodePtr options = NULL;
xmlNodePtr data = NULL;
const char *on_node = NULL;
const char *id = NULL;
const char *runnable = NULL;
const char *optional = NULL;
const char *task = NULL;
const char *discard = NULL;
const char *timeout = NULL;
const char *destination = NULL;
#ifndef TESTING
xmlNodePtr rsc_op = NULL;
#endif
discard = xmlGetProp(action->xml, XML_LRM_ATTR_DISCARD);
on_node = xmlGetProp(action->xml, XML_LRM_ATTR_TARGET);
id = xmlGetProp(action->xml, XML_ATTR_ID);
runnable = xmlGetProp(action->xml, XML_LRM_ATTR_RUNNABLE);
optional = xmlGetProp(action->xml, XML_LRM_ATTR_OPTIONAL);
task = xmlGetProp(action->xml, XML_LRM_ATTR_TASK);
timeout = xmlGetProp(action->xml, "timeout");
if(id == NULL || strlen(id) == 0
|| task == NULL || strlen(task) == 0) {
/* error */
crm_err("Failed on corrupted command: %s (id=%s) %s",
action->xml->name, crm_str(id), crm_str(task));
} else if(action->type == action_type_pseudo){
crm_info("Executing pseudo-event (%d): "
"%s on %s", action->id, task, on_node);
action->complete = TRUE;
process_trigger(action->id);
ret = TRUE;
} else if(on_node == NULL || strlen(on_node) == 0) {
/* error */
crm_err("Failed on corrupted command: %s (id=%s) %s on %s",
action->xml->name, crm_str(id),
crm_str(task), crm_str(on_node));
} else if(action->type == action_type_crm){
/*
<crm_msg op=XML_LRM_ATTR_TASK to=XML_RES_ATTR_TARGET>
*/
crm_info("Executing crm-event (%s): %s on %s",
id, task, on_node);
#ifndef TESTING
data = NULL;
action->complete = TRUE;
destination = CRM_SYSTEM_CRMD;
options = create_xml_node(NULL, XML_TAG_OPTIONS);
set_xml_property_copy(options, XML_ATTR_OP, task);
#endif
ret = TRUE;
} else if(action->type == action_type_rsc){
crm_info("Executing rsc-op (%s): %s %s on %s",
id, task,
xmlGetProp(action->xml->children, XML_ATTR_ID),
on_node);
/* let everyone know this was invoked */
do_update_cib(action->xml, -1);
#ifndef TESTING
/*
<msg_data>
<rsc_op id="operation number" on_node="" task="">
<resource>...</resource>
*/
data = create_xml_node(NULL, "msg_data");
rsc_op = create_xml_node(data, "rsc_op");
options = create_xml_node(NULL, XML_TAG_OPTIONS);
set_xml_property_copy(options, XML_ATTR_OP, "rsc_op");
set_xml_property_copy(rsc_op, XML_ATTR_ID, id);
set_xml_property_copy(rsc_op, XML_LRM_ATTR_TASK, task);
set_xml_property_copy(rsc_op, XML_LRM_ATTR_TARGET, on_node);
add_node_copy(rsc_op, action->xml->children);
destination = CRM_SYSTEM_LRMD;
-
-
#endif
ret = TRUE;
} else {
crm_err("Failed on unsupported command type: "
"%s, %s (id=%s) on %s",
action->xml->name, task, id, on_node);
}
if(ret && options != NULL) {
char *counter = crm_itoa(transition_counter);
set_xml_property_copy(
options, "transition_id", crm_str(counter));
crm_free(counter);
crm_xml_debug(options, "Performing");
if(data != NULL) {
crm_xml_debug(data, "Performing");
}
#ifdef MSG_LOG
if(msg_te_strm != NULL) {
char *message = dump_xml_formatted(data);
char *ops = dump_xml_formatted(options);
fprintf(msg_te_strm, "[Action]\t%s\n%s\n",
crm_str(ops), crm_str(message));
fflush(msg_te_strm);
crm_free(message);
crm_free(ops);
}
#endif
send_ipc_request(
crm_ch, options, data, on_node,
destination, CRM_SYSTEM_TENGINE, NULL, NULL);
if(action->timeout > 0) {
crm_debug("Setting timer for action %d",action->id);
start_te_timer(action->timer);
}
}
free_xml(options);
free_xml(data);
return ret;
}
gboolean
initiate_transition(void)
{
crm_info("Initating transition");
process_graph_event(NULL);
return TRUE;
}
void
check_synapse_triggers(synapse_t *synapse, int action_id)
{
synapse->triggers_complete = TRUE;
if(synapse->confirmed) {
crm_debug("Skipping confirmed synapse %d", synapse->id);
return;
} else if(synapse->complete == FALSE) {
crm_debug("Checking pre-reqs for %d", synapse->id);
/* lookup prereqs */
slist_iter(
prereq, action_t, synapse->inputs, lpc,
crm_devel("Processing input %d", prereq->id);
if(prereq->id == action_id) {
crm_devel("Marking input %d complete",
action_id);
prereq->complete = TRUE;
} else if(prereq->complete == FALSE) {
crm_devel("Inputs for synapse %d not satisfied",
synapse->id);
synapse->triggers_complete = FALSE;
}
);
}
}
void
fire_synapse(synapse_t *synapse)
{
if(synapse == NULL) {
crm_err("Synapse was NULL!");
return;
}
crm_debug("Checking if synapse %d needs to be fired", synapse->id);
if(synapse->complete) {
crm_debug("Skipping complete synapse %d", synapse->id);
return;
} else if(synapse->triggers_complete == FALSE) {
crm_debug("Synapse %d not yet satisfied", synapse->id);
return;
}
crm_devel("All inputs for synapse %d satisfied... invoking actions",
synapse->id);
synapse->complete = TRUE;
slist_iter(
action, action_t, synapse->actions, lpc,
/* allow some leway */
int tmp_time = 2 * action->timeout;
gboolean passed = FALSE;
action->invoked = TRUE;
/* Invoke the action and start the timer */
passed = initiate_action(action);
if(passed == FALSE) {
crm_err("Failed initiating <%s id=%d> in synapse %d",
action->xml->name, action->id, synapse->id);
send_abort("Action init failed", action->xml);
return;
}
if(tmp_time > next_transition_timeout) {
next_transition_timeout = tmp_time;
}
);
crm_debug("Synapse %d complete", synapse->id);
}
gboolean
confirm_synapse(synapse_t *synapse, int action_id)
{
gboolean complete = TRUE;
synapse->confirmed = TRUE;
slist_iter(
action, action_t, synapse->actions, lpc,
if(action->type == action_type_rsc
&& action->complete == FALSE) {
complete = FALSE;
synapse->confirmed = FALSE;
crm_debug("Found an incomplete action"
" - transition not complete");
break;
}
);
return complete;
}
void
process_trigger(int action_id)
{
graph_complete = TRUE;
crm_debug("Processing trigger from action %d", action_id);
/* something happened, stop the timer and start it again at the end */
stop_te_timer(transition_timer);
slist_iter(
synapse, synapse_t, graph, lpc,
if(synapse->confirmed) {
crm_debug("Skipping confirmed synapse %d", synapse->id);
continue;
}
check_synapse_triggers(synapse, action_id);
fire_synapse(synapse);
if(graph == NULL) {
crm_err("Trigger processing aborted after failed synapse");
break;
}
crm_debug("Checking if %d is confirmed", synapse->id);
if(synapse->complete == FALSE) {
crm_debug("Found an incomplete synapse"
" - transition not complete");
/* indicate that the transition is not yet complete */
graph_complete = FALSE;
} else if(synapse->confirmed == FALSE) {
graph_complete = graph_complete
&& confirm_synapse(synapse, action_id);
}
crm_debug("%d is %s", synapse->id,
synapse->confirmed?"confirmed":synapse->complete?"complete":"pending");
);
}
diff --git a/crm/test/2node-fail.sh.in b/crm/test/2node-fail.sh.in
index 6253cd869e..b3995c8575 100644
--- a/crm/test/2node-fail.sh.in
+++ b/crm/test/2node-fail.sh.in
@@ -1,339 +1,341 @@
#!/bin/bash
#
# Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
#
# 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
# of the License, or (at your option) any later version.
#
# This program 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 program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
testdir=@libdir@/heartbeat/crmtest
. ${testdir}/helper.sh || exit 1
CRM_ERR_SHUTDOWN=0
test_nodes=2
function 2node_fail_test() {
test_type=$1
fail_pieces=$2
fail_node=$3
good_node=$4
do_failback=$5
accelerated=$6
if [ $fail_node = $test_node_1 ]; then
moved_rsc=rsc1
else
moved_rsc=rsc2
fi
#----
echo -ne "\033]0;$test_type: Iteration $iteration of $repeats\007"
crm-cleanup
do_cmd echo "#############################"
do_cmd echo "$test_type: Iteration $iteration of $repeats"
# make *sure* theres nothing left over from last time
#----
do_cmd echo "wait for HA to start on ${test_node_1}"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd remote_cmd $INIT_USER $test_node_1 $HALIB_DIR/heartbeat -M "2>&1 >/dev/null" &
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 1000 \
-s "${test_node_1} ccm(.*): info: Hostname: ${test_node_1}" \
-s "${test_node_1} heartbeat(.*) info: Starting(.*)lrmd" \
-e "${test_node_1} heartbeat(.*)Client(.*) respawning too fast"
cts_assert "Startup of Heartbeat on ${test_node_1} failed."
#----
do_cmd echo "wait for CRMd to start on ${test_node_1}"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd remote_cmd $CRMD_USER $test_node_1 $HALIB_DIR/crmd "$CRM_OPTS" "2>&1 >/dev/null" &
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 1500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 2500 \
-s "${test_node_1} crmd(.*): info:(.*)FSA Hostname: ${test_node_1}" \
-s "crmd(.*) State transition (.*) \-> \"S_IDLE\""
cts_assert "CRMd startup on ${test_node_1} failed."
do_cmd wait_for_state S_IDLE 3 $test_node_1
cts_assert "S_IDLE not reached on $test_node_1 (startup)!"
#----
do_cmd echo Create the first constraint and wait for S_IDLE
rsc=rsc1
uuid1=`uuidgen`
uuid2=`uuidgen`
uuid3=`uuidgen`
node_xml="'<rsc_location id=\"${uuid1}\" rsc=\"${rsc}\">
<rule id=\"${uuid2}\" result=\"can\"/>
<rule id=\"${uuid3}\" score=\"1000\" boolean_op=\"or\">
<expression attribute=\"uname\" operation=\"eq\" value=\"${test_node_1}\"/>
</rule>
</rsc_location>'"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd make_constraint_adv $test_node_1 $node_xml
do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 1500 \
-s "crmd(.*) State transition (.*) \-> \"S_IDLE\""
cts_assert Adding constraint1 did not pass
#----
do_cmd echo Create the second constraint and wait for S_IDLE
rsc=rsc2
uuid1=`uuidgen`
uuid2=`uuidgen`
uuid3=`uuidgen`
node_xml="'<rsc_location id=\"${uuid1}\" rsc=\"${rsc}\">
<rule id=\"${uuid2}\" result=\"can\"/>
<rule id=\"${uuid3}\" score=\"1000\" boolean_op=\"or\">
<expression attribute=\"uname\" operation=\"eq\" value=\"${test_node_2}\"/>
</rule>
</rsc_location>'"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd make_constraint_adv $test_node_1 $node_xml
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 1500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 2500 \
-s "crmd(.*) State transition (.*) \-> \"S_IDLE\""
cts_assert Adding constraint2 did not pass
#----
do_cmd echo Create the first resource and wait for S_IDLE after start
args="<nvpair name=\"1\" value=\"${ip_rsc_1}\"/>"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd make_resource $test_node_1 rsc1 heartbeat IPaddr - - ignore $args
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 1500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 2500 \
-s "crmd(.*) State transition (.*) \-> \"S_IDLE\"" \
-s "crmd(.*) Performing op start(.*) on rsc1" \
-s "crmd(.*) Resource state: rsc1(.*) after start"
cts_assert Adding rsc1 did not pass
#----
do_cmd echo Create the second resource and wait for S_IDLE after start
args="<nvpair name=\"1\" value=\"${ip_rsc_2}\"/>"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd make_resource $test_node_1 rsc2 heartbeat IPaddr - - ignore $args
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 1500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 2500 \
-s "crmd(.*) State transition (.*) \-> \"S_IDLE\"" \
-s "crmd(.*) Performing op start(.*) on rsc2" \
-s "crmd(.*) Resource state: rsc2(.*) after start"
cts_assert Adding rsc2 did not pass
#----
do_cmd echo Various sanity checks - stage 1
do_cmd wait_for_state S_IDLE 3 $test_node_1
cts_assert "S_IDLE not reached on $test_node_1 (CIB create)!"
do_cmd is_running rsc1 $test_node_1
cts_assert "rsc1 NOT running"
do_cmd is_running rsc2 $test_node_1
cts_assert "rsc2 NOT running"
do_cmd is_dc $test_node_1
cts_assert "$test_node_1 is supposed to be the DC"
do_cmd is_running rsc1 $test_node_1 x$test_node_1
cts_assert_false "rsc1 IS running on x$test_node_1"
do_cmd is_running rsc1 $test_node_1 $test_node_1
cts_assert "rsc1 NOT running on $test_node_1"
do_cmd is_running rsc2 $test_node_1 $test_node_1
cts_assert "rsc2 NOT running on $test_node_1"
#----
do_cmd echo "wait for HA to start on $test_node_2"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd remote_cmd $INIT_USER $test_node_2 $HALIB_DIR/heartbeat -M "2>&1 >/dev/null" &
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 1500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 5000 \
-s "${test_node_2} ccm(.*) Hostname: ${test_node_2}" \
-s "${test_node_2} heartbeat(.*): info: Starting (.*)lrmd" \
-e "${test_node_2} heartbeat(.*) Client (.*) respawning too fast"
cts_assert "Startup of Heartbeat on ${test_node_2} failed."
#----
do_cmd echo "wait for CRMd to start on $test_node_2"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd remote_cmd $CRMD_USER $test_node_2 $HALIB_DIR/crmd "$CRM_OPTS" "2>&1 >/dev/null" &
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 2500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 5000 \
-s "${test_node_2} crmd(.*)FSA Hostname: ${test_node_2}" \
-s "${test_node_2} crmd(.*) State transition \"S_PENDING\" \-> \"S_NOT_DC\""
cts_assert "CRMd startup on ${test_node_2} failed."
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 3500 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 8000 \
-s "${test_node_1} crmd(.*) State transition(.*) \-> \"S_IDLE\"" \
-s "${test_node_2} crmd(.*) Performing op start(.*) on rsc2" \
-s "crmd(.*) Resource state: rsc2(.*) after start] on ${test_node_2}"
cts_assert "rsc2 was not transferred to ${test_node_2} on startup."
#----
do_cmd echo Various sanity checks - stage 2
do_cmd wait_for_state S_NOT_DC 30 $test_node_2
cts_assert "S_NOT_DC not reached on $test_node_2 (startup - 2)!"
do_cmd wait_for_state S_IDLE 30 $test_node_1
cts_assert "S_IDLE not reached on $test_node_1 (startup - 2)!"
do_cmd is_running rsc1 $test_node_1
cts_assert "rsc1 NOT running"
do_cmd is_running rsc2 $test_node_1
cts_assert "rsc2 NOT running"
do_cmd is_running rsc1 $test_node_1 $test_node_1
cts_assert "rsc1 NOT running on $test_node_1"
do_cmd is_running rsc2 $test_node_1 $test_node_2
cts_assert "rsc2 NOT running on $test_node_2"
#----
is_dc $fail_node 2>&1 > /dev/null
test_for_election=$?
do_cmd echo Killing $fail_pieces on $fail_node
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd remote_cmd $ADMIN_USER $fail_node "killall -9 $fail_pieces" &
if [ $test_for_election = 0 ]; then
do_cmd echo Killed the DC... checking for DC Failover
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 60000 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 80000 \
+ -s "${good_node} crmd(.*) State transition" \
-s "${good_node} crmd(.*) State transition (.*) \-> \"S_ELECTION\"" \
-s "${good_node} crmd(.*) State transition (.*) \-> \"S_IDLE\""
cts_assert "Transition of the DC from ${fail_node} to ${good_node} failed."
else
do_cmd echo Killed slave node... checking the DC noticed
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 60000 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 80000 \
+ -s "${good_node} crmd(.*) State transition" \
-s "${good_node} crmd(.*) State transition (.*) \-> \"S_POLICY_ENGINE\"" \
-s "${good_node} crmd(.*) State transition (.*) \-> \"S_IDLE\""
cts_assert "Failure of slave node ${fail_node} was not noticed on the DC (${good_node})."
fi
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 60000 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 80000 \
-s "${god_node} crmd(.*) Performing op start(.*) on ${moved_rsc}" \
-s "crmd(.*) Resource state: ${moved_rsc}(.*) after start] on ${good_node}"
cts_assert "Move of ${moved_rsc} to ${good_node} failed."
#----
do_cmd echo Various sanity checks - stage 3
do_cmd wait_for_state S_IDLE 60 $good_node
cts_assert "S_IDLE not reached on $good_node after kill!"
do_cmd is_running rsc1 $good_node
cts_assert "rsc1 NOT running on $good_node"
do_cmd is_running rsc2 $good_node
cts_assert "rsc2 NOT running on $good_node"
do_cmd is_running rsc1 $good_node $fail_node
cts_assert_false "rsc1 IS running on $fail_node"
do_cmd is_running rsc2 $good_node $good_node
cts_assert "rsc2 NOT running on $good_node"
#----
if [ $do_failback = 1 ]; then
do_cmd echo "Re-Starting on failed node $fail_node"
if [ "$fail_pieces" = "crmd" ]; then
do_cmd echo "HA still running, skipping restart"
else
do_cmd echo "wait for HA to start on $fail_node"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd remote_cmd $INIT_USER $fail_node $HALIB_DIR/heartbeat -M "2>&1 >/dev/null" &
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 2000 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 5000 \
-s "${fail_node} ccm(.*) Hostname: ${fail_node}" \
-s "${fail_node} heartbeat(.*): info: Starting (.*)lrmd" \
-e "${fail_node} heartbeat(.*) Client (.*) respawning too fast"
cts_assert "Startup of Heartbeat on ${fail_node} failed."
fi
#----
do_cmd echo "wait for CRMd to start on $fail_node"
crm_log_pos=$(stat -L -c %s $logfile)
do_cmd remote_cmd $CRMD_USER $fail_node $HALIB_DIR/crmd "$CRM_OPTS" "2>&1 >/dev/null" &
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 10000 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 20000 \
-s "${fail_node} crmd(.*)FSA Hostname: ${fail_node}" \
-s "${fail_node} crmd(.*) State transition \"S_PENDING\" \-> \"S_NOT_DC\""
cts_assert "CRMd startup on ${fail_node} failed."
- do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 10000 \
+ do_cmd ${testdir}/testutils.pl -p $crm_log_pos -l ${logfile} --search -a -m 20000 \
-s "${good_node} crmd(.*) State transition(.*) \-> \"S_IDLE\"" \
-s "${fail_node} crmd(.*) Performing op start(.*) on ${moved_rsc}" \
-s "crmd(.*) Resource state: ${moved_rsc}(.*) after start] on ${fail_node}"
cts_assert "$moved_rsc was not transferred to ${fail_node} on startup."
do_cmd echo Various sanity checks - stage 4
do_cmd wait_for_state S_NOT_DC 30 $fail_node
cts_assert "S_NOT_DC not reached on $fail_node (restart)!"
do_cmd wait_for_state S_IDLE 30 $good_node
cts_assert "S_IDLE not reached on $good_node (restart)!"
do_cmd is_running rsc1 $test_node_1
cts_assert "rsc1 NOT running"
do_cmd is_running rsc2 $test_node_1
cts_assert "rsc2 NOT running"
do_cmd is_running rsc1 $test_node_1 $test_node_1
cts_assert "rsc1 NOT running on $test_node_1"
do_cmd is_running rsc2 $test_node_1 $test_node_2
cts_assert "rsc2 NOT running on $test_node_2"
fi
#----
do_cmd echo "test ${test_type}: PASSED"
}
while [ $iteration -lt $repeats ]; do
iteration=`expr $iteration + 1`
echo -ne "\033]0;$test_type : Iteration $iteration of $repeats\007"
echo "########### $test_type : Begining iteration $iteration of $repeats ###########"
(
2node_fail_test 2node__fail_DC_All "heartbeat ccm lrmd crmd" ${test_node_1} ${test_node_2} 0 0
2node_fail_test 2node__fail_slave_All "heartbeat ccm lrmd crmd" ${test_node_2} ${test_node_1} 0 0
2node_fail_test 2node__failback_DC_All "heartbeat ccm lrmd crmd" ${test_node_1} ${test_node_2} 1 0
2node_fail_test 2node__failback_slave_All "heartbeat ccm lrmd crmd" ${test_node_2} ${test_node_1} 1 0
2node_fail_test 2node__fail_DC_CRMd "crmd" ${test_node_1} ${test_node_2} 0 0
2node_fail_test 2node__fail_slave_CRMd "crmd" ${test_node_2} ${test_node_1} 0 0
2node_fail_test 2node__failback_DC_CRMd "crmd" ${test_node_1} ${test_node_2} 1 0
2node_fail_test 2node__failback_slave_CRMd "crmd" ${test_node_2} ${test_node_1} 1 0
#2node_fail_test 2node__fail_slave_LRM "lrmd" ${test_node_2} ${test_node_1}
#2node_fail_test 2node__fail_DC_LRM "lrmd" ${test_node_1} ${test_node_2}
echo "test suite: PASSED"
)
done
diff --git a/include/crm/cib.h b/include/crm/cib.h
index d5095bacc6..6c270aeb37 100644
--- a/include/crm/cib.h
+++ b/include/crm/cib.h
@@ -1,266 +1,269 @@
-/* $Id: cib.h,v 1.10 2004/12/10 20:07:07 andrew Exp $ */
+/* $Id: cib.h,v 1.11 2004/12/16 14:34:16 andrew Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#ifndef CIB__H
#define CIB__H
#include <libxml/tree.h>
#include <clplumbing/ipc.h>
#include <ha_msg.h>
enum cib_variant {
cib_native,
cib_database,
cib_edir
};
enum cib_state {
cib_connected_command,
cib_connected_query,
cib_disconnected
};
enum cib_conn_type {
cib_command,
cib_query,
cib_no_connection
};
enum cib_call_options {
cib_none = 0x000000,
cib_verbose = 0x000001,
cib_discard_reply = 0x000004,
cib_scope_local = 0x000010,
/* cib_scope_global = 0x000020, */
cib_sync_call = 0x000040,
/* cib_async_call = 0x000080, */
cib_inhibit_notify= 0x000100
};
#define cib_default_options = cib_none
enum cib_errors {
cib_ok = 0,
cib_operation = -1,
cib_create_msg = -2,
cib_not_connected = -3,
cib_not_authorized = -4,
cib_send_failed = -5,
cib_reply_failed = -6,
cib_return_code = -7,
cib_output_ptr = -8,
cib_output_data = -9,
cib_connection = -10,
cib_authentication = -11,
cib_missing = -12,
cib_variant = -28,
CIBRES_MISSING_ID = -13,
CIBRES_MISSING_TYPE = -14,
CIBRES_MISSING_FIELD = -15,
CIBRES_OBJTYPE_MISMATCH = -16,
CIBRES_CORRUPT = -17,
CIBRES_OTHER = -18,
cib_unknown = -19,
cib_STALE = -20,
cib_EXISTS = -21,
cib_NOTEXISTS = -22,
cib_ACTIVATION = -23,
cib_NOSECTION = -24,
cib_NOOBJECT = -25,
cib_NOPARENT = -26,
cib_NODECOPY = -27,
cib_NOTSUPPORTED = -29,
cib_registration_msg = -30,
cib_callback_token = -31,
cib_callback_register = -32,
cib_msg_field_add = -33,
cib_client_gone = -34,
cib_not_master = -35,
- cib_client_corrupt = -36
+ cib_client_corrupt = -36,
+ cib_master_timeout = -37
};
enum cib_op {
CIB_OP_NONE = 0,
CIB_OP_ADD,
CIB_OP_MODIFY,
CIB_OP_DELETE,
CIB_OP_MAX
};
enum cib_section {
cib_section_none,
cib_section_all,
cib_section_nodes,
cib_section_constraints,
cib_section_resources,
cib_section_crmconfig,
cib_section_status
};
#define F_CIB_CLIENTID "cib_clientid"
#define F_CIB_CALLOPTS "cib_callopt"
#define F_CIB_CALLID "cib_callid"
#define F_CIB_CALLDATA "cib_calldata"
#define F_CIB_OPERATION "cib_op"
#define F_CIB_ISREPLY "cib_isreplyto"
#define F_CIB_SECTION "cib_section"
#define F_CIB_HOST "cib_host"
#define F_CIB_RC "cib_rc"
#define F_CIB_CALLBACK_TOKEN "cib_callback_token"
#define F_CIB_GLOBAL_UPDATE "cib_update"
#define F_CIB_DELEGATED "cib_delegated_from"
#define F_CIB_OBJID "cib_object"
#define F_CIB_OBJTYPE "cib_object_type"
+#define F_CIB_EXISTING "cib_existing_object"
+#define F_CIB_SEENCOUNT "cib_seen"
+#define F_CIB_TIMEOUT "cib_timeout"
#define F_CIB_UPDATE "cib_update"
#define F_CIB_UPDATE_RESULT "cib_update_result"
-#define F_CIB_EXISTING "cib_existing_object"
#define T_CIB "cib"
#define T_CIB_NOTIFY "cib_notify"
/* notify sub-types */
#define T_CIB_PRE_NOTIFY "cib_pre_notify"
#define T_CIB_POST_NOTIFY "cib_post_notify"
#define T_CIB_UPDATE_CONFIRM "cib_update_confirmation"
typedef struct cib_s cib_t;
typedef struct cib_api_operations_s
{
int (*variant_op)(
cib_t *cib, const char *op, const char *host,
const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options);
int (*signon) (cib_t *cib, enum cib_conn_type type);
int (*signoff)(cib_t *cib);
int (*free) (cib_t *cib);
int (*set_op_callback)(
cib_t *cib, void (*callback)(
const struct ha_msg *msg, int callid ,
int rc, xmlNodePtr output));
int (*add_notify_callback)(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
int (*del_notify_callback)(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
int (*set_connection_dnotify)(
cib_t *cib, void (*dnotify)(gpointer user_data));
IPC_Channel *(*channel)(cib_t* cib);
int (*inputfd)(cib_t* cib);
int (*noop)(cib_t *cib, int call_options);
int (*ping)(
cib_t *cib, xmlNodePtr *output_data, int call_options);
int (*query)(cib_t *cib, const char *section,
xmlNodePtr *output_data, int call_options);
int (*query_from)(
cib_t *cib, const char *host, const char *section,
xmlNodePtr *output_data, int call_options);
gboolean (*is_master) (cib_t *cib);
int (*set_master)(cib_t *cib, int call_options);
int (*set_slave) (cib_t *cib, int call_options);
int (*set_slave_all)(cib_t *cib, int call_options);
int (*sync)(cib_t *cib, const char *section, int call_options);
int (*sync_from)(
cib_t *cib, const char *host, const char *section,
int call_options);
int (*bump_epoch)(cib_t *cib, int call_options);
int (*create)(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int (*modify)(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int (*replace)(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int (*delete)(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int (*erase)(
cib_t *cib, xmlNodePtr *output_data, int call_options);
int (*quit)(cib_t *cib, int call_options);
gboolean (*msgready)(cib_t* cib);
int (*rcvmsg)(cib_t* cib, int blocking);
gboolean (*dispatch)(IPC_Channel *channel, gpointer user_data);
} cib_api_operations_t;
struct cib_s
{
enum cib_state state;
enum cib_conn_type type;
int call_id;
void *variant_opaque;
GList *notify_list;
void (*op_callback)(const struct ha_msg *msg, int call_id,
int rc, xmlNodePtr output);
cib_api_operations_t *cmds;
};
typedef struct cib_notify_client_s
{
const char *event;
const char *obj_id; /* implement one day */
const char *obj_type; /* implement one day */
void (*callback)(
const char *event, struct ha_msg *msg);
} cib_notify_client_t;
/* Core functions */
extern cib_t *cib_new(void);
extern gboolean startCib(const char *filename);
extern xmlNodePtr get_cib_copy(cib_t *cib);
extern xmlNodePtr cib_get_generation(cib_t *cib);
extern int cib_compare_generation(xmlNodePtr left, xmlNodePtr right);
/* Utility functions */
extern xmlNodePtr get_object_root(const char *object_type,xmlNodePtr the_root);
extern xmlNodePtr create_cib_fragment_adv(
xmlNodePtr update, const char *section, const char *source);
extern char *cib_pluralSection(const char *a_section);
/* Error Interpretation*/
extern const char *cib_error2string(enum cib_errors);
extern const char *cib_op2string(enum cib_op);
extern xmlNodePtr createEmptyCib(void);
extern gboolean verifyCibXml(xmlNodePtr cib);
extern int cib_section2enum(const char *a_section);
#define create_cib_fragment(update,section) create_cib_fragment_adv(update, section, __FUNCTION__)
#endif
diff --git a/lib/crm/cib/cib_client.c b/lib/crm/cib/cib_client.c
index 93279683c9..33714c1086 100755
--- a/lib/crm/cib/cib_client.c
+++ b/lib/crm/cib/cib_client.c
@@ -1,1084 +1,1087 @@
/*
* 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
*
*/
#include <portability.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <glib.h>
#include <heartbeat.h>
#include <clplumbing/ipc.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
gboolean verify_cib_cmds(cib_t *cib);
int cib_client_set_op_callback(
cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id,
int rc, xmlNodePtr output));
int cib_client_noop(cib_t *cib, int call_options);
int cib_client_ping(cib_t *cib, xmlNodePtr *output_data, int call_options);
int cib_client_query(cib_t *cib, const char *section,
xmlNodePtr *output_data, int call_options);
int cib_client_query_from(cib_t *cib, const char *host, const char *section,
xmlNodePtr *output_data, int call_options);
int cib_client_sync(cib_t *cib, const char *section, int call_options);
int cib_client_sync_from(
cib_t *cib, const char *host, const char *section, int call_options);
gboolean cib_client_is_master(cib_t *cib);
int cib_client_set_slave(cib_t *cib, int call_options);
int cib_client_set_slave_all(cib_t *cib, int call_options);
int cib_client_set_master(cib_t *cib, int call_options);
int cib_client_bump_epoch(cib_t *cib, int call_options);
int cib_client_create(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int cib_client_modify(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int cib_client_replace(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int cib_client_delete(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options) ;
int cib_client_erase(
cib_t *cib, xmlNodePtr *output_data, int call_options);
int cib_client_quit(cib_t *cib, int call_options);
int cib_client_add_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
int cib_client_del_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg));
-gint cib_GCompareFunc(gconstpointer a, gconstpointer b);
+gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b);
extern cib_t *cib_native_new(cib_t *cib);
static enum cib_variant configured_variant = cib_native;
/* define of the api functions*/
cib_t*
cib_new(void)
{
cib_t* new_cib = NULL;
if(configured_variant != cib_native) {
crm_err("Only the native CIB type is currently implemented");
return NULL;
}
crm_malloc(new_cib, sizeof(cib_t));
new_cib->call_id = 1;
new_cib->type = cib_none;
new_cib->state = cib_disconnected;
new_cib->op_callback = NULL;
new_cib->variant_opaque = NULL;
new_cib->notify_list = NULL;
/* the rest will get filled in by the variant constructor */
crm_malloc(new_cib->cmds, sizeof(cib_api_operations_t));
memset(new_cib->cmds, 0, sizeof(cib_api_operations_t));
new_cib->cmds->set_op_callback = cib_client_set_op_callback;
new_cib->cmds->add_notify_callback = cib_client_add_notify_callback;
new_cib->cmds->del_notify_callback = cib_client_del_notify_callback;
new_cib->cmds->noop = cib_client_noop;
new_cib->cmds->ping = cib_client_ping;
new_cib->cmds->query = cib_client_query;
new_cib->cmds->sync = cib_client_sync;
new_cib->cmds->query_from = cib_client_query_from;
new_cib->cmds->sync_from = cib_client_sync_from;
new_cib->cmds->is_master = cib_client_is_master;
new_cib->cmds->set_master = cib_client_set_master;
new_cib->cmds->set_slave = cib_client_set_slave;
new_cib->cmds->set_slave_all = cib_client_set_slave_all;
new_cib->cmds->bump_epoch = cib_client_bump_epoch;
new_cib->cmds->create = cib_client_create;
new_cib->cmds->modify = cib_client_modify;
new_cib->cmds->replace = cib_client_replace;
new_cib->cmds->delete = cib_client_delete;
new_cib->cmds->erase = cib_client_erase;
new_cib->cmds->quit = cib_client_quit;
cib_native_new(new_cib);
if(verify_cib_cmds(new_cib) == FALSE) {
return NULL;
}
return new_cib;
}
int
cib_client_set_op_callback(
cib_t *cib, void (*callback)(const struct ha_msg *msg, int call_id,
int rc, xmlNodePtr output))
{
if(callback == NULL) {
crm_info("Un-Setting operation callback");
} else {
crm_debug("Setting operation callback");
}
cib->op_callback = callback;
return cib_ok;
}
int cib_client_noop(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_NOOP, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_ping(cib_t *cib, xmlNodePtr *output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_PING, NULL,NULL,NULL, output_data, call_options);
}
int cib_client_query(cib_t *cib, const char *section,
xmlNodePtr *output_data, int call_options)
{
return cib->cmds->query_from(
cib, NULL, section, output_data, call_options);
}
int cib_client_query_from(cib_t *cib, const char *host, const char *section,
xmlNodePtr *output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CRM_OP_CIB_QUERY, host, section,
NULL, output_data, call_options);
}
gboolean cib_client_is_master(cib_t *cib)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_CIB_ISMASTER, NULL, NULL,NULL,NULL,
cib_scope_local|cib_sync_call);
}
int cib_client_set_slave(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_CIB_SLAVE, NULL,NULL,NULL,NULL, call_options);
}
int cib_client_set_slave_all(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_CIB_SLAVEALL, NULL,NULL,NULL,NULL, call_options);
}
int cib_client_set_master(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
crm_debug("Adding cib_scope_local to options");
return cib->cmds->variant_op(
cib, CRM_OP_CIB_MASTER, NULL,NULL,NULL,NULL,
call_options|cib_scope_local);
}
int cib_client_bump_epoch(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_CIB_BUMP, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_sync(cib_t *cib, const char *section, int call_options)
{
return cib->cmds->sync_from(cib, NULL, section, call_options);
}
int cib_client_sync_from(
cib_t *cib, const char *host, const char *section, int call_options)
{
enum cib_errors rc = cib_ok;
xmlNodePtr stored_cib = NULL;
xmlNodePtr current_cib = NULL;
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
crm_debug("Retrieving current CIB from %s", host);
rc = cib->cmds->query_from(
cib, host, section, ¤t_cib, call_options|cib_sync_call);
if(rc == cib_ok) {
if(call_options & cib_scope_local) {
/* having scope == local makes no sense from here on */
call_options ^= cib_scope_local;
}
crm_debug("Storing current CIB (should trigger a store everywhere)");
crm_xml_debug(current_cib, "XML to store");
rc = cib->cmds->replace(
cib, section, current_cib, &stored_cib, call_options);
}
free_xml(current_cib);
free_xml(stored_cib);
return rc;
}
int cib_client_create(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CRM_OP_CIB_CREATE, NULL, section,
data, output_data, call_options);
}
int cib_client_modify(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CRM_OP_CIB_UPDATE, NULL, section,
data, output_data, call_options);
}
int cib_client_replace(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CRM_OP_CIB_REPLACE, NULL, NULL,
data, output_data, call_options);
}
int cib_client_delete(cib_t *cib, const char *section, xmlNodePtr data,
xmlNodePtr *output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CRM_OP_CIB_DELETE, NULL, section,
data, output_data, call_options);
}
int cib_client_erase(
cib_t *cib, xmlNodePtr *output_data, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(cib, CRM_OP_CIB_ERASE, NULL, NULL, NULL,
output_data, call_options);
}
int cib_client_quit(cib_t *cib, int call_options)
{
if(cib == NULL) {
return cib_missing;
} else if(cib->state == cib_disconnected) {
return cib_not_connected;
} else if(cib->cmds->variant_op == NULL) {
return cib_variant;
}
return cib->cmds->variant_op(
cib, CRM_OP_QUIT, NULL, NULL, NULL, NULL, call_options);
}
int cib_client_add_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg))
{
GList *list_item = NULL;
cib_notify_client_t *new_client = NULL;
crm_debug("Adding callback for %s events (%d)",
event, g_list_length(cib->notify_list));
crm_malloc(new_client, sizeof(cib_notify_client_t));
new_client->event = event;
new_client->callback = callback;
list_item = g_list_find_custom(
- cib->notify_list, new_client, cib_GCompareFunc);
+ cib->notify_list, new_client, ciblib_GCompareFunc);
if(list_item != NULL) {
crm_warn("Callback already present");
} else {
cib->notify_list = g_list_append(
cib->notify_list, new_client);
crm_debug("Callback added (%d)", g_list_length(cib->notify_list));
}
return cib_ok;
}
int cib_client_del_notify_callback(
cib_t *cib, const char *event, void (*callback)(
const char *event, struct ha_msg *msg))
{
GList *list_item = NULL;
cib_notify_client_t *new_client = NULL;
crm_debug("Removing callback for %s events", event);
crm_malloc(new_client, sizeof(cib_notify_client_t));
new_client->event = event;
new_client->callback = callback;
list_item = g_list_find_custom(
- cib->notify_list, new_client, cib_GCompareFunc);
+ cib->notify_list, new_client, ciblib_GCompareFunc);
if(list_item != NULL) {
cib_notify_client_t *list_client = list_item->data;
cib->notify_list =
g_list_remove(cib->notify_list, list_client);
crm_free(list_client);
crm_debug("Removed callback");
} else {
crm_debug("Callback not present");
}
crm_free(new_client);
return cib_ok;
}
-gint cib_GCompareFunc(gconstpointer a, gconstpointer b)
+gint ciblib_GCompareFunc(gconstpointer a, gconstpointer b)
{
const cib_notify_client_t *a_client = a;
const cib_notify_client_t *b_client = b;
if(a_client->callback == b_client->callback
&& safe_str_neq(a_client->event, b_client->event)) {
return 0;
} else if(((int)a_client->callback) < ((int)b_client->callback)) {
return -1;
}
return 1;
}
char *
cib_pluralSection(const char *a_section)
{
char *a_section_parent = NULL;
if (a_section == NULL) {
a_section_parent = crm_strdup("all");
} else if(strcmp(a_section, XML_TAG_CIB) == 0) {
a_section_parent = crm_strdup("all");
} else if(strcmp(a_section, XML_CIB_TAG_NODE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_NODES);
} else if(strcmp(a_section, XML_CIB_TAG_STATE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_STATUS);
} else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcmp(a_section, "rsc_location") == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcmp(a_section, "rsc_dependancy") == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcmp(a_section, "rsc_order") == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS);
} else if(strcmp(a_section, XML_CIB_TAG_RESOURCE) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES);
} else if(strcmp(a_section, XML_CIB_TAG_NVPAIR) == 0) {
a_section_parent = crm_strdup(XML_CIB_TAG_CRMCONFIG);
} else {
crm_err("Unknown section %s", a_section);
a_section_parent = crm_strdup("all");
}
crm_verbose("Plural of %s is %s", crm_str(a_section), a_section_parent);
return a_section_parent;
}
const char *
cib_error2string(enum cib_errors return_code)
{
const char *error_msg = NULL;
switch(return_code) {
case cib_msg_field_add:
error_msg = "failed adding field to cib message";
break;
case cib_operation:
error_msg = "invalid operation";
break;
case cib_create_msg:
error_msg = "couldnt create cib message";
break;
case cib_client_gone:
error_msg = "client left before we could send reply";
break;
case cib_not_connected:
error_msg = "not connected";
break;
case cib_not_authorized:
error_msg = "not authorized";
break;
case cib_send_failed:
error_msg = "send failed";
break;
case cib_reply_failed:
error_msg = "reply failed";
break;
case cib_return_code:
error_msg = "no return code";
break;
case cib_output_ptr:
error_msg = "nowhere to store output";
break;
case cib_output_data:
error_msg = "corrupt output data";
break;
case cib_connection:
error_msg = "connection failed";
break;
case cib_callback_register:
error_msg = "couldnt register callback channel";
break;
case cib_authentication:
error_msg = "";
break;
case cib_registration_msg:
error_msg = "invalid registration msg";
break;
case cib_callback_token:
error_msg = "callback token not found";
break;
case cib_missing:
error_msg = "cib object missing";
break;
case cib_variant:
error_msg = "unknown/corrupt cib variant";
break;
case CIBRES_MISSING_ID:
error_msg = "The id field is missing";
break;
case CIBRES_MISSING_TYPE:
error_msg = "The type field is missing";
break;
case CIBRES_MISSING_FIELD:
error_msg = "A required field is missing";
break;
case CIBRES_OBJTYPE_MISMATCH:
error_msg = "CIBRES_OBJTYPE_MISMATCH";
break;
case cib_EXISTS:
error_msg = "The object already exists";
break;
case cib_NOTEXISTS:
error_msg = "The object does not exist";
break;
case CIBRES_CORRUPT:
error_msg = "The CIB is corrupt";
break;
case cib_NOOBJECT:
error_msg = "The update was empty";
break;
case cib_NOPARENT:
error_msg = "The parent object does not exist";
break;
case cib_NODECOPY:
error_msg = "Failed while copying update";
break;
case CIBRES_OTHER:
error_msg = "CIBRES_OTHER";
break;
case cib_ok:
error_msg = "ok";
break;
case cib_unknown:
error_msg = "Unknown error";
break;
case cib_STALE:
error_msg = "Discarded old update";
break;
case cib_ACTIVATION:
error_msg = "Activation Failed";
break;
case cib_NOSECTION:
error_msg = "Required section was missing";
break;
case cib_NOTSUPPORTED:
error_msg = "Supplied information is not supported";
break;
case cib_not_master:
error_msg = "Local service is not the master instance";
break;
case cib_client_corrupt:
error_msg = "Service client not valid";
break;
+ case cib_master_timeout:
+ error_msg = "No master service is currently active";
+ break;
}
if(error_msg == NULL) {
crm_err("Unknown CIB Error Code: %d", return_code);
error_msg = "<unknown error>";
}
return error_msg;
}
const char *
cib_op2string(enum cib_op operation)
{
const char *operation_msg = NULL;
switch(operation) {
case 0:
operation_msg = "none";
break;
case 1:
operation_msg = "add";
break;
case 2:
operation_msg = "modify";
break;
case 3:
operation_msg = "delete";
break;
case CIB_OP_MAX:
operation_msg = "invalid operation";
break;
}
if(operation_msg == NULL) {
crm_err("Unknown CIB operation %d", operation);
operation_msg = "<unknown operation>";
}
return operation_msg;
}
int
cib_section2enum(const char *a_section)
{
if(a_section == NULL || strcmp(a_section, "all") == 0) {
return cib_section_all;
} else if(strcmp(a_section, XML_CIB_TAG_NODES) == 0) {
return cib_section_nodes;
} else if(strcmp(a_section, XML_CIB_TAG_STATUS) == 0) {
return cib_section_status;
} else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINTS) == 0) {
return cib_section_constraints;
} else if(strcmp(a_section, XML_CIB_TAG_RESOURCES) == 0) {
return cib_section_resources;
} else if(strcmp(a_section, XML_CIB_TAG_CRMCONFIG) == 0) {
return cib_section_crmconfig;
}
crm_err("Unknown CIB section: %s", a_section);
return cib_section_none;
}
int
cib_compare_generation(xmlNodePtr left, xmlNodePtr right)
{
int int_gen_l = -1;
int int_gen_r = -1;
const char *gen_l = xmlGetProp(left, XML_ATTR_GENERATION);
const char *gen_r = xmlGetProp(right, XML_ATTR_GENERATION);
if(gen_l != NULL) int_gen_l = atoi(gen_l);
if(gen_r != NULL) int_gen_r = atoi(gen_r);
crm_xml_trace(left, "left");
crm_xml_trace(left, "right");
if(int_gen_l < int_gen_r) {
crm_trace("lt");
return -1;
} else if(int_gen_l > int_gen_r) {
crm_trace("gt");
return 1;
}
crm_trace("eq");
return 0;
}
xmlNodePtr
get_cib_copy(cib_t *cib)
{
xmlNodePtr xml_cib;
int options = cib_scope_local|cib_sync_call;
if(cib->cmds->query(cib, NULL, &xml_cib, options) != cib_ok) {
crm_err("Couldnt retrieve the CIB");
return NULL;
}
return xml_cib->children;
}
xmlNodePtr
cib_get_generation(cib_t *cib)
{
xmlNodePtr the_cib = get_cib_copy(cib);
xmlNodePtr generation = create_xml_node(NULL, "generation_tuple");
copy_in_properties(generation, the_cib);
free_xml(the_cib);
return generation;
}
/*
* The caller should never free the return value
*/
xmlNodePtr
get_object_root(const char *object_type, xmlNodePtr the_root)
{
const char *node_stack[2];
xmlNodePtr tmp_node = NULL;
if(the_root == NULL) {
crm_err("CIB root object was NULL");
return NULL;
} else if(object_type == NULL) {
crm_debug("Returning the whole CIB");
return the_root;
}
node_stack[0] = XML_CIB_TAG_CONFIGURATION;
node_stack[1] = object_type;
if(object_type == NULL
|| strlen(object_type) == 0
|| safe_str_eq("all", object_type)) {
return the_root;
/* get the whole cib */
} else if(strcmp(object_type, XML_CIB_TAG_STATUS) == 0) {
/* these live in a different place */
tmp_node = find_xml_node(the_root, XML_CIB_TAG_STATUS);
node_stack[0] = XML_CIB_TAG_STATUS;
node_stack[1] = NULL;
/* } else if(strcmp(object_type, XML_CIB_TAG_CRMCONFIG) == 0) { */
/* /\* these live in a different place too *\/ */
/* tmp_node = find_xml_node(the_root, XML_CIB_TAG_CRMCONFIG); */
/* node_stack[0] = XML_CIB_TAG_CRMCONFIG; */
/* node_stack[1] = NULL; */
} else {
tmp_node = find_xml_node_nested(the_root, node_stack, 2);
}
if (tmp_node == NULL) {
crm_err("[cib] Section %s [%s [%s]] not present",
the_root->name,
node_stack[0],
node_stack[1]?node_stack[1]:"");
}
return tmp_node;
}
xmlNodePtr
create_cib_fragment_adv(
xmlNodePtr update, const char *section, const char *source)
{
gboolean whole_cib = FALSE;
xmlNodePtr fragment = create_xml_node(NULL, XML_TAG_FRAGMENT);
xmlNodePtr cib = NULL;
xmlNodePtr object_root = NULL;
char *auto_section = cib_pluralSection(update?update->name:NULL);
if(update == NULL) {
crm_err("No update to create a fragment for");
crm_free(auto_section);
return NULL;
} else if(section == NULL) {
section = auto_section;
} else if(strcmp(auto_section, section) != 0) {
crm_err("Values for update (tag=%s) and section (%s)"
" were not consistent", update->name, section);
crm_free(auto_section);
return NULL;
}
if(strcmp(section, "all")==0 && strcmp(update->name, XML_TAG_CIB)==0) {
whole_cib = TRUE;
}
set_xml_property_copy(fragment, XML_ATTR_SECTION, section);
if(whole_cib == FALSE) {
cib = createEmptyCib();
object_root = get_object_root(section, cib);
xmlAddChildList(object_root, xmlCopyNodeList(update));
} else {
cib = xmlCopyNodeList(update);
}
xmlAddChild(fragment, cib);
set_xml_property_copy(cib, "debug_source", source);
crm_free(auto_section);
crm_debug("Verifying created fragment");
if(verifyCibXml(cib) == FALSE) {
crm_err("Fragment creation failed");
crm_err("[src] %s", dump_xml_formatted(update));
crm_err("[created] %s", dump_xml_formatted(fragment));
free_xml(fragment);
fragment = NULL;
}
return fragment;
}
/*
* It is the callers responsibility to free both the new CIB (output)
* and the new CIB (input)
*/
xmlNodePtr
createEmptyCib(void)
{
xmlNodePtr cib_root = NULL, config = NULL, status = NULL;
cib_root = create_xml_node(NULL, XML_TAG_CIB);
config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
status = create_xml_node(cib_root, XML_CIB_TAG_STATUS);
set_node_tstamp(cib_root);
set_node_tstamp(config);
set_node_tstamp(status);
set_xml_property_copy(cib_root, "version", "1");
set_xml_property_copy(cib_root, "generated", XML_BOOLEAN_TRUE);
create_xml_node(config, XML_CIB_TAG_CRMCONFIG);
create_xml_node(config, XML_CIB_TAG_NODES);
create_xml_node(config, XML_CIB_TAG_RESOURCES);
create_xml_node(config, XML_CIB_TAG_CONSTRAINTS);
if (verifyCibXml(cib_root)) {
return cib_root;
}
crm_crit("The generated CIB did not pass integrity testing!!"
" All hope is lost.");
return NULL;
}
gboolean
verifyCibXml(xmlNodePtr cib)
{
gboolean is_valid = TRUE;
xmlNodePtr tmp_node = NULL;
if (cib == NULL) {
crm_warn("XML Buffer was empty.");
return FALSE;
}
tmp_node = get_object_root(XML_CIB_TAG_NODES, cib);
if (tmp_node == NULL) is_valid = FALSE;
tmp_node = get_object_root(XML_CIB_TAG_RESOURCES, cib);
if (tmp_node == NULL) is_valid = FALSE;
tmp_node = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
if (tmp_node == NULL) is_valid = FALSE;
tmp_node = get_object_root(XML_CIB_TAG_STATUS, cib);
if (tmp_node == NULL) is_valid = FALSE;
tmp_node = get_object_root(XML_CIB_TAG_CRMCONFIG, cib);
if (tmp_node == NULL) is_valid = FALSE;
/* more integrity tests */
return is_valid;
}
gboolean verify_cib_cmds(cib_t *cib)
{
gboolean valid = TRUE;
if(cib->cmds->variant_op == NULL) {
crm_err("Operation variant_op not set");
valid = FALSE;
}
if(cib->cmds->signon == NULL) {
crm_err("Operation signon not set");
valid = FALSE;
}
if(cib->cmds->signoff == NULL) {
crm_err("Operation signoff not set");
valid = FALSE;
}
if(cib->cmds->free == NULL) {
crm_err("Operation free not set");
valid = FALSE;
}
if(cib->cmds->set_op_callback == NULL) {
crm_err("Operation set_op_callback not set");
valid = FALSE;
}
if(cib->cmds->add_notify_callback == NULL) {
crm_err("Operation add_notify_callback not set");
valid = FALSE;
}
if(cib->cmds->del_notify_callback == NULL) {
crm_err("Operation del_notify_callback not set");
valid = FALSE;
}
if(cib->cmds->set_connection_dnotify == NULL) {
crm_err("Operation set_connection_dnotify not set");
valid = FALSE;
}
if(cib->cmds->channel == NULL) {
crm_err("Operation channel not set");
valid = FALSE;
}
if(cib->cmds->inputfd == NULL) {
crm_err("Operation inputfd not set");
valid = FALSE;
}
if(cib->cmds->noop == NULL) {
crm_err("Operation noop not set");
valid = FALSE;
}
if(cib->cmds->ping == NULL) {
crm_err("Operation ping not set");
valid = FALSE;
}
if(cib->cmds->query == NULL) {
crm_err("Operation query not set");
valid = FALSE;
}
if(cib->cmds->query_from == NULL) {
crm_err("Operation query_from not set");
valid = FALSE;
}
if(cib->cmds->is_master == NULL) {
crm_err("Operation is_master not set");
valid = FALSE;
}
if(cib->cmds->set_master == NULL) {
crm_err("Operation set_master not set");
valid = FALSE;
}
if(cib->cmds->set_slave == NULL) {
crm_err("Operation set_slave not set");
valid = FALSE;
}
if(cib->cmds->set_slave_all == NULL) {
crm_err("Operation set_slave_all not set");
valid = FALSE;
}
if(cib->cmds->sync == NULL) {
crm_err("Operation sync not set");
valid = FALSE;
} if(cib->cmds->sync_from == NULL) {
crm_err("Operation sync_from not set");
valid = FALSE;
}
if(cib->cmds->bump_epoch == NULL) {
crm_err("Operation bump_epoch not set");
valid = FALSE;
}
if(cib->cmds->create == NULL) {
crm_err("Operation create not set");
valid = FALSE;
}
if(cib->cmds->modify == NULL) {
crm_err("Operation modify not set");
valid = FALSE;
}
if(cib->cmds->replace == NULL) {
crm_err("Operation replace not set");
valid = FALSE;
}
if(cib->cmds->delete == NULL) {
crm_err("Operation delete not set");
valid = FALSE;
}
if(cib->cmds->erase == NULL) {
crm_err("Operation erase not set");
valid = FALSE;
}
if(cib->cmds->quit == NULL) {
crm_err("Operation quit not set");
valid = FALSE;
}
if(cib->cmds->msgready == NULL) {
crm_err("Operation msgready not set");
valid = FALSE;
}
if(cib->cmds->rcvmsg == NULL) {
crm_err("Operation rcvmsg not set");
valid = FALSE;
}
if(cib->cmds->dispatch == NULL) {
crm_err("Operation dispatch not set");
valid = FALSE;
}
return valid;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 10, 2:25 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009733
Default Alt Text
(152 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment