diff --git a/crm/admin/adminmain.c b/crm/admin/adminmain.c index e6ca2348dc..34b8c152d8 100644 --- a/crm/admin/adminmain.c +++ b/crm/admin/adminmain.c @@ -1,637 +1,636 @@ -/* $Id: adminmain.c,v 1.22 2004/04/29 15:33:02 andrew Exp $ */ +/* $Id: adminmain.c,v 1.23 2004/05/10 21:52:56 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OPTARGS "V?i:o:D:C:S:HA:U:M:I:EWRFt:m:a:d:w:c:r:p:s:" #include #include GMainLoop *mainloop = NULL; const char *crm_system_name = "crmadmin"; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); ll_cluster_t *do_init(void); int do_work(ll_cluster_t * hb_cluster); gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); xmlNodePtr handleCibMod(void); gboolean DO_DAEMON = FALSE; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean DO_HEALTH = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_RECALC_TREE = FALSE; gboolean DO_FLUSH_RECALC = FALSE; const char *cib_action = NULL; xmlNodePtr msg_options = NULL; typedef struct str_list_s { int num_items; char *value; struct str_list_s *next; } str_list_t; const char *verbose = "false"; char *id = NULL; char *this_msg_reference = NULL; char *obj_type = NULL; char *clear = NULL; char *status = NULL; char *disconnect = NULL; char *unload_ha = NULL; char *migrate_from = NULL; char *migrate_res = NULL; char *subtype = NULL; char *reset = NULL; int operation_status = 0; const char *sys_to = NULL;; int main(int argc, char **argv) { int option_index = 0; int argerr = 0; int flag; ll_cluster_t *hb_cluster = NULL; static struct option long_options[] = { // Top-level Options {"daemon", 0, 0, 0}, {CRM_OPERATION_ERASE, 0, 0, 0}, {CRM_OPERATION_QUERY, 0, 0, 0}, {CRM_OPERATION_CREATE, 0, 0, 0}, {CRM_OPERATION_REPLACE, 0, 0, 0}, {CRM_OPERATION_STORE, 0, 0, 0}, {CRM_OPERATION_UPDATE, 0, 0, 0}, {CRM_OPERATION_DELETE, 0, 0, 0}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"reference", 1, 0, 0}, // common options {"id", 1, 0, 'i'}, {"obj_type", 1, 0, 'o'}, // daemon options {"reset", 1, 0, 'C'}, {"status", 1, 0, 'S'}, {"health", 0, 0, 'H'}, {"disconnect", 1, 0, 'A'}, {"unload_ha", 1, 0, 'U'}, {"migrate_from", 1, 0, 'M'}, {"migrate_res", 1, 0, 'I'}, {"elect_dc", 0, 0, 'E'}, {"whois_dc", 0, 0, 'W'}, {"recalc_tree", 0, 0, 'R'}, {"flush_recalc_tree", 0, 0, 'F'}, {0, 0, 0, 0} }; cl_log_set_entity(crm_system_name); cl_log_enable_stderr(TRUE); 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 (strcmp("daemon", long_options[option_index].name) == 0) DO_DAEMON = TRUE; else if (strcmp(CRM_OPERATION_ERASE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_CREATE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_UPDATE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_DELETE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_REPLACE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_STORE, long_options[option_index].name) == 0 || strcmp(CRM_OPERATION_QUERY, long_options[option_index].name) == 0){ cib_action = cl_strdup(long_options[option_index].name); } else if (strcmp("reference", long_options[option_index].name) == 0) { this_msg_reference = cl_strdup(optarg); } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'V': BE_VERBOSE = TRUE; verbose = "true"; break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'i': CRM_DEBUG("Option %c => %s", flag, optarg); id = cl_strdup(optarg); break; case 'o': CRM_DEBUG("Option %c => %s", flag, optarg); obj_type = cl_strdup(optarg); break; case 'C': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'S': DO_HEALTH = TRUE; status = cl_strdup(optarg); break; case 'H': DO_HEALTH = TRUE; break; case 'A': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'U': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'M': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'I': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'E': DO_ELECT_DC = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'W': DO_WHOIS_DC = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'R': DO_RECALC_TREE = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'F': DO_FLUSH_RECALC = TRUE; printf("Option %c is not yet supported\n", flag); ++argerr; break; default: printf("?? getopt returned character code 0%o ??\n", 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 (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } hb_cluster = do_init(); if (hb_cluster != NULL) { if (do_work(hb_cluster) > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); cl_log(LOG_INFO, "%s waiting for reply from the local CRM", crm_system_name); g_main_run(mainloop); return_to_orig_privs(); } else { cl_log(LOG_ERR, "No message to send"); operation_status = -1; } } else { cl_log(LOG_ERR, "Init failed, could not perform requested operations"); operation_status = -2; } cl_log(LOG_DEBUG, "%s exiting normally", crm_system_name); return operation_status; } xmlNodePtr handleCibMod(void) { const char *attr_name = NULL; const char *attr_value = NULL; xmlNodePtr fragment = NULL; xmlNodePtr cib_object = file2xml(stdin); if(cib_object == NULL) { return NULL; } if(strcmp(cib_object->name, obj_type) != 0) { cl_log(LOG_ERR, "Mismatching xml." " Expected root element <%s>, got <%s>", obj_type, cib_object->name); return NULL; } attr_name = XML_ATTR_ID; attr_value = xmlGetProp(cib_object, attr_name); if(attr_name == NULL || strlen(attr_name) == 0) { cl_log(LOG_ERR, "No value for %s specified.", attr_name); return NULL; } CRM_DEBUG("Object creation complete"); // create the cib request fragment = create_cib_fragment(cib_object, NULL); set_xml_property_copy(msg_options, XML_ATTR_OP, cib_action); return fragment; } int do_work(ll_cluster_t * hb_cluster) { /* construct the request */ xmlNodePtr msg_data = NULL; const char *dest_node = NULL; gboolean all_is_good = TRUE; char *obj_type_parent = NULL; const char *ping_type = NULL; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); set_xml_property_copy(msg_options, XML_ATTR_VERBOSE, verbose); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_DAEMON == TRUE && cib_action != NULL) { if(strcmp(CRM_OPERATION_QUERY, cib_action) == 0) { cl_log(LOG_DEBUG, "Querying the CIB"); obj_type_parent = pluralSection(obj_type); CRM_DEBUG("Querying the CIB for section: %s", obj_type_parent); set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OPERATION_QUERY); set_xml_property_copy(msg_options, XML_ATTR_FILTER_ID, obj_type_parent); dest_node = status; CRM_DEBUG("CIB query creation %s", msg_data == NULL ? "failed." : "passed."); sys_to = CRM_SYSTEM_DCIB; } else if (strcmp(CRM_OPERATION_ERASE, cib_action) == 0) { set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OPERATION_ERASE); dest_node = status; CRM_DEBUG("CIB Erase op in progress"); sys_to = CRM_SYSTEM_DCIB; } else { cl_log(LOG_ERR, "Unknown daemon options"); all_is_good = FALSE; } } else if(cib_action != NULL) { msg_data = handleCibMod(); sys_to = CRM_SYSTEM_DCIB; if(msg_data == NULL) all_is_good = FALSE; } else if (DO_DAEMON == TRUE && DO_HEALTH == TRUE) { CRM_DEBUG("Querying the system"); sys_to = CRM_SYSTEM_DC; if (status != NULL) { sys_to = CRM_SYSTEM_CRMD; ping_type = CRM_OPERATION_PING; if (BE_VERBOSE) { ping_type = "ping_deep"; if (status != NULL) expected_responses = 2; // 5; // CRM/DC, LRMD, CIB, PENGINE, TENGINE else expected_responses = -1;// wait until timeout instead } set_xml_property_copy(msg_options, XML_ATTR_OP, ping_type); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = status; } else { cl_log(LOG_INFO, "Cluster-wide health not available yet"); all_is_good = FALSE; } } else { cl_log(LOG_ERR, "Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { cl_log(LOG_ERR, "Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { cl_log(LOG_ERR, "The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) sys_to = CRM_SYSTEM_CRMD; else sys_to = CRM_SYSTEM_DC; } send_ipc_request(crmd_channel, msg_options, msg_data, dest_node, sys_to, crm_system_name, admin_uuid, this_msg_reference); return 1; } ll_cluster_t * do_init(void) { int facility; ll_cluster_t *hb_cluster = NULL; /* docs say only do this once, but in their code they do it every time! */ xmlInitParser (); /* change the logging facility to the one used by heartbeat daemon */ hb_cluster = ll_cluster_new("heartbeat"); cl_log(LOG_INFO, "Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } admin_uuid = cl_malloc(sizeof(char) * 11); snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; crmd_channel = - init_client_ipc_comms(CRM_SYSTEM_CRMD, - admin_msg_callback, - NULL); + init_client_ipc_comms(CRM_SYSTEM_CRMD,admin_msg_callback,NULL); + if(crmd_channel != NULL) { send_hello_message(crmd_channel, admin_uuid, crm_system_name, "0", "1"); return hb_cluster; } return NULL; } 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); } const char *ournode; gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; char *filename; int filename_len = 0; const char *result = NULL; xmlNodePtr options = NULL; xmlNodePtr xml_root_node = NULL; char *buffer = NULL; FNIN(); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); FNRET(!hack_return_good); } if (msg == NULL) { CRM_DEBUG("No message this time"); continue; } lpc++; buffer =(char *) msg->msg_body; CRM_DEBUG("Got xml [text=%s]", buffer); xml_root_node = find_xml_in_ipcmessage(msg, TRUE); if (xml_root_node == NULL) { cl_log(LOG_INFO, "XML in IPC message was not valid... " "discarding."); continue; } else if (validate_crm_message(xml_root_node, crm_system_name, admin_uuid, "response") == FALSE) { cl_log(LOG_INFO, "Message was not a CRM response. Discarding."); continue; } options = find_xml_node(xml_root_node, XML_TAG_OPTIONS); result = xmlGetProp(options, XML_ATTR_RESULT); if(result == NULL || strcmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } received_responses++; // do stuff if (this_msg_reference != NULL) { // in testing mode... /* 31 = "test-_.xml" + an_int_as_string + '\0' */ filename_len = 31 + strlen(this_msg_reference); filename = cl_malloc(sizeof(char) * filename_len); sprintf(filename, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (xmlSaveFormatFile(filename, xml_root_node->doc, 1) < 0) { cl_log(LOG_CRIT, "Could not save response %s_%s_%d.xml", this_msg_reference, result, received_responses); } } } if (server->ch_status == IPC_DISCONNECT) { cl_log(LOG_INFO, "admin_msg_callback: received HUP"); FNRET(!hack_return_good); } if (received_responses >= expected_responses) { cl_log(LOG_INFO, "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); g_main_quit(mainloop); return !hack_return_good; } FNRET(hack_return_good); } diff --git a/crm/cib/cibmain.c b/crm/cib/cibmain.c index 05008a8345..e02d891509 100644 --- a/crm/cib/cibmain.c +++ b/crm/cib/cibmain.c @@ -1,356 +1,354 @@ -/* $Id: cibmain.c,v 1.17 2004/04/29 15:33:03 andrew Exp $ */ +/* $Id: cibmain.c,v 1.18 2004/05/10 21:52:56 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* #define REALTIME_SUPPORT 0 */ #define PID_FILE WORKING_DIR"/cib.pid" #define DAEMON_LOG LOG_DIR"/cib.log" #define DAEMON_DEBUG LOG_DIR"/cib.debug" GMainLoop* mainloop = NULL; const char* crm_system_name = CRM_SYSTEM_CIB; void usage(const char* cmd, int exit_status); int init_start(void); void cib_shutdown(int nsig); gboolean cib_msg_callback(IPC_Channel *client, gpointer user_data); #define OPTARGS "skrh" 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; cl_log_set_entity(crm_system_name); cl_log_enable_stderr(TRUE); cl_log_set_facility(LOG_USER); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 's': /* Status */ req_status = TRUE; break; case 'k': /* Stop (kill) */ req_stop = 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; } } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } // read local config file if (req_status){ FNRET(init_status(PID_FILE, crm_system_name)); } if (req_stop){ FNRET(init_stop(PID_FILE)); } if (req_restart) { init_stop(PID_FILE); } FNRET(init_start()); } int init_start(void) { long pid; ll_cluster_t *hb_fd; int facility; IPC_Channel *crm_ch = NULL; #ifdef REALTIME_SUPPORT static int crm_realtime = 1; #endif if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { cl_log(LOG_CRIT, "already running: [pid %ld].", pid); exit(LSB_EXIT_OK); } cl_log(LOG_INFO, "Register PID"); register_pid(PID_FILE, FALSE, cib_shutdown); xmlInitParser(); // only do this once cl_log_set_logfile(DAEMON_LOG); // if (crm_debug()) { cl_log_set_debugfile(DAEMON_DEBUG); // } hb_fd = ll_cluster_new("heartbeat"); cl_log(LOG_INFO, "Switching to Heartbeat logger"); if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { cl_log_set_facility(facility); } if(startCib(CIB_FILENAME) == FALSE){ cl_log(LOG_CRIT, "Cannot start CIB... terminating"); exit(1); } - crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, - cib_msg_callback, - NULL); + crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, cib_msg_callback,NULL); if(crm_ch != NULL) { send_hello_message(crm_ch, "-", CRM_SYSTEM_CIB, "0", "1"); /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); cl_log(LOG_INFO, "Starting %s", crm_system_name); /* G_main_add_IPC_Channel(G_PRIORITY_LOW, */ /* crm_ch, */ /* FALSE, */ /* cib_msg_callback, */ /* crm_ch, */ /* default_ipc_input_destroy); */ #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 g_main_run(mainloop); return_to_orig_privs(); } else { cl_log(LOG_ERR, "Connection to CRM not valid, exiting."); } if (unlink(PID_FILE) == 0) { cl_log(LOG_INFO, "[%s] stopped", crm_system_name); } FNRET(0); } gboolean cib_msg_callback(IPC_Channel *sender, void *user_data) { int lpc = 0; char *buffer = NULL; xmlDocPtr doc = NULL; IPC_Message *msg = NULL; gboolean all_is_well = TRUE; xmlNodePtr answer = NULL, root_xml_node = NULL; const char *sys_to; const char *type; FNIN(); while(sender->ops->is_message_pending(sender)) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if (sender->ops->recv(sender, &msg) != IPC_OK) { perror("Receive failure:"); FNRET(!all_is_well); } if (msg == NULL) { cl_log(LOG_ERR, "No message this time"); continue; } lpc++; /* the docs say only do this once, but in their code * they do it every time! */ // xmlInitParser(); buffer = (char*)msg->msg_body; cl_log(LOG_DEBUG, "Message %d [text=%s]", lpc, buffer); doc = xmlParseMemory(cl_strdup(buffer), strlen(buffer)); if(doc == NULL) { cl_log(LOG_INFO, "XML Buffer was not valid...\n Buffer: (%s)", buffer); } root_xml_node = xmlDocGetRootElement(doc); sys_to= xmlGetProp(root_xml_node, XML_ATTR_SYSTO); type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE); if (root_xml_node == NULL) { cl_log(LOG_ERR, "Root node was NULL!!"); } else if(sys_to == NULL) { cl_log(LOG_ERR, "Value of %s was NULL!!", XML_ATTR_SYSTO); } else if(type == NULL) { cl_log(LOG_ERR, "Value of %s was NULL!!", XML_ATTR_MSGTYPE); } else if(strcmp(type, XML_ATTR_REQUEST) != 0) { cl_log(LOG_INFO, "Message was a response not a request." " Discarding"); } else if (strcmp(sys_to, CRM_SYSTEM_CIB) == 0 || strcmp(sys_to, CRM_SYSTEM_DCIB) == 0) { answer = process_cib_message(root_xml_node, TRUE); if (send_xmlipc_message(sender, answer)==FALSE) cl_log(LOG_WARNING, "Cib answer could not be sent"); } else { cl_log(LOG_WARNING, "Received a message destined for %s by mistake", sys_to); } if(answer != NULL) free_xml(answer); msg->msg_done(msg); msg = NULL; } // clean up after a break if(msg != NULL) msg->msg_done(msg); if(root_xml_node != NULL) free_xml(root_xml_node); CRM_DEBUG("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { cl_log(LOG_ERR, "The server has left us: Shutting down...NOW"); exit(1); // shutdown properly later FNRET(!all_is_well); } FNRET(all_is_well); } 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); } 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); } } diff --git a/crm/common/crmutils.c b/crm/common/crmutils.c index 97c151de50..1bdc5f8d97 100644 --- a/crm/common/crmutils.c +++ b/crm/common/crmutils.c @@ -1,397 +1,393 @@ -/* $Id: crmutils.c,v 1.13 2004/05/06 12:05:24 andrew Exp $ */ +/* $Id: crmutils.c,v 1.14 2004/05/10 21:52:57 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int wdt_interval_ms = 10000; gboolean tickle_apphb_template(gpointer data) { char app_instance[APPNAME_LEN]; int rc = 0; sprintf(app_instance, "%s_%ld", "our_system_name", (long)getpid()); rc = apphb_hb(); if (rc < 0) { cl_perror("%s apphb_hb failure", app_instance); exit(3); } return TRUE; } void register_pid(const char *pid_file, gboolean do_fork, void (*shutdown)(int nsig)) { int j; long pid; FILE * lockfd; if (do_fork) { pid = fork(); if (pid < 0) { cl_log(LOG_CRIT, "cannot start daemon"); exit(LSB_EXIT_GENERIC); }else if (pid > 0) { exit(LSB_EXIT_OK); } } lockfd = fopen(pid_file, "w"); if (lockfd == NULL) { cl_log(LOG_CRIT, "cannot create pid file: %s", pid_file); exit(LSB_EXIT_GENERIC); }else{ pid = getpid(); fprintf(lockfd, "%ld\n", pid); fclose(lockfd); } umask(022); for (j=0; j < 3; ++j) { close(j); (void)open("/dev/null", j == 0 ? O_RDONLY : O_RDONLY); } // CL_IGNORE_SIG(SIGINT); // CL_IGNORE_SIG(SIGHUP); CL_SIGNAL(SIGTERM, shutdown); } long get_running_pid(const char *pid_file, gboolean* anypidfile) { long pid; FILE * lockfd; lockfd = fopen(pid_file, "r"); if (anypidfile) { *anypidfile = (lockfd != NULL); } if (lockfd != NULL && fscanf(lockfd, "%ld", &pid) == 1 && pid > 0) { if (CL_PID_EXISTS((pid_t)pid)) { fclose(lockfd); return(pid); } } if (lockfd != NULL) { fclose(lockfd); } return(-1L); } int init_stop(const char *pid_file) { long pid; int rc = LSB_EXIT_OK; FNIN(); if (pid_file == NULL) { cl_log(LOG_ERR, "No pid file specified to kill process"); return LSB_EXIT_GENERIC; } pid = get_running_pid(pid_file, NULL); if (pid > 0) { if (CL_KILL((pid_t)pid, SIGTERM) < 0) { rc = (errno == EPERM ? LSB_EXIT_EPERM : LSB_EXIT_GENERIC); fprintf(stderr, "Cannot kill pid %ld\n", pid); }else{ cl_log(LOG_INFO, "Signal sent to pid=%ld," " waiting for process to exit", pid); while (CL_PID_EXISTS(pid)) { sleep(1); } } } FNRET(rc); } int init_status(const char *pid_file, const char *client_name) { gboolean anypidfile; long pid = get_running_pid(pid_file, &anypidfile); if (pid > 0) { fprintf(stderr, "%s is running [pid: %ld]\n" , client_name, pid); return LSB_STATUS_OK; } if (anypidfile) { fprintf(stderr, "%s is stopped [pidfile exists]\n" , client_name); return LSB_STATUS_VAR_PID; } fprintf(stderr, "%s is stopped.\n", client_name); return LSB_STATUS_STOPPED; } gboolean register_with_ha(ll_cluster_t *hb_cluster, const char *client_name, gboolean (*dispatch_method)(int fd, gpointer user_data), void (*message_callback)(const struct ha_msg* msg, void* private_data), GDestroyNotify cleanup_method) { const char* ournode = NULL; cl_log(LOG_INFO, "Signing in with Heartbeat"); if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) { cl_log(LOG_ERR, "Cannot sign on with heartbeat"); cl_log(LOG_ERR, "REASON: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } cl_log(LOG_DEBUG, "Finding our node name"); if ((ournode = hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) { cl_log(LOG_ERR, "get_mynodeid() failed"); return FALSE; } - cl_log(LOG_INFO, "Hostname: %s", ournode); + cl_log(LOG_INFO, "hostname: %s", ournode); -/* cl_log(LOG_INFO, "Be informed of link status changes"); */ -/* if (hb_cluster->llc_ops->set_ifstatus_callback(hb_cluster, LinkStatus, NULL) */ -/* !=HA_OK){ */ -/* cl_log(LOG_ERR, "Cannot set if status callback"); */ -/* cl_log(LOG_ERR, "REASON: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); */ -/* return FALSE; */ -/* } */ - cl_log(LOG_DEBUG, "Be informed of CRM messages"); if (hb_cluster->llc_ops->set_msg_callback(hb_cluster, "CRM", message_callback, hb_cluster) !=HA_OK){ cl_log(LOG_ERR, "Cannot set CRM message callback"); cl_log(LOG_ERR, "REASON: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } G_main_add_fd(G_PRIORITY_HIGH, hb_cluster->llc_ops->inputfd(hb_cluster), FALSE, dispatch_method, hb_cluster, // usrdata cleanup_method); /* it seems we need to poke the message receiving stuff in order for it to * start seeing messages. Its like it gets blocked or something. */ dispatch_method(0, hb_cluster); return TRUE; } void register_with_apphb(const char *client_name, gboolean(*tickle_fn)(gpointer data)) { char app_instance[APPNAME_LEN]; int hb_intvl_ms = wdt_interval_ms * 2; int rc = 0; // Register with apphb cl_log(LOG_INFO, "Signing in with AppHb"); sprintf(app_instance, "%s_%ld", client_name, (long)getpid()); cl_log(LOG_INFO, "Client %s registering with apphb", app_instance); rc = apphb_register(client_name, app_instance); if (rc < 0) { cl_perror("%s registration failure", app_instance); exit(1); } cl_log(LOG_DEBUG, "Client %s registered with apphb", app_instance); cl_log(LOG_INFO, "Client %s setting %d ms apphb heartbeat interval" , app_instance, hb_intvl_ms); rc = apphb_setinterval(hb_intvl_ms); if (rc < 0) { cl_perror("%s setinterval failure", app_instance); exit(2); } // regularly tell apphb that we are alive cl_log(LOG_INFO, "Setting up AppHb Heartbeat"); Gmain_timeout_add(wdt_interval_ms, tickle_fn, NULL); } char * crm_itoa(int an_int) { int len = 32; char *buffer = cl_malloc(sizeof(char)*(len+1)); snprintf(buffer, len, "%d", an_int); return buffer; } gboolean subsystem_input_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; char *buffer = NULL; xmlDocPtr doc = NULL; IPC_Message *msg = NULL; gboolean all_is_well = TRUE; xmlNodePtr answer = NULL, root_xml_node = NULL; const char *sys_to; const char *type; FNIN(); while(sender->ops->is_message_pending(sender)) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if (sender->ops->recv(sender, &msg) != IPC_OK) { perror("Receive failure:"); FNRET(!all_is_well); } if (msg == NULL) { cl_log(LOG_ERR, "No message this time"); continue; } lpc++; /* the docs say only do this once, but in their code * they do it every time! */ // xmlInitParser(); buffer = (char*)msg->msg_body; cl_log(LOG_DEBUG, "Message %d [text=%s]", lpc, buffer); doc = xmlParseMemory(cl_strdup(buffer), strlen(buffer)); if(doc == NULL) { cl_log(LOG_INFO, "XML Buffer was not valid...\n Buffer: (%s)", buffer); } root_xml_node = xmlDocGetRootElement(doc); sys_to= xmlGetProp(root_xml_node, XML_ATTR_SYSTO); type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE); if (root_xml_node == NULL) { cl_log(LOG_ERR, "Root node was NULL!!"); + } else if (safe_str_eq(root_xml_node->name, "hello")) { + cl_log(LOG_WARNING, "HACK: Ignore hello messages"); + } else if(sys_to == NULL) { cl_log(LOG_ERR, "Value of %s was NULL!!", XML_ATTR_SYSTO); } else if(type == NULL) { cl_log(LOG_ERR, "Value of %s was NULL!!", XML_ATTR_MSGTYPE); } else if(strcmp(type, XML_ATTR_REQUEST) != 0) { cl_log(LOG_INFO, "Message was a response not a request." " Discarding"); - } else if (strcmp(sys_to, "foo"/*crm_system_name*/) == 0) { - void (*process_function)(xmlNodePtr msg) = NULL; + } else { + gboolean (*process_function)(xmlNodePtr msg, IPC_Channel *sender) = NULL; process_function = user_data; - process_function(root_xml_node); - - } else { - cl_log(LOG_WARNING, - "Received a message destined for %s by mistake", - sys_to); + if(process_function(root_xml_node, sender) == FALSE) { + cl_log(LOG_WARNING, + "Received a message destined for %s" + " by mistake", sys_to); + } + } if(answer != NULL) free_xml(answer); + answer = NULL; msg->msg_done(msg); msg = NULL; } // clean up after a break if(msg != NULL) msg->msg_done(msg); if(root_xml_node != NULL) free_xml(root_xml_node); CRM_DEBUG("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { cl_log(LOG_ERR, "The server has left us: Shutting down...NOW"); exit(1); // shutdown properly later FNRET(!all_is_well); } FNRET(all_is_well); } diff --git a/crm/common/ipcutils.c b/crm/common/ipcutils.c index 75768d3596..1fadee589f 100644 --- a/crm/common/ipcutils.c +++ b/crm/common/ipcutils.c @@ -1,555 +1,553 @@ -/* $Id: ipcutils.c,v 1.24 2004/04/29 15:34:22 andrew Exp $ */ +/* $Id: ipcutils.c,v 1.25 2004/05/10 21:52:57 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include // for getNow() #include /* #include #include */ #include #include #include #include FILE *msg_out_strm = NULL; IPC_Message *create_simple_message(char *text, IPC_Channel *ch); void LinkStatus(const char * node, const char * lnk, const char * status ,void * private) { // put something here } gboolean send_xmlipc_message(IPC_Channel *ipc_client, xmlNodePtr msg) { char *xml_message = NULL; IPC_Message *cib_dump = NULL; gboolean res; FNIN(); xml_message = dump_xml(msg); cib_dump = create_simple_message(xml_message, ipc_client); res = send_ipc_message(ipc_client, cib_dump); cl_free(xml_message); xml_message_debug(msg, "Sent IPC Message"); FNRET(res); } gboolean send_xmlha_message(ll_cluster_t *hb_fd, xmlNodePtr root) { gboolean broadcast = FALSE; gboolean all_is_good = TRUE; int send_result = -1; int xml_len = -1; const char *host_to = NULL; const char *sys_to = NULL; struct ha_msg *msg = NULL; char *xml_text; #ifdef MSG_LOG char *msg_text = NULL; #endif FNIN(); if (root == NULL) { cl_log(LOG_ERR, "Attempt to send NULL Message via HA failed."); all_is_good = FALSE; } host_to = xmlGetProp(root, XML_ATTR_HOSTTO); sys_to = xmlGetProp(root, XML_ATTR_SYSTO); if (sys_to != NULL && strcmp("dc", sys_to) == 0) { cl_log(LOG_INFO, "Resetting the value of %s to null from %s", XML_ATTR_HOSTTO, host_to); // xmlSetProp(root, XML_ATTR_HOSTTO, ""); } if (all_is_good) { msg = ha_msg_new(4); ha_msg_add(msg, F_TYPE, "CRM"); ha_msg_add(msg, F_COMMENT, "A CRM xml message"); xml_text = dump_xml(root); xml_len = strlen(xml_text); if (xml_text == NULL || xml_len <= 0) { cl_log(LOG_ERR, "Failed sending an invalid XML Message via HA"); all_is_good = FALSE; xml_message_debug(root, "Bad message was"); } else { if(ha_msg_add(msg, "xml", xml_text) == HA_FAIL) { cl_log(LOG_ERR, "Could not add xml to HA message"); all_is_good = FALSE; } } } if (all_is_good) { if (sys_to == NULL || strlen(sys_to) == 0) { cl_log(LOG_ERR, "You did not specify a destination sub-system" " for this message."); all_is_good = FALSE; } } /* There are a number of messages may not need to be ordered. * At a later point perhaps we should detect them and send them * as unordered messages. */ if (all_is_good) { if (host_to == NULL || strlen(host_to) == 0 || strcmp("dc", sys_to) == 0) { broadcast = TRUE; send_result = hb_fd->llc_ops->send_ordered_clustermsg(hb_fd, msg); } else { send_result = hb_fd->llc_ops->send_ordered_nodemsg(hb_fd, msg, host_to); } if(send_result != HA_OK) all_is_good = FALSE; } if(!all_is_good) { cl_log(LOG_ERR, "Sending %s HA message (ref=%s, len=%d) to %s@%s %s.", broadcast?"broadcast":"directed", xmlGetProp(root, XML_ATTR_REFERENCE), xml_len, sys_to, host_to==NULL?"":host_to, all_is_good?"succeeded":"failed"); } else { xmlNodePtr opts = find_xml_node(root, XML_TAG_OPTIONS); const char *op = xmlGetProp(opts, XML_ATTR_OP); if(op == NULL || strcmp(op, CRM_OPERATION_HBEAT) != 0) { cl_log(LOG_DEBUG, "Sent %s HA message (ref=%s, len=%d) to %s@%s", broadcast?"broadcast":"directed", xmlGetProp(root, XML_ATTR_REFERENCE), xml_len, sys_to, host_to==NULL?"":host_to); } } #ifdef MSG_LOG msg_text = dump_xml(root); if(msg_out_strm == NULL) { msg_out_strm = fopen("/tmp/outbound.log", "w"); } fprintf(msg_out_strm, "[%d HA (%s:%d)]\t%s\n", all_is_good, xmlGetProp(root, XML_ATTR_REFERENCE), send_result, msg_text); fflush(msg_out_strm); cl_free(msg_text); if(msg != NULL) { ha_msg_del(msg); } #endif FNRET(all_is_good); } gboolean send_ipc_message(IPC_Channel *ipc_client, IPC_Message *msg) { gboolean all_is_good = TRUE; int lpc = 0; FNIN(); if (msg == NULL) { cl_log(LOG_WARNING, "cant send NULL message"); all_is_good = FALSE; } else if (msg->msg_len <= 0) { cl_log(LOG_WARNING, "cant send 0 sized message"); all_is_good = FALSE; } else if (msg->msg_len > MAXDATASIZE) { cl_log(LOG_WARNING, "cant send msg... too big"); all_is_good = FALSE; } /* CRM_DEBUG("Sending message: %s", (char*)msg->msg_body); */ CRM_DEBUG("Message is%s valid to send", all_is_good?"":" not"); if (ipc_client == NULL) { all_is_good = FALSE; } CRM_DEBUG("IPC Client is%s set.", all_is_good?"":" not"); if (all_is_good) { while(lpc++ < MAX_IPC_FAIL && ipc_client->ops->send(ipc_client, msg) == IPC_FAIL) { cl_log(LOG_WARNING, "ipc channel blocked"); cl_shortsleep(); } } if (lpc == MAX_IPC_FAIL) { cl_log(LOG_ERR, "Could not send IPC, message. Channel is dead."); FNRET(!all_is_good); } CRM_DEBUG("Sending of IPC message %s.", all_is_good?"succeeded":"failed"); FNRET(all_is_good); } IPC_Message * create_simple_message(char *text, IPC_Channel *ch) { // char str[256]; IPC_Message *ack_msg = NULL; FNIN(); if (text == NULL) FNRET(NULL); ack_msg = (IPC_Message *)cl_malloc(sizeof(IPC_Message)); ack_msg->msg_private = NULL; ack_msg->msg_done = NULL; ack_msg->msg_body = text; ack_msg->msg_ch = ch; ack_msg->msg_len = strlen(text)+1; FNRET(ack_msg); } gboolean default_ipc_input_dispatch(IPC_Channel *client, gpointer user_data) { xmlNodePtr root; xmlNodePtr options; IPC_Message *msg = NULL; const char *op; FNIN(); msg = get_ipc_message(client); if (msg) { root = find_xml_in_ipcmessage(msg, TRUE); validate_crm_message(root, NULL, NULL, NULL); options = find_xml_node(root, XML_TAG_OPTIONS); op = xmlGetProp(options, XML_ATTR_OP); if(op != NULL && strcmp(op, "quit") == 0) { cl_log(LOG_WARNING, "The CRMd has asked us to exit... complying"); exit(0); } } else if (client->ch_status == IPC_DISCONNECT) { cl_log(LOG_ERR, "The server has left us: Shutting down...NOW"); exit(1); /* Server disconnects should be fatal, * but I will do it a little more gracefully :) */ FNRET(FALSE); /* This conection is hosed */ } FNRET(TRUE); /* TOBEDONE */ } xmlNodePtr find_xml_in_hamessage(const struct ha_msg* msg) { const char *xml; xmlDocPtr doc; xmlNodePtr root; FNIN(); if (msg == NULL) { cl_log(LOG_INFO, "**** ha_crm_msg_callback called on a NULL message"); FNRET(NULL); } #if 0 cl_log(LOG_DEBUG, "[F_TYPE=%s]", ha_msg_value(msg, F_TYPE)); cl_log(LOG_DEBUG, "[F_ORIG=%s]", ha_msg_value(msg, F_ORIG)); cl_log(LOG_DEBUG, "[F_TO=%s]", ha_msg_value(msg, F_TO)); cl_log(LOG_DEBUG, "[F_COMMENT=%s]", ha_msg_value(msg, F_COMMENT)); cl_log(LOG_DEBUG, "[F_XML=%s]", ha_msg_value(msg, "xml")); // cl_log(LOG_DEBUG, "[F_=%s]", ha_msg_value(ha_msg, F_)); #endif if (strcmp("CRM", ha_msg_value(msg, F_TYPE)) != 0) { cl_log(LOG_INFO, "Received a (%s) message by mistake.", ha_msg_value(msg, F_TYPE)); FNRET(NULL); } xml = ha_msg_value(msg, "xml"); if (xml == NULL) { cl_log(LOG_INFO, "No XML attached to this message."); FNRET(NULL); } doc = xmlParseMemory(xml, strlen(xml)); if (doc == NULL) { cl_log(LOG_INFO, "XML Buffer was not valid."); FNRET(NULL); } root = xmlDocGetRootElement(doc); if (root == NULL) { cl_log(LOG_INFO, "Root node was NULL."); FNRET(NULL); } FNRET(root); } xmlNodePtr find_xml_in_ipcmessage(IPC_Message *msg, gboolean do_free) { char *buffer = NULL; xmlDocPtr doc; xmlNodePtr root; FNIN(); if (msg == NULL) { CRM_DEBUG("IPC Message was empty..."); FNRET(NULL); } buffer = (char*)msg->msg_body; doc = xmlParseMemory(buffer, strlen(buffer)); if (do_free) msg->msg_done(msg); if (doc == NULL) { cl_log(LOG_INFO, "IPC Message did not contain an XML buffer..."); FNRET(NULL); } root = xmlDocGetRootElement(doc); if (root == NULL) { cl_log(LOG_INFO, "Root node was NULL."); FNRET(NULL); } FNRET(root); } void default_ipc_input_destroy(gpointer user_data) { FNIN(); FNOUT(); } int init_server_ipc_comms( const char *child, gboolean (*channel_client_connect)(IPC_Channel *newclient, gpointer user_data), void (*channel_input_destroy)(gpointer user_data)) { /* the clients wait channel is the other source of events. * This source delivers the clients connection events. * listen to this source at a relatively lower priority. */ char commpath[SOCKET_LEN]; IPC_WaitConnection *wait_ch; FNIN(); sprintf(commpath, WORKING_DIR "/%s", child); wait_ch = wait_channel_init(commpath); if (wait_ch == NULL) FNRET(1); G_main_add_IPC_WaitConnection(G_PRIORITY_LOW, wait_ch, NULL, FALSE, channel_client_connect, wait_ch, // user data passed to ?? channel_input_destroy); cl_log(LOG_DEBUG, "Listening on: %s", commpath); FNRET(0); } IPC_Channel * init_client_ipc_comms(const char *child, gboolean (*dispatch)(IPC_Channel* source_data ,gpointer user_data), crmd_client_t *client_data) { IPC_Channel *ch; GHashTable * attrs; GCHSource *the_source = NULL; void *callback_data = client_data; static char path[] = IPC_PATH_ATTR; char *commpath = NULL; int local_socket_len = 2; // 2 = '/' + '\0' FNIN(); local_socket_len += strlen(child); local_socket_len += strlen(WORKING_DIR); commpath = (char*)cl_malloc(sizeof(char)*local_socket_len); sprintf(commpath, WORKING_DIR "/%s", child); commpath[local_socket_len - 1] = '\0'; cl_log(LOG_DEBUG, "Attempting to talk on: %s", commpath); attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, commpath); ch = ipc_channel_constructor(IPC_ANYTYPE, attrs); g_hash_table_destroy(attrs); if (ch == NULL) { cl_log(LOG_CRIT, "Could not access channel on: %s", commpath); + } else if (ch->ops->initiate_connection(ch) != IPC_OK) { cl_log(LOG_CRIT, "Could not init comms on: %s", commpath); FNRET(NULL); } if(callback_data == NULL) callback_data = ch; ch->ops->set_recv_qlen(ch, 100); ch->ops->set_send_qlen(ch, 100); the_source = G_main_add_IPC_Channel(G_PRIORITY_LOW, ch, FALSE, dispatch, callback_data, default_ipc_input_destroy); - if(client_data != NULL) { - client_data->client_source = the_source; - client_data->client_channel = ch; - } - + cl_log(LOG_DEBUG, "Processing of %s complete", commpath); + FNRET(ch); } IPC_WaitConnection * wait_channel_init(char daemonsocket[]) { IPC_WaitConnection *wait_ch; mode_t mask; char path[] = IPC_PATH_ATTR; GHashTable * attrs; FNIN(); attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, daemonsocket); mask = umask(0); wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs); if (wait_ch == NULL) { cl_perror("Can't create wait channel of type %s", IPC_ANYTYPE); exit(1); } mask = umask(mask); g_hash_table_destroy(attrs); FNRET(wait_ch); } IPC_Message * get_ipc_message(IPC_Channel *a_channel) { IPC_Message *msg = NULL; FNIN(); if(a_channel->ops->is_message_pending(a_channel) == TRUE) { if (a_channel->ch_status == IPC_DISCONNECT) { /* The pending message was IPC_DISCONNECT */ cl_log(LOG_INFO, "get_ipc_message: received HUP"); FNRET(msg); } if(a_channel->ops->recv(a_channel, &msg) != IPC_OK) { perror("Receive failure:"); FNRET(msg); } cl_log(LOG_INFO, "Got message [body=%s]", (char*)msg->msg_body); } FNRET(msg); } diff --git a/crm/common/msgutils.c b/crm/common/msgutils.c index 192bf7ce47..e41ecb5fff 100644 --- a/crm/common/msgutils.c +++ b/crm/common/msgutils.c @@ -1,736 +1,738 @@ -/* $Id: msgutils.c,v 1.27 2004/04/29 15:33:03 andrew Exp $ */ +/* $Id: msgutils.c,v 1.28 2004/05/10 21:52:57 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include xmlNodePtr create_common_message(xmlNodePtr original_request, xmlNodePtr xml_response_data); xmlNodePtr createPingAnswerFragment(const char *from, const char *status) { xmlNodePtr ping = NULL; FNIN(); ping = create_xml_node(NULL, XML_CRM_TAG_PING); set_xml_property_copy(ping, XML_PING_ATTR_STATUS, status); set_xml_property_copy(ping, XML_PING_ATTR_SYSFROM, from); FNRET(ping); } xmlNodePtr createPingRequest(const char *crm_msg_reference, const char *to) { xmlNodePtr root_xml_node = NULL; int sub_type_len; int msg_type_len; char *sub_type_target; char *msg_type_target; FNIN(); // 2 = "_" + '\0' sub_type_len = strlen(to) + strlen(XML_ATTR_REQUEST) + 2; sub_type_target = (char*)cl_malloc(sizeof(char)*(sub_type_len)); sprintf(sub_type_target, "%s_%s", to, XML_ATTR_REQUEST); root_xml_node = create_xml_node(NULL, sub_type_target); set_xml_property_copy(root_xml_node, XML_ATTR_REFERENCE, crm_msg_reference); msg_type_len = strlen(to) + 10 + 1; // + "_operation" + '\0' msg_type_target = (char*)cl_malloc(sizeof(char)*(msg_type_len)); sprintf(msg_type_target, "%s_operation", to); set_xml_property_copy(root_xml_node, msg_type_target, CRM_OPERATION_PING); cl_free(msg_type_target); FNRET(root_xml_node); } static uint ref_counter = 0; const char * generateReference(const char *custom1, const char *custom2) { const char *local_cust1 = custom1; const char *local_cust2 = custom2; int reference_len = 4; char *since_epoch = NULL; FNIN(); reference_len += 20; // too big reference_len += 40; // too big if(local_cust1 == NULL) local_cust1 = "_empty_"; reference_len += strlen(local_cust1); if(local_cust2 == NULL) local_cust2 = "_empty_"; reference_len += strlen(local_cust2); since_epoch = (char*)cl_malloc(reference_len*(sizeof(char))); FNIN(); sprintf(since_epoch, "%s-%s-%ld-%u", local_cust1, local_cust2, (unsigned long)time(NULL), ref_counter++); FNRET(since_epoch); } xmlNodePtr validate_crm_message(xmlNodePtr root_xml_node, const char *sys, const char *uuid, const char *msg_type) { const char *from = NULL; const char *to = NULL; const char *type = NULL; const char *crm_msg_reference = NULL; xmlNodePtr action = NULL; const char *true_sys; FNIN(); if (root_xml_node == NULL) FNRET(NULL); from = xmlGetProp(root_xml_node, XML_ATTR_SYSFROM); to = xmlGetProp(root_xml_node, XML_ATTR_SYSTO); type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE); crm_msg_reference = xmlGetProp(root_xml_node, XML_ATTR_REFERENCE); /* cl_log(LOG_DEBUG, "Recieved XML message with (version=%s)", xmlGetProp(root_xml_node, XML_ATTR_VERSION)); cl_log(LOG_DEBUG, "Recieved XML message with (from=%s)", from); cl_log(LOG_DEBUG, "Recieved XML message with (to=%s)" , to); cl_log(LOG_DEBUG, "Recieved XML message with (type=%s)", type); cl_log(LOG_DEBUG, "Recieved XML message with (ref=%s)" , crm_msg_reference); */ action = root_xml_node; true_sys = sys; if (uuid != NULL) true_sys = generate_hash_key(sys, uuid); if (to == NULL) { cl_log(LOG_INFO, "No sub-system defined."); action = NULL; } else if (true_sys != NULL && strcmp(to, true_sys) != 0) { cl_log(LOG_DEBUG, "The message is not for this sub-system (%s != %s).", to, true_sys); action = NULL; } if (type == NULL) { cl_log(LOG_INFO, "No message type defined."); FNRET(NULL); } else if (msg_type != NULL && strcmp(msg_type, type) != 0) { cl_log(LOG_INFO, "Expecting a (%s) message but receieved a (%s).", msg_type, type); action = NULL; } if (crm_msg_reference == NULL) { cl_log(LOG_INFO, "No message crm_msg_reference defined."); action = NULL; } /* if(action != NULL) cl_log(LOG_DEBUG, "XML is valid and node with message type (%s) found.", type); cl_log(LOG_DEBUG, "Returning node (%s)", xmlGetNodePath(action)); */ FNRET(action); } gboolean decodeNVpair(const char *srcstring, char separator, char **name, char **value) { int lpc = 0; int len = 0; const char *temp = NULL; FNIN(); CRM_DEBUG("Attempting to decode: [%s]", srcstring); if (srcstring != NULL) { len = strlen(srcstring); while(lpc < len) { if (srcstring[lpc++] == separator) { *name = (char*)cl_malloc(sizeof(char)*lpc); CRM_DEBUG("Malloc ok %d", lpc); strncpy(*name, srcstring, lpc-1); CRM_DEBUG("Strcpy ok %d", lpc-1); (*name)[lpc-1] = '\0'; CRM_DEBUG("Found token [%s]", *name); // this sucks but as the strtok *is* a bug len = len-lpc+1; *value = (char*)cl_malloc(sizeof(char)*len); CRM_DEBUG("Malloc ok %d", len); temp = srcstring+lpc; CRM_DEBUG("Doing str copy"); strncpy(*value, temp, len-1); (*value)[len-1] = '\0'; CRM_DEBUG("Found token [%s]", *value); FNRET(TRUE); } } } *name = NULL; *value = NULL; FNRET(FALSE); } char * generate_hash_key(const char *crm_msg_reference, const char *sys) { int ref_len = strlen(sys) + strlen(crm_msg_reference) + 2; char *hash_key = (char*)cl_malloc(sizeof(char)*(ref_len)); FNIN(); sprintf(hash_key, "%s_%s", sys, crm_msg_reference); hash_key[ref_len-1] = '\0'; cl_log(LOG_INFO, "created hash key: (%s)", hash_key); FNRET(hash_key); } char * generate_hash_value(const char *src_node, const char *src_subsys) { int ref_len; char *hash_value; FNIN(); if (src_node == NULL || src_subsys == NULL) { FNRET(NULL); } if (strcmp("dc", src_subsys) == 0) { hash_value = cl_strdup(src_subsys); if (!hash_value) { cl_log(LOG_ERR, "memory allocation failed in " "generate_hash_value()\n"); FNRET(NULL); } FNRET(hash_value); } ref_len = strlen(src_subsys) + strlen(src_node) + 2; hash_value = (char*)cl_malloc(sizeof(char)*(ref_len)); if (!hash_value) { cl_log(LOG_ERR, "memory allocation failed in " "generate_hash_value()\n"); FNRET(NULL); } snprintf(hash_value, ref_len-1, "%s_%s", src_node, src_subsys); hash_value[ref_len-1] = '\0';// make sure it is null terminated cl_log(LOG_INFO, "created hash value: (%s)", hash_value); FNRET(hash_value); } gboolean decode_hash_value(gpointer value, char **node, char **subsys) { char *char_value = (char*)value; int value_len = strlen(char_value); FNIN(); cl_log(LOG_INFO, "Decoding hash value: (%s:%d)", char_value, value_len); if (strcmp("dc", (char*)value) == 0) { *node = NULL; *subsys = (char*)cl_strdup(char_value); if (!*subsys) { cl_log(LOG_ERR, "memory allocation failed in " "decode_hash_value()\n"); FNRET(FALSE); } cl_log(LOG_INFO, "Decoded value: (%s:%d)", *subsys, (int)strlen(*subsys)); FNRET(TRUE); } else if (char_value != NULL) { if (decodeNVpair(char_value, '_', node, subsys)) { FNRET(TRUE); } else { *node = NULL; *subsys = NULL; FNRET(FALSE); } } FNRET(FALSE); } void send_hello_message(IPC_Channel *ipc_client, const char *uuid, const char *client_name, const char *major_version, const char *minor_version) { xmlNodePtr hello_node = NULL; FNIN(); if (uuid == NULL || strlen(uuid) == 0 || client_name == NULL || strlen(client_name) == 0 || major_version == NULL || strlen(major_version) == 0 || minor_version == NULL || strlen(minor_version) == 0) { cl_log(LOG_ERR, "Missing fields, Hello message will not be valid."); return; } hello_node = create_xml_node(NULL, "hello"); set_xml_property_copy(hello_node, "major_version", major_version); set_xml_property_copy(hello_node, "minor_version", minor_version); set_xml_property_copy(hello_node, "client_name", client_name); set_xml_property_copy(hello_node, "client_uuid", uuid); send_xmlipc_message(ipc_client, hello_node); free_xml(hello_node); } gboolean process_hello_message(IPC_Message *hello_message, char **uuid, char **client_name, char **major_version, char **minor_version) { xmlNodePtr hello; xmlDocPtr hello_doc; char *local_uuid; char *local_client_name; char *local_major_version; char *local_minor_version; FNIN(); *uuid = NULL; *client_name = NULL; *major_version = NULL; *minor_version = NULL; if (hello_message == NULL || hello_message->msg_body == NULL) { FNRET(FALSE); } hello_doc = xmlParseMemory( hello_message->msg_body, strlen(hello_message->msg_body)); if (hello_doc == NULL) { cl_log(LOG_ERR, "Expected a Hello message, Got: %s", (char*)hello_message->msg_body); FNRET(FALSE); } hello = xmlDocGetRootElement(hello_doc); if (hello == NULL) { FNRET(FALSE); } else if (strcmp("hello", hello->name) != 0) { FNRET(FALSE); } local_uuid = xmlGetProp(hello, "client_uuid"); local_client_name = xmlGetProp(hello, "client_name"); local_major_version = xmlGetProp(hello, "major_version"); local_minor_version = xmlGetProp(hello, "minor_version"); if (local_uuid == NULL || strlen(local_uuid) == 0) { cl_log(LOG_ERR, "Hello message was not valid (field %s not found): %s", "uuid", (char*)hello_message->msg_body); FNRET(FALSE); } else if (local_client_name==NULL || strlen(local_client_name)==0){ cl_log(LOG_ERR, "Hello message was not valid (field %s not found): %s", "client name", (char*)hello_message->msg_body); FNRET(FALSE); } else if(local_major_version == NULL || strlen(local_major_version) == 0){ cl_log(LOG_ERR, "Hello message was not valid (field %s not found): %s", "major version", (char*)hello_message->msg_body); FNRET(FALSE); } else if (local_minor_version == NULL || strlen(local_minor_version) == 0){ cl_log(LOG_ERR, "Hello message was not valid (field %s not found): %s", "minor version", (char*)hello_message->msg_body); FNRET(FALSE); } *uuid = cl_strdup(local_uuid); *client_name = cl_strdup(local_client_name); *major_version = cl_strdup(local_major_version); *minor_version = cl_strdup(local_minor_version); FNRET(TRUE); } gboolean forward_ipc_request(IPC_Channel *ipc_channel, xmlNodePtr xml_request, xmlNodePtr xml_response_data, const char *sys_to, const char *sys_from) { gboolean was_sent = FALSE; xmlNodePtr forward; FNIN(); forward = create_forward(xml_request, - xml_response_data, - sys_to); + xml_response_data, + sys_to); + if (forward != NULL) { was_sent = send_xmlipc_message(ipc_channel, forward); free_xml(forward); } + FNRET(was_sent); } /* * This method adds a copy of xml_response_data */ gboolean send_ipc_request(IPC_Channel *ipc_channel, xmlNodePtr msg_options, xmlNodePtr msg_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *crm_msg_reference) { gboolean was_sent = FALSE; xmlNodePtr request = NULL; FNIN(); request = create_request(msg_options, msg_data, host_to, sys_to, sys_from, uuid_from, crm_msg_reference); // xml_message_debug(request, "Final request..."); was_sent = send_xmlipc_message(ipc_channel, request); free_xml(request); FNRET(was_sent); } /* * This method adds a copy of xml_response_data */ gboolean send_ha_request(ll_cluster_t *hb_fd, xmlNodePtr msg_options, xmlNodePtr msg_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *crm_msg_reference) { gboolean was_sent = FALSE; xmlNodePtr request = NULL; FNIN(); request = create_request(msg_options, msg_data, host_to, sys_to, sys_from, uuid_from, crm_msg_reference); // xml_message_debug(request, "Final request..."); was_sent = send_xmlha_message(hb_fd, request); free_xml(request); FNRET(was_sent); } xmlNodePtr create_request(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *crm_msg_reference) { const char *true_from = sys_from; xmlNodePtr request; FNIN(); if (uuid_from != NULL) true_from = generate_hash_key(sys_from, uuid_from); // else make sure we are internal else { if (strcmp(CRM_SYSTEM_LRMD, sys_from) != 0 && strcmp(CRM_SYSTEM_PENGINE, sys_from) != 0 && strcmp(CRM_SYSTEM_TENGINE, sys_from) != 0 && strcmp(CRM_SYSTEM_DC, sys_from) != 0 && strcmp(CRM_SYSTEM_CRMD, sys_from) != 0) { cl_log(LOG_ERR, "only internal systems can leave uuid_from blank"); FNRET(FALSE); } } if (crm_msg_reference == NULL) { crm_msg_reference = generateReference( xmlGetProp(msg_options,XML_ATTR_OP),sys_from); } // host_from will get set for us if necessary by CRMd when routed request = create_xml_node(NULL, XML_MSG_TAG); set_node_tstamp(request); set_xml_property_copy(request, XML_ATTR_VERSION, CRM_VERSION); set_xml_property_copy(request, XML_ATTR_MSGTYPE, XML_ATTR_REQUEST); set_xml_property_copy(request, XML_ATTR_SYSTO, sys_to); set_xml_property_copy(request, XML_ATTR_SYSFROM, true_from); set_xml_property_copy(request, XML_ATTR_REFERENCE, crm_msg_reference); if(host_to != NULL && strlen(host_to) > 0) set_xml_property_copy(request, XML_ATTR_HOSTTO, host_to); if (msg_options != NULL) { add_node_copy(request, msg_options); } if (msg_data != NULL) { add_node_copy(request, msg_data); } FNRET(request); } /* * This method adds a copy of xml_response_data */ gboolean send_ipc_reply(IPC_Channel *ipc_channel, xmlNodePtr xml_request, xmlNodePtr xml_response_data) { gboolean was_sent = FALSE; xmlNodePtr reply; FNIN(); reply = create_reply(xml_request, xml_response_data); // xml_message_debug(reply, "Final reply..."); if (reply != NULL) { was_sent = send_xmlipc_message(ipc_channel, reply); free_xml(reply); } FNRET(was_sent); } // required? or just send to self an let relay_message do its thing? /* * This method adds a copy of xml_response_data */ gboolean send_ha_reply(ll_cluster_t *hb_cluster, xmlNodePtr xml_request, xmlNodePtr xml_response_data) { gboolean was_sent = FALSE; xmlNodePtr reply; FNIN(); was_sent = FALSE; reply = create_reply(xml_request, xml_response_data); if (reply != NULL) { was_sent = send_xmlha_message(hb_cluster, reply); free_xml(reply); } FNRET(was_sent); } /* * This method adds a copy of xml_response_data */ xmlNodePtr create_reply(xmlNodePtr original_request, xmlNodePtr xml_response_data) { const char *host_from = NULL; const char *sys_from = NULL; const char *sys_to = NULL; xmlNodePtr reply; FNIN(); host_from = xmlGetProp(original_request, XML_ATTR_HOSTFROM); sys_from = xmlGetProp(original_request, XML_ATTR_SYSFROM); sys_to = xmlGetProp(original_request, XML_ATTR_SYSTO); reply = create_common_message(original_request, xml_response_data); set_xml_property_copy(reply, XML_ATTR_MSGTYPE, XML_ATTR_RESPONSE); /* since this is a reply, we reverse the from and to */ // HOSTTO will be ignored if it is to the DC anyway. if(host_from != NULL && strlen(host_from) > 0) set_xml_property_copy(reply, XML_ATTR_HOSTTO, host_from); set_xml_property_copy(reply, XML_ATTR_SYSTO, sys_from); set_xml_property_copy(reply, XML_ATTR_SYSFROM, sys_to); FNRET(reply); } /* * This method adds a copy of xml_response_data */ xmlNodePtr create_forward(xmlNodePtr original_request, xmlNodePtr xml_response_data, const char *sys_to) { const char *host_from = NULL; const char *host_to = NULL; const char *sys_from = NULL; xmlNodePtr forward; FNIN(); host_from = xmlGetProp(original_request, XML_ATTR_HOSTFROM); host_to = xmlGetProp(original_request, XML_ATTR_HOSTTO); sys_from = xmlGetProp(original_request, XML_ATTR_SYSFROM); forward = create_common_message(original_request, xml_response_data); set_xml_property_copy(forward, XML_ATTR_MSGTYPE, XML_ATTR_REQUEST); // HOSTTO will be ignored if it is to the DC anyway. if(host_to != NULL && strlen(host_to) > 0) set_xml_property_copy(forward, XML_ATTR_HOSTTO, host_to); if(host_from != NULL) set_xml_property_copy(forward, XML_ATTR_HOSTFROM, host_from); set_xml_property_copy(forward, XML_ATTR_SYSTO, sys_to); set_xml_property_copy(forward, XML_ATTR_SYSFROM, sys_from); FNRET(forward); } xmlNodePtr create_common_message(xmlNodePtr original_request, xmlNodePtr xml_response_data) { const char *crm_msg_reference = NULL; const char *type = NULL; const char *operation = NULL; xmlNodePtr options = NULL; xmlNodePtr new_message; FNIN(); crm_msg_reference = xmlGetProp(original_request, XML_ATTR_REFERENCE); type = xmlGetProp(original_request, XML_ATTR_MSGTYPE); operation = xmlGetProp(original_request, XML_ATTR_OP); if (type == NULL) { cl_log(LOG_ERR, "Cannot create new_message," " no message type in original message"); FNRET(NULL); #if 0 } else if (strcmp(XML_ATTR_REQUEST, type) != 0) { cl_log(LOG_ERR, "Cannot create new_message," " original message was not a request"); FNRET(NULL); #endif } new_message = create_xml_node(NULL, XML_MSG_TAG); set_node_tstamp(new_message); set_xml_property_copy(new_message, XML_ATTR_VERSION, CRM_VERSION); set_xml_property_copy(new_message, XML_ATTR_OP, operation); set_xml_property_copy(new_message, XML_ATTR_REFERENCE, crm_msg_reference); if (xml_response_data != NULL) { add_node_copy(new_message, xml_response_data); } options = find_xml_node(original_request, XML_TAG_OPTIONS); if (options != NULL) { add_node_copy(new_message, options); } FNRET(new_message); } diff --git a/crm/crm-1.0.dtd b/crm/crm-1.0.dtd index 018fc7a8c0..5138b13ec7 100644 --- a/crm/crm-1.0.dtd +++ b/crm/crm-1.0.dtd @@ -1,558 +1,558 @@ - + - + diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c index 4a6804b08a..6b969d7b5b 100644 --- a/crm/crmd/ccm.c +++ b/crm/crmd/ccm.c @@ -1,512 +1,506 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 */ /* put these first so that uuid_t is defined without conflicts */ #include #include #include #include #include #include #include #include void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); #include #include #include #include #include #include int register_with_ccm(ll_cluster_t *hb_cluster); void msg_ccm_join(const struct ha_msg *msg, void *foo); void crmd_ccm_input_callback(oc_ed_t event, void *cookie, size_t size, const void *data); void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event); gboolean ccm_dispatch(int fd, gpointer user_data); void new_node_state(xmlNodePtr node_updates, const char *uname, const char *state); #define CCM_EVENT_DETAIL 1 oc_ev_t *fsa_ev_token; /* A_CCM_CONNECT */ enum crmd_fsa_input do_ccm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { int ret; /* fd_set rset; */ int fsa_ev_fd; FNIN(); if(action & A_CCM_DISCONNECT){ oc_ev_unregister(fsa_ev_token); } if(action & A_CCM_CONNECT) { cl_log(LOG_INFO, "Registering with CCM"); oc_ev_register(&fsa_ev_token); cl_log(LOG_INFO, "Setting up CCM callbacks"); oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS, crmd_ccm_input_callback, NULL); oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/); cl_log(LOG_INFO, "Activating CCM token"); ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd); if (ret){ cl_log(LOG_INFO, "CCM Activation failed... unregistering"); oc_ev_unregister(fsa_ev_token); return(I_FAIL); } cl_log(LOG_INFO, "CCM Activation passed... all set to go!"); /* FD_ZERO(&rset); */ /* FD_SET(fsa_ev_fd, &rset); */ //GFDSource* G_main_add_fd(G_PRIORITY_LOW, fsa_ev_fd, FALSE, ccm_dispatch, fsa_ev_token, default_ipc_input_destroy); } if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) { cl_log(LOG_ERR, "Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } FNRET(I_NULL); } /* A_CCM_EVENT */ enum crmd_fsa_input do_ccm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input return_input = I_NULL; const oc_ev_membership_t *oc = ((struct ccm_data *)data)->oc; oc_ed_t event = *((struct ccm_data *)data)->event; FNIN(); cl_log(LOG_INFO,"event=%s", event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP": event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY": event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED": event==OC_EV_MS_EVICTED?"EVICTED": "NO QUORUM MEMBERSHIP"); if(CCM_EVENT_DETAIL) { ccm_event_detail(oc, event); } if (OC_EV_MS_EVICTED == event) { /* get out... NOW! */ return_input = I_SHUTDOWN; } if(return_input == I_SHUTDOWN) { ; /* ignore everything, the new DC will handle it */ } else { /* My understanding is that we will never get both * node leaving *and* node joining callbacks at the * same time. * * This logic would need to change if this is not * the case */ if(oc->m_n_out !=0) { return_input = I_NODE_LEFT; } else if(oc->m_n_in !=0) { /* delay the I_NODE_JOIN until they acknowledge our * DC status and send us their CIB */ return_input = I_NULL; } else { cl_log(LOG_INFO, "So why are we here? What CCM event happened?"); } } FNRET(return_input); } /* A_CCM_UPDATE_CACHE */ /* * Take the opportunity to update the node status in the CIB as well * (but only if we are the DC) */ enum crmd_fsa_input do_ccm_update_cache(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input next_input = I_NULL; int lpc, offset; oc_node_t *members = NULL; oc_ed_t event = *((struct ccm_data *)data)->event; const oc_ev_membership_t *oc = ((struct ccm_data *)data)->oc; oc_node_list_t *tmp = NULL, *membership_copy = (oc_node_list_t *) cl_malloc(sizeof(oc_node_list_t)); xmlNodePtr update_list = create_xml_node(NULL, XML_CIB_TAG_STATE); FNIN(); set_xml_property_copy(update_list, XML_ATTR_ID, fsa_our_uname); cl_log(LOG_INFO,"Updating CCM cache after a \"%s\" event.", event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP": event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY": event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED": event==OC_EV_MS_EVICTED?"EVICTED": "NO QUORUM MEMBERSHIP"); /*--*-- All Member Nodes --*--*/ offset = oc->m_memb_idx; membership_copy->members_size = oc->m_n_member; - CRM_DEBUG("Number of members: %d", membership_copy->members_size); - if(membership_copy->members_size > 0) { int size = membership_copy->members_size; size = size * sizeof(oc_node_t); - CRM_DEBUG("Allocing %d", size); membership_copy->members = (oc_node_t *)cl_malloc(size); members = membership_copy->members; for(lpc=0; lpc < membership_copy->members_size; lpc++) { members[lpc].node_id = oc->m_array[offset+lpc].node_id; members[lpc].node_born_on = oc->m_array[offset+lpc].node_born_on; members[lpc].node_uname = cl_strdup(oc->m_array[offset+lpc].node_uname); new_node_state(update_list, members[lpc].node_uname, "in_ccm"); } } else { membership_copy->members = NULL; } /*--*-- New Member Nodes --*--*/ offset = oc->m_in_idx; membership_copy->new_members_size = oc->m_n_in; - CRM_DEBUG("Number of new members: %d", membership_copy->new_members_size); if(membership_copy->new_members_size > 0) { int size = membership_copy->new_members_size; size = size * sizeof(oc_node_t); - CRM_DEBUG("Allocing %d", size); - membership_copy->new_members = (oc_node_t *)cl_malloc(size); members = membership_copy->new_members; for(lpc=0; lpc < membership_copy->new_members_size; lpc++) { members[lpc].node_id = oc->m_array[offset+lpc].node_id; members[lpc].node_born_on = oc->m_array[offset+lpc].node_born_on; members[lpc].node_uname = cl_strdup(oc->m_array[offset+lpc].node_uname); new_node_state(update_list, members[lpc].node_uname, "in_ccm"); } } else { membership_copy->new_members = NULL; } /*--*-- Recently Dead Member Nodes --*--*/ offset = oc->m_out_idx; membership_copy->dead_members_size = oc->m_n_out; if(membership_copy->dead_members_size > 0) { int size = membership_copy->dead_members_size; size = size * sizeof(oc_node_t); membership_copy->dead_members = (oc_node_t *)cl_malloc(size); members = membership_copy->dead_members; for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) { members[lpc].node_id = oc->m_array[offset+lpc].node_id; members[lpc].node_born_on = oc->m_array[offset+lpc].node_born_on; members[lpc].node_uname = cl_strdup(oc->m_array[offset+lpc].node_uname); new_node_state(update_list, members[lpc].node_uname, "down"); } } else { membership_copy->dead_members = NULL; } if(AM_I_DC) { // should be sufficient for only the DC to do this xmlNodePtr fragment = create_cib_fragment(update_list, NULL); send_request(NULL, fragment, CRM_OPERATION_UPDATE, NULL, CRM_SYSTEM_DCIB); - + free_xml(fragment); } tmp = fsa_membership_copy; fsa_membership_copy = membership_copy; /* Free the old copy */ if(tmp != NULL) { if(tmp->members != NULL) cl_free(tmp->members); if(tmp->new_members != NULL) cl_free(tmp->new_members); if(tmp->dead_members != NULL) cl_free(tmp->dead_members); cl_free(tmp); } FNRET(next_input); } /* * node_updates must be pre-constructed (non-NULL) */ void new_node_state(xmlNodePtr node_updates, const char *uname, const char *state) { xmlNodePtr tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); set_node_tstamp(tmp1); set_xml_property_copy(tmp1, XML_ATTR_ID, uname); set_xml_property_copy(tmp1, "source", fsa_our_uname); set_xml_property_copy(tmp1, "state", state); xmlAddSibling(node_updates, tmp1); } void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event) { int member_id = -1; gboolean member = FALSE; int lpc; int node_list_size; cl_log(LOG_INFO,"trans=%d, nodes=%d, new=%d, lost=%d n_idx=%d, " "new_idx=%d, old_idx=%d", oc->m_instance, oc->m_n_member, oc->m_n_in, oc->m_n_out, oc->m_memb_idx, oc->m_in_idx, oc->m_out_idx); cl_log(LOG_INFO, "NODES IN THE PRIMARY MEMBERSHIP"); node_list_size = oc->m_n_member; for(lpc=0; lpcm_array[oc->m_memb_idx+lpc].node_uname, oc->m_array[oc->m_memb_idx+lpc].node_id, oc->m_array[oc->m_memb_idx+lpc].node_born_on); if(fsa_our_uname != NULL && strcmp(fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname)) { member = TRUE; member_id = oc->m_array[oc->m_memb_idx+lpc].node_id; } } if (member == FALSE) { cl_log(LOG_WARNING, "MY NODE IS NOT IN CCM THE MEMBERSHIP LIST"); } else { cl_log(LOG_INFO, "MY NODE ID IS %d", member_id); } cl_log(LOG_INFO, "NEW MEMBERS"); if (oc->m_n_in==0) cl_log(LOG_INFO, "\tNONE"); for(lpc=0; lpcm_n_in; lpc++) { cl_log(LOG_INFO,"\t%s [nodeid=%d, born=%d]", oc->m_array[oc->m_in_idx+lpc].node_uname, oc->m_array[oc->m_in_idx+lpc].node_id, oc->m_array[oc->m_in_idx+lpc].node_born_on); } cl_log(LOG_INFO, "MEMBERS LOST"); if (oc->m_n_out==0) cl_log(LOG_INFO, "\tNONE"); for(lpc=0; lpcm_n_out; lpc++) { cl_log(LOG_INFO,"\t%s [nodeid=%d, born=%d]", oc->m_array[oc->m_out_idx+lpc].node_uname, oc->m_array[oc->m_out_idx+lpc].node_id, oc->m_array[oc->m_out_idx+lpc].node_born_on); if(fsa_our_uname != NULL && strcmp(fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname)) { cl_log(LOG_ERR, "We're not part of the cluster anymore"); } } cl_log(LOG_INFO, "-----------------------"); } int register_with_ccm(ll_cluster_t *hb_cluster) { FNRET(0); } gboolean ccm_dispatch(int fd, gpointer user_data) { oc_ev_t *ccm_token = (oc_ev_t*)user_data; oc_ev_handle_event(ccm_token); return TRUE; } void crmd_ccm_input_callback(oc_ed_t event, void *cookie, size_t size, const void *data) { struct ccm_data *event_data = NULL; FNIN(); if(data != NULL) { event_data = (struct ccm_data *) cl_malloc(sizeof(struct ccm_data)); event_data->event = &event; event_data->oc = (const oc_ev_membership_t *)data; s_crmd_fsa(C_CCM_CALLBACK, I_CCM_EVENT, (void*)event_data); event_data->event = NULL; event_data->oc = NULL; cl_free(event_data); } else { cl_log(LOG_INFO, "CCM Callback with NULL data... " "I dont /think/ this is bad"); } oc_ev_callback_done(cookie); FNOUT(); } void msg_ccm_join(const struct ha_msg *msg, void *foo) { FNIN(); cl_log(LOG_INFO, "\n###### Recieved ccm_join message..."); if (msg != NULL) { cl_log(LOG_INFO, "[type=%s]", ha_msg_value(msg, F_TYPE)); cl_log(LOG_INFO, "[orig=%s]", ha_msg_value(msg, F_ORIG)); cl_log(LOG_INFO, "[to=%s]", ha_msg_value(msg, F_TO)); cl_log(LOG_INFO, "[status=%s]", ha_msg_value(msg, F_STATUS)); cl_log(LOG_INFO, "[info=%s]", ha_msg_value(msg, F_COMMENT)); cl_log(LOG_INFO, "[rsc_hold=%s]", ha_msg_value(msg, F_RESOURCES)); cl_log(LOG_INFO, "[stable=%s]", ha_msg_value(msg, F_ISSTABLE)); cl_log(LOG_INFO, "[rtype=%s]", ha_msg_value(msg, F_RTYPE)); cl_log(LOG_INFO, "[ts=%s]", ha_msg_value(msg, F_TIME)); cl_log(LOG_INFO, "[seq=%s]", ha_msg_value(msg, F_SEQ)); cl_log(LOG_INFO, "[generation=%s]", ha_msg_value(msg, F_HBGENERATION)); // cl_log(LOG_INFO, "[=%s]", ha_msg_value(msg, F_)); } FNOUT(); } diff --git a/crm/crmd/control.c b/crm/crmd/control.c index c7863d865e..8f2c148d94 100644 --- a/crm/crmd/control.c +++ b/crm/crmd/control.c @@ -1,403 +1,416 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #define PID_FILE WORKING_DIR"/crm.pid" #define DAEMON_LOG LOG_DIR"/crm.log" #define DAEMON_DEBUG LOG_DIR"/crm.debug" gboolean crmd_ha_input_dispatch(int fd, gpointer user_data); void crmd_ha_input_destroy(gpointer user_data); void crm_shutdown(int nsig); GHashTable *ipc_clients = NULL; /* A_HA_CONNECT */ enum crmd_fsa_input do_ha_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { gboolean registered = FALSE; FNIN(); if(action & A_HA_DISCONNECT) { if(fsa_cluster_conn != NULL) { fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn); } } if(action & A_HA_CONNECT) { if(fsa_cluster_conn == NULL) fsa_cluster_conn = ll_cluster_new("heartbeat"); // make sure we are disconnected first fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn); registered = register_with_ha(fsa_cluster_conn, crm_system_name, crmd_ha_input_dispatch, crmd_ha_input_callback, crmd_ha_input_destroy); if(registered == FALSE) FNRET(I_FAIL); } if(action & ~(A_HA_CONNECT|A_HA_DISCONNECT)) { cl_log(LOG_ERR, "Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } FNRET(I_NULL); } /* A_SHUTDOWN */ enum crmd_fsa_input do_shutdown(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input next_input = I_NULL; enum crmd_fsa_input tmp = I_NULL; FNIN(); /* last attempt to shut these down */ if(is_set(fsa_input_register, R_PE_CONNECTED)) { cl_log(LOG_WARNING, "Last attempt to shutdown the PolicyEngine"); tmp = do_pe_control(A_PE_STOP, cause, cur_state, current_input, data); if(tmp != I_NULL) { next_input = I_ERROR; cl_log(LOG_ERR, "Failed to shutdown the PolicyEngine"); } } if(is_set(fsa_input_register, R_TE_CONNECTED)) { cl_log(LOG_WARNING, "Last attempt to shutdown the Transitioner"); tmp = do_pe_control(A_TE_STOP, cause, cur_state, current_input, data); if(tmp != I_NULL) { next_input = I_ERROR; cl_log(LOG_ERR, "Failed to shutdown the Transitioner"); } } /* TODO: shutdown all remaining resources? */ FNRET(next_input); } /* A_SHUTDOWN_REQ */ enum crmd_fsa_input do_shutdown_req(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input next_input = I_NULL; FNIN(); if(send_request(NULL, NULL, CRM_OPERATION_SHUTDOWN_REQ, NULL, CRM_SYSTEM_DC) == FALSE){ next_input = I_ERROR; } FNRET(next_input); } gboolean crmd_ha_input_dispatch(int fd, gpointer user_data) { + int lpc = 0; ll_cluster_t* hb_cluster = (ll_cluster_t*)user_data; FNIN(); while(hb_cluster->llc_ops->msgready(hb_cluster)) { + lpc++; // invoke the callbacks but dont block hb_cluster->llc_ops->rcvmsg(hb_cluster, 0); } + + if(lpc == 0){ + // hey what happened?? + cl_log(LOG_ERR, "We were called but no message was ready.\n" + "\tLikely the connection to Heartbeat failed, check the logs"); + + // TODO: feed this back into the FSA + + FNRET(FALSE); + } + FNRET(TRUE); } void crmd_ha_input_destroy(gpointer user_data) { cl_log(LOG_INFO, "in my hb_input_destroy"); } /* A_EXIT_0, A_EXIT_1 */ enum crmd_fsa_input do_exit(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { FNIN(); cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); if(action & A_EXIT_0) { g_main_quit(crmd_mainloop); } else { exit(1); } FNRET(I_NULL); } /* A_STARTUP */ enum crmd_fsa_input do_startup(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { int facility; int was_error = 0; int interval = 1; // seconds between DC heartbeats FNIN(); fsa_input_register = 0; // zero out the regester cl_log(LOG_INFO, "Register PID"); register_pid(PID_FILE, FALSE, crm_shutdown); cl_log_set_logfile(DAEMON_LOG); /* if (crm_debug()) { */ cl_log_set_debugfile(DAEMON_DEBUG); /* cl_log_enable_stderr(FALSE); } */ ipc_clients = g_hash_table_new(&g_str_hash, &g_str_equal); /* change the logging facility to the one used by heartbeat daemon */ fsa_cluster_conn = ll_cluster_new("heartbeat"); cl_log(LOG_INFO, "Switching to Heartbeat logger"); if ((facility = fsa_cluster_conn->llc_ops->get_logfacility( fsa_cluster_conn)) > 0) { cl_log_set_facility(facility); } CRM_DEBUG("Facility: %d", facility); if(was_error == 0) { CRM_DEBUG("Init server comms"); was_error = init_server_ipc_comms(CRM_SYSTEM_CRMD, crmd_client_connect, default_ipc_input_destroy); } if (was_error == 0) { CRM_DEBUG("Finding our node name"); fsa_our_uname = fsa_cluster_conn->llc_ops->get_mynodeid( fsa_cluster_conn); if (fsa_our_uname == NULL) { cl_log(LOG_ERR, "get_mynodeid() failed"); was_error = 1; } - cl_log(LOG_INFO, "Hostname: %s", fsa_our_uname); + cl_log(LOG_INFO, "FSA Hostname: %s", fsa_our_uname); } /* set up the timers */ dc_heartbeat = (fsa_timer_t *)cl_malloc(sizeof(fsa_timer_t)); integration_timer= (fsa_timer_t *)cl_malloc(sizeof(fsa_timer_t)); election_trigger = (fsa_timer_t *)cl_malloc(sizeof(fsa_timer_t)); election_timeout = (fsa_timer_t *)cl_malloc(sizeof(fsa_timer_t)); shutdown_escalation_timmer = (fsa_timer_t *) cl_malloc(sizeof(fsa_timer_t)); interval = interval * 1000; election_trigger->source_id = -1; election_trigger->period_ms = interval*4; election_trigger->fsa_input = I_DC_TIMEOUT; election_trigger->callback = timer_popped; dc_heartbeat->source_id = -1; dc_heartbeat->period_ms = interval; dc_heartbeat->fsa_input = I_NULL; dc_heartbeat->callback = do_dc_heartbeat; election_timeout->source_id = -1; election_timeout->period_ms = interval*6; election_timeout->fsa_input = I_ELECTION_DC; election_timeout->callback = timer_popped; integration_timer->source_id = -1; integration_timer->period_ms = interval*6; integration_timer->fsa_input = I_INTEGRATION_TIMEOUT; integration_timer->callback = timer_popped; shutdown_escalation_timmer->source_id = -1; shutdown_escalation_timmer->period_ms = interval*13; shutdown_escalation_timmer->fsa_input = I_TERMINATE; shutdown_escalation_timmer->callback = timer_popped; /* set up the sub systems */ cib_subsystem = (struct crm_subsystem_s*) cl_malloc(sizeof(struct crm_subsystem_s)); cib_subsystem->pid = 0; cib_subsystem->respawn = 1; cib_subsystem->path = cl_strdup(BIN_DIR); cib_subsystem->name = cl_strdup(CRM_SYSTEM_CIB); cib_subsystem->command = BIN_DIR"/cib"; cib_subsystem->flag = R_CIB_CONNECTED; te_subsystem = (struct crm_subsystem_s*) cl_malloc(sizeof(struct crm_subsystem_s)); te_subsystem->pid = 0; te_subsystem->respawn = 1; te_subsystem->path = cl_strdup(BIN_DIR); te_subsystem->name = cl_strdup(CRM_SYSTEM_TENGINE); te_subsystem->command = BIN_DIR"/tengine"; te_subsystem->flag = R_TE_CONNECTED; pe_subsystem = (struct crm_subsystem_s*) cl_malloc(sizeof(struct crm_subsystem_s)); pe_subsystem->pid = 0; pe_subsystem->respawn = 1; pe_subsystem->path = cl_strdup(BIN_DIR); pe_subsystem->name = cl_strdup(CRM_SYSTEM_PENGINE); pe_subsystem->command = BIN_DIR"/pengine"; pe_subsystem->flag = R_PE_CONNECTED; if(was_error) FNRET(I_FAIL); FNRET(I_NULL); } /* A_STOP */ enum crmd_fsa_input do_stop(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { FNIN(); cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); FNRET(I_NULL); } /* A_STARTED */ enum crmd_fsa_input do_started(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { FNIN(); clear_bit_inplace(&fsa_input_register, R_STARTING); FNRET(I_NULL); } /* A_RECOVER */ enum crmd_fsa_input do_recover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { FNIN(); cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); FNRET(I_SHUTDOWN); } void crm_shutdown(int nsig) { FNIN(); CL_SIGNAL(nsig, crm_shutdown); if (crmd_mainloop != NULL && g_main_is_running(crmd_mainloop)) { if(is_set(fsa_input_register, R_SHUTDOWN)) { CRM_DEBUG("Escalating the shutdown"); s_crmd_fsa(C_SHUTDOWN, I_ERROR, NULL); } else { set_bit_inplace(&fsa_input_register, R_SHUTDOWN); // cant rely on this... startTimer(shutdown_escalation_timmer); s_crmd_fsa(C_SHUTDOWN, I_SHUTDOWN, NULL); } } else { CRM_DEBUG("exit from shutdown"); exit(LSB_EXIT_OK); } FNOUT(); } diff --git a/crm/crmd/fsa.c b/crm/crmd/fsa.c index cca29a7c1a..904e6658ce 100644 --- a/crm/crmd/fsa.c +++ b/crm/crmd/fsa.c @@ -1,1056 +1,1088 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include long long do_state_transition(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, enum crmd_fsa_input current_input, void *data); #ifdef DOT_FSA_ACTIONS # ifdef FSA_TRACE -# define ELSEIF_FSA_ACTION(x,y) \ - else if(is_set(actions,x)) { \ +# define IF_FSA_ACTION(x,y) \ + if(is_set(actions,x)) { \ CRM_DEBUG("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ + last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data==NULL?"no":"yes", \ fsa_input2string(next_input)); \ fflush(dot_strm); \ - CRM_DEBUG("Result of action %s was %s", \ + CRM_DEBUG("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else -# define ELSEIF_FSA_ACTION(x,y) \ - else if(is_set(actions,x)) { \ +# define IF_FSA_ACTION(x,y) \ + if(is_set(actions,x)) { \ + last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data==NULL?"no":"yes", \ fsa_input2string(next_input)); \ fflush(dot_strm); \ } # endif #else # ifdef FSA_TRACE -# define ELSEIF_FSA_ACTION(x,y) \ - else if(is_set(actions,x)) { \ +# define IF_FSA_ACTION(x,y) \ + if(is_set(actions,x)) { \ CRM_DEBUG("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ + last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ - CRM_DEBUG("Result of action %s was %s", \ + CRM_DEBUG("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else -# define ELSEIF_FSA_ACTION(x,y) \ - else if(is_set(actions,x)) { \ +# define IF_FSA_ACTION(x,y) \ + if(is_set(actions,x)) { \ + last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ } # endif #endif +#define ELSEIF_FSA_ACTION(x,y) else IF_FSA_ACTION(x,y) + const char *dot_intro = "digraph \"g\" {\n" " size = \"30,30\"\n" " graph [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " bb = \"0,0,398.922306,478.927856\"\n" " color = \"black\"\n" " ]\n" " node [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " shape = \"ellipse\"\n" " color = \"black\"\n" " ]\n" " edge [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " color = \"black\"\n" " ]\n" "// special nodes\n" " \"S_PENDING\" \n" " [\n" " color = \"blue\"\n" " fontcolor = \"blue\"\n" " ]\n" " \"S_TERMINATE\" \n" " [\n" " color = \"red\"\n" " fontcolor = \"red\"\n" " ]\n" "\n" "// DC only nodes\n" " \"S_RECOVERY_DC\" [ fontcolor = \"green\" ]\n" " \"S_INTEGRATION\" [ fontcolor = \"green\" ]\n" " \"S_POLICY_ENGINE\" [ fontcolor = \"green\" ]\n" " \"S_TRANSITION_ENGINE\" [ fontcolor = \"green\" ]\n" " \"S_RELEASE_DC\" [ fontcolor = \"green\" ]\n" " \"S_IDLE\" [ fontcolor = \"green\" ]\n"; static FILE *dot_strm = NULL; enum crmd_fsa_state fsa_state; oc_node_list_t *fsa_membership_copy; ll_cluster_t *fsa_cluster_conn; ll_lrm_t *fsa_lrm_conn; long long fsa_input_register; +long long fsa_actions = A_NOTHING; const char *fsa_our_uname; fsa_timer_t *election_trigger = NULL; /* */ fsa_timer_t *election_timeout = NULL; /* */ fsa_timer_t *shutdown_escalation_timmer = NULL; /* */ fsa_timer_t *integration_timer = NULL; fsa_timer_t *dc_heartbeat = NULL; long long toggle_bit(long long action_list, long long action) { // CRM_DEBUG("Toggling bit %.16llx", action); action_list ^= action; // CRM_DEBUG("Result %.16llx", action_list & action); return action_list; } long long clear_bit(long long action_list, long long action) { // CRM_DEBUG("Clearing bit\t%.16llx", action); // ensure its set action_list |= action; // then toggle action_list = action_list ^ action; return action_list; } long long set_bit(long long action_list, long long action) { // CRM_DEBUG("Adding bit\t%.16llx", action); action_list |= action; return action_list; } void toggle_bit_inplace(long long *action_list, long long action) { *action_list = toggle_bit(*action_list, action); } void clear_bit_inplace(long long *action_list, long long action) { *action_list = clear_bit(*action_list, action); } void set_bit_inplace(long long *action_list, long long action) { *action_list = set_bit(*action_list, action); } gboolean is_set(long long action_list, long long action) { // CRM_DEBUG("Checking bit\t%.16llx", action); return ((action_list & action) == action); } gboolean startTimer(fsa_timer_t *timer) { if(((int)timer->source_id) < 0) { timer->source_id = Gmain_timeout_add(timer->period_ms, timer->callback, (void*)timer); /* CRM_DEBUG("#!!#!!# Started %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); */ } else { cl_log(LOG_INFO, "#!!#!!# Timer %s already running (%d)", fsa_input2string(timer->fsa_input), timer->source_id); return FALSE; } return TRUE; } gboolean stopTimer(fsa_timer_t *timer) { if(((int)timer->source_id) > 0) { /* CRM_DEBUG("#!!#!!# Stopping %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); */ g_source_remove(timer->source_id); timer->source_id = -2; } else { cl_log(LOG_INFO, "#!!#!!# Timer %s already stopped (%d)", fsa_input2string(timer->fsa_input), timer->source_id); return FALSE; } return TRUE; } enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause, enum crmd_fsa_input initial_input, void *data) { - long long actions = A_NOTHING, new_actions = A_NOTHING; + long long actions = fsa_actions; + long long new_actions = A_NOTHING; + long long last_action = A_NOTHING; enum crmd_fsa_input last_input = initial_input; enum crmd_fsa_input cur_input; enum crmd_fsa_input next_input; enum crmd_fsa_state last_state, cur_state, next_state, starting_state; FNIN(); starting_state = fsa_state; cur_input = initial_input; next_input = initial_input; last_state = starting_state; cur_state = starting_state; next_state = starting_state; #ifdef FSA_TRACE CRM_DEBUG("FSA invoked with Cause: %s\n\tState: %s, Input: %s", fsa_cause2string(cause), fsa_state2string(cur_state), fsa_input2string(cur_input)); #endif if(dot_strm == NULL) { dot_strm = fopen("/tmp/live.dot", "w"); fprintf(dot_strm, "%s", dot_intro); } /* * Process actions in order of priority but do only one * action at a time to avoid complicating the ordering. * * Actions may result in a new I_ event, these are added to * (not replace) existing actions before the next iteration. * */ while(next_input != I_NULL || actions != A_NOTHING) { if(next_input == I_WAIT_FOR_EVENT) { /* we may be waiting for an a-sync task to "happen" * and until it does, we cant do anything else + * + * Re-add the last action */ + + actions |= last_action; + cl_log(LOG_INFO, "Wait until something else happens"); break; } - cur_input = next_input; - #ifdef FSA_TRACE CRM_DEBUG("FSA while loop:\tState: %s, Input: %s", fsa_state2string(cur_state), fsa_input2string(cur_input)); -#endif +#endif + + /* update input variables */ + cur_input = next_input; + if(cur_input != I_NULL) { + last_input = cur_input; + } + /* get the next batch of actions */ new_actions = crmd_fsa_actions[cur_input][cur_state]; - next_state = crmd_fsa_state[cur_input][cur_state]; - last_state = cur_state; - cur_state = next_state; - fsa_state = next_state; - if(new_actions != A_NOTHING) { #ifdef FSA_TRACE CRM_DEBUG("Adding actions %.16llx", new_actions); #endif actions |= new_actions; } - switch(cur_input) { - case I_NULL: - break; -#if 0 - case I_SOME_EVENT: - case I_SOME_OTHER_EVENT: - cc_transitioner(cur_input, data); - /* flow through... */ -#endif - default: - last_input = cur_input; - break; - } + /* logging : *before* the state is changed */ + IF_FSA_ACTION(A_ERROR, do_log) + ELSEIF_FSA_ACTION(A_WARN, do_log) + ELSEIF_FSA_ACTION(A_LOG, do_log) + + /* update state variables */ + next_state = crmd_fsa_state[cur_input][cur_state]; + last_state = cur_state; + cur_state = next_state; + fsa_state = next_state; + + /* start doing things... */ + /* * Hook for change of state. * Allows actions to be added or removed when entering a state */ if(last_state != cur_state){ actions = do_state_transition(actions, cause, last_state, cur_state, last_input, data); } /* this is always run, some inputs/states may make various * actions irrelevant/invalid */ actions = clear_flags(actions, cause, cur_state, cur_input); /* regular action processing in order of action priority * * Make sure all actions that connect to required systems * are performed first */ if(actions == A_NOTHING) { cl_log(LOG_INFO, "Nothing to do"); next_input = I_NULL; /* // check registers, see if anything is pending if(is_set(fsa_input_register, R_SHUTDOWN)) { CRM_DEBUG("(Re-)invoking shutdown"); next_input = I_SHUTDOWN; } else if(is_set(fsa_input_register, R_INVOKE_PE)) { CRM_DEBUG("Invoke the PE somehow"); } -*/ } +*/ + } + - /* logging */ - ELSEIF_FSA_ACTION(A_ERROR, do_log) - ELSEIF_FSA_ACTION(A_WARN, do_log) - ELSEIF_FSA_ACTION(A_LOG, do_log) - /* get out of here NOW! before anything worse happens */ - ELSEIF_FSA_ACTION(A_EXIT_1, do_exit) + ELSEIF_FSA_ACTION(A_EXIT_1, do_exit) ELSEIF_FSA_ACTION(A_STARTUP, do_startup) ELSEIF_FSA_ACTION(A_CIB_START, do_cib_control) ELSEIF_FSA_ACTION(A_HA_CONNECT, do_ha_control) ELSEIF_FSA_ACTION(A_LRM_CONNECT,do_lrm_control) ELSEIF_FSA_ACTION(A_CCM_CONNECT,do_ccm_control) ELSEIF_FSA_ACTION(A_ANNOUNCE, do_announce) /* sub-system start */ ELSEIF_FSA_ACTION(A_PE_START, do_pe_control) ELSEIF_FSA_ACTION(A_TE_START, do_te_control) /* sub-system restart */ ELSEIF_FSA_ACTION(O_CIB_RESTART,do_cib_control) ELSEIF_FSA_ACTION(O_PE_RESTART, do_pe_control) ELSEIF_FSA_ACTION(O_TE_RESTART, do_te_control) ELSEIF_FSA_ACTION(A_STARTED, do_started) /* DC Timer */ ELSEIF_FSA_ACTION(O_DC_TIMER_RESTART, do_dc_timer_control) ELSEIF_FSA_ACTION(A_DC_TIMER_STOP, do_dc_timer_control) ELSEIF_FSA_ACTION(A_DC_TIMER_START, do_dc_timer_control) /* * Highest priority actions */ + ELSEIF_FSA_ACTION(A_TE_COPYTO, do_te_copyto) ELSEIF_FSA_ACTION(A_SHUTDOWN_REQ, do_shutdown_req) ELSEIF_FSA_ACTION(A_MSG_ROUTE, do_msg_route) ELSEIF_FSA_ACTION(A_RECOVER, do_recover) ELSEIF_FSA_ACTION(A_ELECTION_VOTE, do_election_vote) ELSEIF_FSA_ACTION(A_ELECT_TIMER_START, do_election_timer_ctrl) ELSEIF_FSA_ACTION(A_ELECT_TIMER_STOP, do_election_timer_ctrl) ELSEIF_FSA_ACTION(A_ELECTION_COUNT, do_election_count_vote) ELSEIF_FSA_ACTION(A_ELECTION_TIMEOUT, do_election_timer_ctrl) /* * "Get this over with" actions */ ELSEIF_FSA_ACTION(A_MSG_STORE, do_msg_store) ELSEIF_FSA_ACTION(A_NODE_BLOCK, do_node_block) /* * High priority actions * Update the cache first */ ELSEIF_FSA_ACTION(A_CCM_UPDATE_CACHE, do_ccm_update_cache) ELSEIF_FSA_ACTION(A_CCM_EVENT, do_ccm_event) /* * Medium priority actions */ ELSEIF_FSA_ACTION(A_DC_TAKEOVER, do_dc_takeover) ELSEIF_FSA_ACTION(A_DC_RELEASE, do_dc_release) ELSEIF_FSA_ACTION(A_JOIN_WELCOME_ALL, do_send_welcome) ELSEIF_FSA_ACTION(A_JOIN_WELCOME, do_send_welcome) ELSEIF_FSA_ACTION(A_JOIN_ACK, do_ack_welcome) ELSEIF_FSA_ACTION(A_JOIN_PROCESS_ACK, do_process_welcome_ack) /* * Low(er) priority actions * Make sure the CIB is always updated before invoking the * PE, and the PE before the TE */ ELSEIF_FSA_ACTION(A_UPDATE_NODESTATUS, do_lrm_invoke) ELSEIF_FSA_ACTION(A_CIB_INVOKE_LOCAL, do_cib_invoke) ELSEIF_FSA_ACTION(A_CIB_INVOKE, do_cib_invoke) ELSEIF_FSA_ACTION(A_CIB_BUMPGEN, do_cib_invoke) ELSEIF_FSA_ACTION(A_LRM_INVOKE, do_lrm_invoke) ELSEIF_FSA_ACTION(A_LRM_EVENT, do_lrm_event) + ELSEIF_FSA_ACTION(A_TE_CANCEL, do_te_invoke) ELSEIF_FSA_ACTION(A_PE_INVOKE, do_pe_invoke) ELSEIF_FSA_ACTION(A_TE_INVOKE, do_te_invoke) /* sub-system stop */ ELSEIF_FSA_ACTION(A_PE_STOP, do_pe_control) ELSEIF_FSA_ACTION(A_TE_STOP, do_te_control) ELSEIF_FSA_ACTION(A_DC_RELEASED, do_dc_release) ELSEIF_FSA_ACTION(A_HA_DISCONNECT, do_ha_control) ELSEIF_FSA_ACTION(A_CCM_DISCONNECT, do_ccm_control) ELSEIF_FSA_ACTION(A_LRM_DISCONNECT, do_lrm_control) ELSEIF_FSA_ACTION(A_CIB_STOP, do_cib_control) /* time to go now... */ /* Some of these can probably be consolidated */ ELSEIF_FSA_ACTION(A_SHUTDOWN, do_shutdown) ELSEIF_FSA_ACTION(A_STOP, do_stop) /* exit gracefully */ ELSEIF_FSA_ACTION(A_EXIT_0, do_exit) // ELSEIF_FSA_ACTION(A_, do_) else if(is_message()) { xmlNodePtr stored_msg = NULL; fsa_message_queue_t msg = get_message(); + + if(is_message() == FALSE) { + actions = clear_bit(actions, A_MSG_PROCESS); + } if(msg == NULL || msg->message == NULL) { cl_log(LOG_ERR, "Invalid stored message"); continue; } data = msg->message; #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t// %s:\t%s\t(data? %s)", fsa_input2string(cur_input), fsa_action2string(A_MSG_PROCESS), stored_msg==NULL?"no":"yes"); fflush(dot_strm); #endif #ifdef FSA_TRACE CRM_DEBUG("Invoking action %s (%.16llx)", fsa_action2string(A_MSG_PROCESS), A_MSG_PROCESS); #endif stored_msg = (xmlNodePtr)data; #ifdef FSA_TRACE xml_message_debug(stored_msg,"FSA processing message"); #endif next_input = handle_message(stored_msg); #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t(result=%s)\n", fsa_input2string(next_input)); #endif CRM_DEBUG("Result of action %s was %s", fsa_action2string(A_MSG_PROCESS), - fsa_input2string(next_input)); - + fsa_input2string(next_input)); + /* Error checking and reporting */ } else if(cur_input != I_NULL && is_set(actions, A_NOTHING)) { cl_log(LOG_WARNING, "No action specified for input,state (%s,%s)", fsa_input2string(cur_input), fsa_state2string(cur_state)); next_input = I_NULL; } else if(cur_input == I_NULL && is_set(actions, A_NOTHING)) { #ifdef FSA_TRACE cl_log(LOG_INFO, "Nothing left to do"); #endif } else { cl_log(LOG_ERR, "Action %s (0x%llx) not supported ", fsa_action2string(actions), actions); next_input = I_ERROR; } } #ifdef FSA_TRACE CRM_DEBUG("################# Exiting the FSA (%s) ##################", fsa_state2string(fsa_state)); #endif + +#ifdef DOT_FSA_ACTIONS + fprintf(dot_strm, + "\t// ### Exiting the FSA (%s)\n", + fsa_state2string(fsa_state)); + fflush(dot_strm); +#endif + // cleanup inputs? + fsa_actions = actions; FNRET(fsa_state); } /* A_NODE_BLOCK */ enum crmd_fsa_input do_node_block(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr xml_message = (xmlNodePtr)data; const char *host_from = xmlGetProp(xml_message, XML_ATTR_HOSTFROM); FNIN(); (void)host_from; FNRET(I_NULL); } const char * fsa_input2string(int input) { const char *inputAsText = NULL; switch(input){ case I_NULL: inputAsText = "I_NULL"; break; case I_CCM_EVENT: inputAsText = "I_CCM_EVENT"; break; case I_CIB_OP: inputAsText = "I_CIB_OP"; break; case I_CIB_UPDATE: inputAsText = "I_CIB_UPDATE"; break; case I_DC_TIMEOUT: inputAsText = "I_DC_TIMEOUT"; break; case I_ELECTION: inputAsText = "I_ELECTION"; break; case I_RELEASE_DC: inputAsText = "I_RELEASE_DC"; break; case I_ELECTION_DC: inputAsText = "I_ELECTION_DC"; break; case I_ERROR: inputAsText = "I_ERROR"; break; case I_FAIL: inputAsText = "I_FAIL"; break; case I_INTEGRATION_TIMEOUT: inputAsText = "I_INTEGRATION_TIMEOUT"; break; case I_NODE_JOIN: inputAsText = "I_NODE_JOIN"; break; case I_NODE_LEFT: inputAsText = "I_NODE_LEFT"; break; case I_NODE_LEAVING: inputAsText = "I_NODE_LEAVING"; break; case I_NOT_DC: inputAsText = "I_NOT_DC"; break; case I_RECOVERED: inputAsText = "I_RECOVERED"; break; case I_RELEASE_FAIL: inputAsText = "I_RELEASE_FAIL"; break; case I_RELEASE_SUCCESS: inputAsText = "I_RELEASE_SUCCESS"; break; case I_RESTART: inputAsText = "I_RESTART"; break; case I_REQUEST: inputAsText = "I_REQUEST"; break; case I_ROUTER: inputAsText = "I_ROUTER"; break; case I_SHUTDOWN: inputAsText = "I_SHUTDOWN"; break; /* case I_SHUTDOWN_REQ: */ /* inputAsText = "I_SHUTDOWN_REQ"; */ /* break; */ case I_STARTUP: inputAsText = "I_STARTUP"; break; case I_SUCCESS: inputAsText = "I_SUCCESS"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; break; case I_WELCOME: inputAsText = "I_WELCOME"; break; case I_WELCOME_ACK: inputAsText = "I_WELCOME_ACK"; break; case I_DC_HEARTBEAT: inputAsText = "I_DC_HEARTBEAT"; break; + case I_WAIT_FOR_EVENT: + inputAsText = "I_WAIT_FOR_EVENT"; + break; case I_ILLEGAL: inputAsText = "I_ILLEGAL"; break; } if(inputAsText == NULL) { cl_log(LOG_ERR, "Input %d is unknown", input); inputAsText = ""; } return inputAsText; } const char * fsa_state2string(int state) { const char *stateAsText = NULL; switch(state){ case S_IDLE: stateAsText = "S_IDLE"; break; case S_ELECTION: stateAsText = "S_ELECTION"; break; case S_INTEGRATION: stateAsText = "S_INTEGRATION"; break; case S_NOT_DC: stateAsText = "S_NOT_DC"; break; case S_POLICY_ENGINE: stateAsText = "S_POLICY_ENGINE"; break; case S_RECOVERY: stateAsText = "S_RECOVERY"; break; case S_RECOVERY_DC: stateAsText = "S_RECOVERY_DC"; break; case S_RELEASE_DC: stateAsText = "S_RELEASE_DC"; break; case S_PENDING: stateAsText = "S_PENDING"; break; case S_STOPPING: stateAsText = "S_STOPPING"; break; case S_TERMINATE: stateAsText = "S_TERMINATE"; break; case S_TRANSITION_ENGINE: stateAsText = "S_TRANSITION_ENGINE"; break; case S_ILLEGAL: stateAsText = "S_ILLEGAL"; break; } if(stateAsText == NULL) { cl_log(LOG_ERR, "State %d is unknown", state); stateAsText = ""; } return stateAsText; } const char * fsa_cause2string(int cause) { const char *causeAsText = NULL; switch(cause){ case C_UNKNOWN: causeAsText = "C_UNKNOWN"; break; case C_STARTUP: causeAsText = "C_STARTUP"; break; case C_IPC_MESSAGE: causeAsText = "C_IPC_MESSAGE"; break; case C_HA_MESSAGE: causeAsText = "C_HA_MESSAGE"; break; case C_CCM_CALLBACK: causeAsText = "C_CCM_CALLBACK"; break; case C_TIMER_POPPED: causeAsText = "C_TIMER_POPPED"; break; case C_SHUTDOWN: causeAsText = "C_SHUTDOWN"; break; case C_HEARTBEAT_FAILED: causeAsText = "C_HEARTBEAT_FAILED"; break; + case C_SUBSYSTEM_CONNECT: + causeAsText = "C_SUBSYSTEM_CONNECT"; + break; case C_ILLEGAL: causeAsText = "C_ILLEGAL"; break; } if(causeAsText == NULL) { cl_log(LOG_ERR, "Cause %d is unknown", cause); causeAsText = ""; } return causeAsText; } const char * fsa_action2string(long long action) { const char *actionAsText = NULL; switch(action){ case A_NOTHING: actionAsText = "A_NOTHING"; break; case O_SHUTDOWN: actionAsText = "O_SHUTDOWN"; break; case O_RELEASE: actionAsText = "O_RELEASE"; break; case A_STARTUP: actionAsText = "A_STARTUP"; break; case A_STARTED: actionAsText = "A_STARTED"; break; case A_HA_CONNECT: actionAsText = "A_HA_CONNECT"; break; case A_HA_DISCONNECT: actionAsText = "A_HA_DISCONNECT"; break; case A_LRM_CONNECT: actionAsText = "A_LRM_CONNECT"; break; case A_LRM_DISCONNECT: actionAsText = "A_LRM_DISCONNECT"; break; case O_DC_TIMER_RESTART: actionAsText = "O_DC_TIMER_RESTART"; break; case A_DC_TIMER_STOP: actionAsText = "A_DC_TIMER_STOP"; break; case A_DC_TIMER_START: actionAsText = "A_DC_TIMER_START"; break; case A_ELECTION_COUNT: actionAsText = "A_ELECTION_COUNT"; break; case A_ELECTION_TIMEOUT: actionAsText = "A_ELECTION_TIMEOUT"; break; case A_ELECT_TIMER_START: actionAsText = "A_ELECT_TIMER_START"; break; case A_ELECT_TIMER_STOP: actionAsText = "A_ELECT_TIMER_STOP"; break; case A_ELECTION_VOTE: actionAsText = "A_ELECTION_VOTE"; break; case A_ANNOUNCE: actionAsText = "A_ANNOUNCE"; break; case A_JOIN_ACK: actionAsText = "A_JOIN_ACK"; break; case A_JOIN_WELCOME: actionAsText = "A_JOIN_WELCOME"; break; case A_JOIN_WELCOME_ALL: actionAsText = "A_JOIN_WELCOME_ALL"; break; case A_JOIN_PROCESS_ACK: actionAsText = "A_JOIN_PROCESS_ACK"; break; case A_MSG_PROCESS: actionAsText = "A_MSG_PROCESS"; break; case A_MSG_ROUTE: actionAsText = "A_MSG_ROUTE"; break; case A_MSG_STORE: actionAsText = "A_MSG_STORE"; break; case A_RECOVER: actionAsText = "A_RECOVER"; break; case A_DC_RELEASE: actionAsText = "A_DC_RELEASE"; break; case A_DC_RELEASED: actionAsText = "A_DC_RELEASED"; break; case A_DC_TAKEOVER: actionAsText = "A_DC_TAKEOVER"; break; case A_SHUTDOWN: actionAsText = "A_SHUTDOWN"; break; case A_SHUTDOWN_REQ: actionAsText = "A_SHUTDOWN_REQ"; break; case A_STOP: actionAsText = "A_STOP "; break; case A_EXIT_0: actionAsText = "A_EXIT_0"; break; case A_EXIT_1: actionAsText = "A_EXIT_1"; break; case A_CCM_CONNECT: actionAsText = "A_CCM_CONNECT"; break; case A_CCM_DISCONNECT: actionAsText = "A_CCM_DISCONNECT"; break; case A_CCM_EVENT: actionAsText = "A_CCM_EVENT"; break; case A_CCM_UPDATE_CACHE: actionAsText = "A_CCM_UPDATE_CACHE"; break; case A_CIB_BUMPGEN: actionAsText = "A_CIB_BUMPGEN"; break; case A_CIB_INVOKE: actionAsText = "A_CIB_INVOKE"; break; case O_CIB_RESTART: actionAsText = "O_CIB_RESTART"; break; case A_CIB_START: actionAsText = "A_CIB_START"; break; case A_CIB_STOP: actionAsText = "A_CIB_STOP"; break; case A_TE_INVOKE: actionAsText = "A_TE_INVOKE"; break; case O_TE_RESTART: actionAsText = "O_TE_RESTART"; break; case A_TE_START: actionAsText = "A_TE_START"; break; case A_TE_STOP: actionAsText = "A_TE_STOP"; break; case A_PE_INVOKE: actionAsText = "A_PE_INVOKE"; break; case O_PE_RESTART: actionAsText = "O_PE_RESTART"; break; case A_PE_START: actionAsText = "A_PE_START"; break; case A_PE_STOP: actionAsText = "A_PE_STOP"; break; case A_NODE_BLOCK: actionAsText = "A_NODE_BLOCK"; break; case A_UPDATE_NODESTATUS: actionAsText = "A_UPDATE_NODESTATUS"; break; case A_LOG: actionAsText = "A_LOG "; break; case A_ERROR: actionAsText = "A_ERROR "; break; case A_WARN: actionAsText = "A_WARN "; break; } if(actionAsText == NULL) { cl_log(LOG_ERR, "Action %.16llx is unknown", action); actionAsText = ""; } return actionAsText; } long long do_state_transition(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, enum crmd_fsa_input current_input, void *data) { long long tmp = A_NOTHING; if(current_input != I_NULL && (current_input != I_DC_HEARTBEAT || cur_state != S_NOT_DC)){ const char *state_from = fsa_state2string(cur_state); const char *state_to = fsa_state2string(next_state); const char *input = fsa_input2string(current_input); time_t now = time(NULL); fprintf(dot_strm, "\t\"%s\" -> \"%s\" [ label =\"%s\" ] // %s", state_from, state_to, input, asctime(localtime(&now))); fflush(dot_strm); } switch(next_state) { case S_PENDING: case S_NOT_DC: if(is_set(fsa_input_register, R_SHUTDOWN)){ tmp = set_bit(actions, A_SHUTDOWN_REQ); } tmp = clear_bit(actions, A_RECOVER); break; case S_RECOVERY_DC: case S_RECOVERY: tmp = set_bit(actions, A_RECOVER); break; default: tmp = clear_bit(actions, A_RECOVER); break; } if(tmp != actions) { cl_log(LOG_INFO, "Action b4 %.16llx ", actions); cl_log(LOG_INFO, "Action after %.16llx ", tmp); actions = tmp; } return actions; } long long clear_flags(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input) { if(is_set(fsa_input_register, R_SHUTDOWN)){ clear_bit_inplace(&actions, A_DC_TIMER_START); } switch(cur_state) { case S_IDLE: break; case S_ELECTION: break; case S_INTEGRATION: break; case S_NOT_DC: break; case S_POLICY_ENGINE: break; case S_RECOVERY: break; case S_RECOVERY_DC: break; case S_RELEASE_DC: break; case S_PENDING: break; case S_STOPPING: break; case S_TERMINATE: break; case S_TRANSITION_ENGINE: break; case S_ILLEGAL: break; } return actions; } diff --git a/crm/crmd/fsa_defines.h b/crm/crmd/fsa_defines.h index a975f87d21..d0bb845d5f 100644 --- a/crm/crmd/fsa_defines.h +++ b/crm/crmd/fsa_defines.h @@ -1,488 +1,495 @@ -/* $Id: fsa_defines.h,v 1.11 2004/04/13 13:26:45 andrew Exp $ */ +/* $Id: fsa_defines.h,v 1.12 2004/05/10 21:52:57 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 XML_FSA_DEFINES__H #define XML_FSA_DEFINES__H /*====================================== * States the DC/CRMd can be in *======================================*/ enum crmd_fsa_state { S_IDLE = 0, /* Nothing happening */ S_ELECTION, /* Take part in the election algorithm as * described below */ S_INTEGRATION, /* integrate that status of new nodes (which is * all of them if we have just been elected DC) * to form a complete and up-to-date picture of * the CIB */ S_NOT_DC, /* we are in crmd/slave mode */ S_POLICY_ENGINE,/* Determin the next stable state of the cluster */ S_RECOVERY, /* Something bad happened, check everything is ok * before continuing and attempt to recover if * required */ S_RECOVERY_DC, /* Something bad happened to the DC, check * everything is ok before continuing and attempt * to recover if required */ S_RELEASE_DC, /* we were the DC, but now we arent anymore, * possibly by our own request, and we should * release all unnecessary sub-systems, finish * any pending actions, do general cleanup and * unset anything that makes us think we are * special :) */ S_PENDING, /* we are just starting out */ S_STOPPING, /* We are in the final stages of shutting down */ S_TERMINATE, /* We are going to shutdown, this is the equiv of * "Sending TERM signal to all processes" in Linux * and in worst case scenarios could be considered * a self STONITH */ S_TRANSITION_ENGINE,/* Attempt to make the calculated next stable * state of the cluster a reality */ /* ----------- Last input found in table is above ---------- */ S_ILLEGAL, /* This is an illegal FSA state */ /* (must be last) */ }; #define MAXSTATE S_ILLEGAL /* A state diagram can be constructed from the dc_fsa.dot with the following command: dot -Tpng crmd_fsa.dot > crmd_fsa.png Description: Once we start and do some basic sanity checks, we go into the S_NOT_DC state and await instructions from the DC or input from the CCM which indicates the election algorithm needs to run. If the election algorithm is triggered we enter the S_ELECTION state from where we can either go back to the S_NOT_DC state or progress to the S_INTEGRATION state (or S_RELEASE_DC if we used to be the DC but arent anymore). The election algorithm has been adapted from http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR521 Loosly known as the Bully Algorithm, its major points are: - Election is initiated by any node (N) notices that the coordinator is no longer responding - Concurrent multiple elections are possible - Algorithm + N sends ELECTION messages to all nodes that occur earlier in the CCM's membership list. + If no one responds, N wins and becomes coordinator + N sends out COORDINATOR messages to all other nodes in the partition + If one of higher-ups answers, it takes over. N is done. Once the election is complete, if we are the DC, we enter the S_INTEGRATION state which is a DC-in-waiting style state. We are the DC, but we shouldnt do anything yet because we may not have an up-to-date picture of the cluster. There may of course be times when this fails, so we should go back to the S_RECOVERY stage and check everything is ok. We may also end up here if a new node came online, since each node is authorative on itself and we would want to incorporate its information into the CIB. Once we have the latest CIB, we then enter the S_POLICY_ENGINE state where invoke the Policy Engine. It is possible that between invoking the Policy Engine and recieving an answer, that we recieve more input. In this case we would discard the orginal result and invoke it again. Once we are satisfied with the output from the Policy Engine we enter S_TRANSITION_ENGINE and feed the Policy Engine's output to the Transition Engine who attempts to make the Policy Engine's calculation a reality. If the transition completes successfully, we enter S_IDLE, otherwise we go back to S_POLICY_ENGINE with the current unstable state and try again. Of course we may be asked to shutdown at any time, however we must progress to S_NOT_DC before doing so. Once we have handed over DC duties to another node, we can then shut down like everyone else, that is by asking the DC for permission and waiting it to take all our resources away. The case where we are the DC and the only node in the cluster is a special case and handled as an escalation which takes us to S_SHUTDOWN. Similarly if any other point in the shutdown fails or stalls, this is escalated and we end up in S_TERMINATE. At any point, the CRMd/DC can relay messages for its sub-systems, but outbound messages (from sub-systems) should probably be blocked until S_INTEGRATION (for the DC case) or the join protocol has completed (for the CRMd case) */ /*====================================== * * Inputs/Events/Stimuli to be given to the finite state machine * * Some of these a true events, and others a synthesised based on * the "register" (see below) and the contents or source of messages. * * At this point, my plan is to have a loop of some sort that keeps * going until recieving I_NULL * *======================================*/ enum crmd_fsa_input { +// 0 I_NULL, /* Nothing happened */ - +// 1 I_CCM_EVENT, I_CIB_OP, /* An update to the CIB occurred */ I_CIB_UPDATE, /* An update to the CIB occurred */ I_DC_TIMEOUT, /* We have lost communication with the DC */ I_ELECTION, /* Someone started an election */ + I_PE_CALC, /* The Policy Engine needs to be invoked */ I_RELEASE_DC, /* The election completed and we were not * elected, but we were the DC beforehand */ I_ELECTION_DC, /* The election completed and we were (re-)elected * DC */ I_ERROR, /* Something bad happened (more serious than * I_FAIL) and may not have been due to the action * being performed. For example, we may have lost * our connection to the CIB. */ +// 10 I_FAIL, /* The action failed to complete successfully */ I_INTEGRATION_TIMEOUT, I_NODE_JOIN, /* A node has entered the CCM membership list*/ I_NODE_LEFT, /* A node shutdown (possibly unexpectedly) */ I_NODE_LEAVING, /* A node has asked to be shutdown */ I_NOT_DC, /* We are not and were not the DC before or after * the current operation or state */ I_RECOVERED, /* The recovery process completed successfully */ I_RELEASE_FAIL, /* We could not give up DC status for some reason */ I_RELEASE_SUCCESS, /* We are no longer the DC */ I_RESTART, /* The current set of actions needs to be * restarted */ +// 20 I_REQUEST, /* Some non-resource, non-ccm action is required * of us, eg. ping */ I_ROUTER, /* Do our job as router and forward this to the * right place */ I_SHUTDOWN, /* We are asking to shutdown */ I_TERMINATE, /* We have been told to shutdown */ I_STARTUP, I_SUCCESS, /* The action completed successfully */ I_WELCOME, /* Welcome a newly joined node */ I_WELCOME_ACK, /* The newly joined node has acknowledged us as overlord */ I_WAIT_FOR_EVENT, /* we may be waiting for an async task to "happen" * and until it does, we cant do anything else */ I_DC_HEARTBEAT, /* The DC is telling us that it is alive and well */ I_LRM_EVENT, /* ------------ Last input found in table is above ----------- */ I_ILLEGAL, /* This is an illegal value for an FSA input */ /* (must be last) */ }; #define MAXINPUT I_ILLEGAL #define I_MESSAGE I_ROUTER /*====================================== * * actions * * Some of the actions below will always occur together for now, but I can * forsee that this may not always be the case. So I've spilt them up so * that if they ever do need to be called independantly in the future, it * wont be a problem. * * For example, separating A_LRM_CONNECT from A_STARTUP might be useful * if we ever try to recover from a faulty or disconnected LRM. * *======================================*/ /* Complete list of actions A_CCM_CONNECT A_CCM_EVENT A_CCM_UPDATE_CACHE A_CIB_INVOKE A_CIB_RESTART A_CIB_START A_CIB_STOP A_CIB_UPDATE A_DC_RELEASE A_DC_TAKEOVER A_DISCONNECT A_ELECTION_COUNT A_ELECTION_TIMEOUT A_ELECTION_VOTE A_ERROR A_EXIT_0 A_EXIT_1 A_HA_CONNECT A_JOIN_ACK A_JOIN_WELCOME A_JOIN_WELCOME_ALL A_LOG A_LRM_CONNECT A_MSG_PROCESS A_MSG_ROUTE A_MSG_STORE A_NODE_BLOCK A_NOTHING A_PE_INVOKE A_PE_RESTART A_PE_START A_PE_STOP A_RECOVER A_SHUTDOWN A_STARTED A_STARTUP A_STOP A_TERMINATE A_TE_INVOKE A_TE_RESTART A_TE_START A_TE_STOP A_DC_TIMER_STOP A_DC_TIMER_START A_WARN */ /* Dont do anything */ #define A_NOTHING 0x0000000000000000ULL /* -- Startup actions -- */ /* Hook to perform any actions (other than starting the CIB, * connecting to HA or the CCM) that might be needed as part * of the startup. */ #define A_STARTUP 0x0000000000000001ULL /* Hook to perform any actions that might be needed as part * after startup is successful. */ #define A_STARTED 0x0000000000000002ULL /* Connect to Heartbeat */ #define A_HA_CONNECT 0x0000000000000004ULL #define A_HA_DISCONNECT 0x0000000000000008ULL /* -- Election actions -- */ #define A_DC_TIMER_START 0x0000000000000010ULL #define A_DC_TIMER_STOP 0x0000000000000020ULL #define A_ELECT_TIMER_START 0x0000000000000040ULL #define A_ELECT_TIMER_STOP 0x0000000000000080ULL #define A_ELECTION_COUNT 0x0000000000000100ULL #define A_ELECTION_TIMEOUT 0x0000000000000200ULL #define A_ELECTION_VOTE 0x0000000000000400ULL /* -- Join protocol actions -- */ #define A_ANNOUNCE 0x0000000000000800ULL /* Acknowledge the DC as our overlord*/ #define A_JOIN_ACK 0x0000000000001000ULL /* Send a welcome message to new node(s) */ #define A_JOIN_WELCOME 0x0000000000002000ULL /* Send a welcome message to all nodes */ #define A_JOIN_WELCOME_ALL 0x0000000000004000ULL /* Process the remote node's ack of our join message */ #define A_JOIN_PROCESS_ACK 0x0000000000008000ULL /* -- Message processing -- */ /* Process the queue of requests */ #define A_MSG_PROCESS 0x0000000000010000ULL /* Send the message to the correct recipient */ #define A_MSG_ROUTE 0x0000000000020000ULL /* Put the request into a queue for processing. We do this every * time so that the processing is consistent. The intent is to * allow the DC to keep doing important work while still not * loosing requests. * Messages are not considered recieved until processed. */ #define A_MSG_STORE 0x0000000000040000ULL /* -- Recovery, DC start/stop -- */ /* Something bad happened, try to recover */ #define A_RECOVER 0x0000000001000000ULL /* Hook to perform any actions (apart from starting, the TE, PE * and gathering the latest CIB) that might be necessary before * giving up the responsibilities of being the DC. */ #define A_DC_RELEASE 0x0000000002000000ULL /* */ #define A_DC_RELEASED 0x0000000004000000ULL /* Hook to perform any actions (apart from starting, the TE, PE * and gathering the latest CIB) that might be necessary before * taking over the responsibilities of being the DC. */ #define A_DC_TAKEOVER 0x0000000008000000ULL /* -- Shutdown actions -- */ #define A_SHUTDOWN 0x0000000010000000ULL #define A_STOP 0x0000000020000000ULL #define A_EXIT_0 0x0000000040000000ULL #define A_EXIT_1 0x0000000080000000ULL #define A_SHUTDOWN_REQ 0x0000000100000000ULL /* -- CCM actions -- */ #define A_CCM_CONNECT 0x0000001000000000ULL #define A_CCM_DISCONNECT 0x0000002000000000ULL /* Process whatever it is the CCM is trying to tell us. * This will generate inputs such as I_NODE_JOIN, * I_NODE_LEAVE, I_SHUTDOWN, I_DC_RELEASE, I_DC_TAKEOVER */ #define A_CCM_EVENT 0x0000004000000000ULL #define A_CCM_UPDATE_CACHE 0x0000008000000000ULL /* -- CBI actions -- */ #define A_CIB_INVOKE 0x0000010000000000ULL #define A_CIB_START 0x0000020000000000ULL #define A_CIB_STOP 0x0000040000000000ULL #define A_CIB_INVOKE_LOCAL 0x0000080000000000ULL /* -- Transition Engine actions -- */ /* Attempt to reach the newly calculated cluster state. This is * only called once per transition (except if it is asked to * stop the transition or start a new one). * Once given a cluster state to reach, the TE will determin * tasks that can be performed in parallel, execute them, wait * for replies and then determin the next set until the new * state is reached or no further tasks can be taken. */ #define A_TE_INVOKE 0x0000100000000000ULL #define A_TE_START 0x0000200000000000ULL #define A_TE_STOP 0x0000400000000000ULL +#define A_TE_CANCEL 0x0000800000000000ULL +#define A_TE_COPYTO 0x0001000000000000ULL /* -- Policy Engine actions -- */ /* Calculate the next state for the cluster. This is only * invoked once per needed calculation. */ -#define A_PE_INVOKE 0x0001000000000000ULL -#define A_PE_START 0x0002000000000000ULL -#define A_PE_STOP 0x0004000000000000ULL +#define A_PE_INVOKE 0x0002000000000000ULL +#define A_PE_START 0x0004000000000000ULL +#define A_PE_STOP 0x0008000000000000ULL /* -- Misc actions -- */ /* Add a system generate "block" so that resources arent moved * to or are activly moved away from the affected node. This * way we can return quickly even if busy with other things. */ #define A_NODE_BLOCK 0x0010000000000000ULL /* Update our information in the local CIB */ #define A_UPDATE_NODESTATUS 0x0020000000000000ULL #define A_CIB_BUMPGEN 0x0040000000000000ULL /* -- LRM Actions -- */ /* Connect to the Local Resource Manager */ #define A_LRM_CONNECT 0x0100000000000000ULL /* Disconnect from the Local Resource Manager */ #define A_LRM_DISCONNECT 0x0200000000000000ULL #define A_LRM_INVOKE 0x0400000000000000ULL #define A_LRM_EVENT 0x0800000000000000ULL /* -- Logging actions -- */ #define A_LOG 0x1000000000000000ULL #define A_ERROR 0x2000000000000000ULL #define A_WARN 0x4000000000000000ULL #define O_SHUTDOWN (A_DC_TIMER_STOP|A_CCM_DISCONNECT|A_LRM_DISCONNECT|A_HA_DISCONNECT|A_SHUTDOWN|A_STOP|A_EXIT_0|A_CIB_STOP) #define O_RELEASE (A_DC_RELEASE|A_PE_STOP|A_TE_STOP|A_DC_RELEASED) #define O_DC_TIMER_RESTART (A_DC_TIMER_STOP|A_DC_TIMER_START) #define O_PE_RESTART (A_PE_START|A_PE_STOP) #define O_TE_RESTART (A_TE_START|A_TE_STOP) #define O_CIB_RESTART (A_CIB_START|A_CIB_STOP) #define O_DC_TICKLE O_DC_TIMER_RESTART /*====================================== * * "register" contents * * Things we may want to remember regardless of which state we are in. * * These also count as inputs for synthesizing I_* * *======================================*/ #define R_THE_DC 0x00000001 /* Are we the DC? */ #define R_STARTING 0x00000002 /* Are we starting up? */ #define R_SHUTDOWN 0x00000004 /* Are we trying to shut down? */ #define R_CIB_DONE 0x00000008 /* Have we calculated the CIB? */ #define R_JOIN_OK 0x00000010 /* Have we completed the join process */ #define R_HAVE_CIB 0x00000020 /* Do we have an up-to-date CIB */ #define R_HAVE_RES 0x00000040 /* Do we have any resources running locally */ #define R_INVOKE_PE 0x00000080 /* Does the PE needed to be invoked at the next appropriate point? */ #define R_CIB_CONNECTED 0x00000100 /* Is the CIB connected? */ #define R_PE_CONNECTED 0x00000200 /* Is the Policy Engine connected? */ #define R_TE_CONNECTED 0x00000400 /* Is the Transition Engine connected? */ #define R_LRM_CONNECTED 0x00000800 /* Is the Local Resource Manager connected? */ #define R_REQ_PEND 0x00001000 /* Are there Requests waiting for processing? */ #define R_PE_PEND 0x00002000 /* Has the PE been invoked and we're awaiting a reply? */ #define R_TE_PEND 0x00004000 /* Has the TE been invoked and we're awaiting completion? */ #define R_RESP_PEND 0x00008000 /* Do we have clients waiting on a response? if so perhaps we shouldnt stop yet */ enum crmd_fsa_cause { C_UNKNOWN = 0, C_STARTUP, C_IPC_MESSAGE, C_HA_MESSAGE, C_CCM_CALLBACK, C_LRM_OP_CALLBACK, C_LRM_MONITOR_CALLBACK, C_TIMER_POPPED, C_SHUTDOWN, C_HEARTBEAT_FAILED, + C_SUBSYSTEM_CONNECT, C_ILLEGAL }; extern const char *fsa_input2string(int input); extern const char *fsa_state2string(int state); extern const char *fsa_cause2string(int cause); extern const char *fsa_action2string(long long action); #endif diff --git a/crm/crmd/fsa_matrix.h b/crm/crmd/fsa_matrix.h index bf15da0482..f5142fcdcb 100644 --- a/crm/crmd/fsa_matrix.h +++ b/crm/crmd/fsa_matrix.h @@ -1,1000 +1,1031 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 XML_FSA_MATRIX__H #define XML_FSA_MATRIX__H /* * The state transition table. The rows are inputs, and * the columns are states. */ const enum crmd_fsa_state crmd_fsa_state [MAXINPUT][MAXSTATE] = { /* Got an I_NULL */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_CCM_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_CIB_OP */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_CIB_UPDATE */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_RECOVERY, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, - /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, + /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_ELECTION, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RECOVERY, /* S_PENDING ==> */ S_ELECTION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_ELECTION */ { /* S_IDLE ==> */ S_ELECTION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_ELECTION, /* S_NOT_DC ==> */ S_ELECTION, /* S_POLICY_ENGINE ==> */ S_ELECTION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_ELECTION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_ELECTION, }, +/* Got an I_PE_CALC */ + { + /* S_IDLE ==> */ S_POLICY_ENGINE, + /* S_ELECTION ==> */ S_ELECTION, + /* S_INTEGRATION ==> */ S_POLICY_ENGINE, + /* S_NOT_DC ==> */ S_RECOVERY, + /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, + /* S_RECOVERY ==> */ S_RECOVERY, + /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, + /* S_RELEASE_DC ==> */ S_RELEASE_DC, + /* S_PENDING ==> */ S_RECOVERY, + /* S_STOPPING ==> */ S_STOPPING, + /* S_TERMINATE ==> */ S_TERMINATE, + /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, + }, + /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_ELECTION_DC */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_INTEGRATION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_INTEGRATION, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY_DC, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_INTEGRATION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, }, /* Got an I_ERROR */ { /* S_IDLE ==> */ S_RECOVERY_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_RECOVERY_DC, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RELEASE_DC, /* S_RELEASE_DC ==> */ S_STOPPING, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_TERMINATE, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY_DC, }, /* Got an I_FAIL */ { /* S_IDLE ==> */ S_RECOVERY_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_INTEGRATION_TIMEOUT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_POLICY_ENGINE, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_NODE_JOIN */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, }, /* Got an I_NODE_LEFT */ { /* S_IDLE ==> */ S_POLICY_ENGINE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_NODE_LEAVING */ { /* S_IDLE ==> */ S_POLICY_ENGINE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_NOT_DC */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_PENDING, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_RECOVERED */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_PENDING, /* S_RECOVERY_DC ==> */ S_INTEGRATION, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_RELEASE_FAIL */ { /* S_IDLE ==> */ S_STOPPING, /* S_ELECTION ==> */ S_STOPPING, /* S_INTEGRATION ==> */ S_STOPPING, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_STOPPING, /* S_RECOVERY ==> */ S_STOPPING, /* S_RECOVERY_DC ==> */ S_STOPPING, /* S_RELEASE_DC ==> */ S_STOPPING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_STOPPING, }, /* Got an I_RELEASE_SUCCESS */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_PENDING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_RESTART */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_REQUEST */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_ROUTER */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_SHUTDOWN */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RELEASE_DC, /* S_RECOVERY ==> */ S_PENDING, /* S_RECOVERY_DC ==> */ S_PENDING, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_TERMINATE */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, /* S_NOT_DC ==> */ S_STOPPING, /* S_POLICY_ENGINE ==> */ S_RELEASE_DC, /* S_RECOVERY ==> */ S_STOPPING, /* S_RECOVERY_DC ==> */ S_STOPPING, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_STARTUP */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_SUCCESS */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_POLICY_ENGINE, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_TERMINATE, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_IDLE, }, /* Got an I_WELCOME */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RELEASE_DC, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RELEASE_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_NOT_DC, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_WELCOME_ACK */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_WAIT_FOR_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_DC_HEARTBEAT */ { /* S_IDLE ==> */ S_ELECTION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_ELECTION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_ELECTION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_ELECTION, }, /* Got an I_LRM_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, }; /* * The action table. Each entry is a set of actions to take or-ed * together. Like the state table, the rows are inputs, and * the columns are states. */ const long long crmd_fsa_actions [MAXINPUT][MAXSTATE] = { /* Got an I_NULL */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_NOTHING, /* S_INTEGRATION ==> */ A_NOTHING, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_RECOVER, /* S_RECOVERY_DC ==> */ A_RECOVER, /* S_RELEASE_DC ==> */ A_NOTHING, /* S_PENDING ==> */ A_NOTHING, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_NOTHING, }, /* Got an I_CCM_EVENT */ { /* S_IDLE ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_ELECTION ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_INTEGRATION ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_NOT_DC ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_POLICY_ENGINE ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_RECOVERY ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_RECOVERY_DC ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_RELEASE_DC ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_PENDING ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, }, /* Got an I_CIB_OP */ { /* S_IDLE ==> */ A_CIB_INVOKE, /* S_ELECTION ==> */ A_CIB_INVOKE, /* S_INTEGRATION ==> */ A_CIB_INVOKE, /* S_NOT_DC ==> */ A_CIB_INVOKE, /* S_POLICY_ENGINE ==> */ A_CIB_INVOKE, /* S_RECOVERY ==> */ A_CIB_INVOKE, /* S_RECOVERY_DC ==> */ A_CIB_INVOKE, /* S_RELEASE_DC ==> */ A_CIB_INVOKE, /* S_PENDING ==> */ A_CIB_INVOKE, /* S_STOPPING ==> */ A_CIB_INVOKE, /* S_TERMINATE ==> */ A_CIB_INVOKE, /* S_TRANSITION_ENGINE ==> */ A_CIB_INVOKE, }, /* Got an I_CIB_UPDATE */ { - /* S_IDLE ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, + /* S_IDLE ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, /* S_ELECTION ==> */ A_LOG, - /* S_INTEGRATION ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, + /* S_INTEGRATION ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, + /* S_POLICY_ENGINE ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, + /* S_RECOVERY_DC ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, + /* S_TRANSITION_ENGINE ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_ELECTION ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_INTEGRATION ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_NOT_DC ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_POLICY_ENGINE ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_RECOVERY ==> */ A_NOTHING, /* S_RECOVERY_DC ==> */ A_NOTHING, /* S_RELEASE_DC ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_PENDING ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, }, /* Got an I_ELECTION */ { /* S_IDLE ==> */ A_ELECTION_COUNT, /* S_ELECTION ==> */ A_ELECTION_COUNT, /* S_INTEGRATION ==> */ A_ELECTION_COUNT, /* S_NOT_DC ==> */ A_ELECTION_COUNT, /* S_POLICY_ENGINE ==> */ A_ELECTION_COUNT, /* S_RECOVERY ==> */ A_LOG, /* S_RECOVERY_DC ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_ELECTION_COUNT, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_ELECTION_COUNT, }, +/* Got an I_PE_CALC */ + { + /* S_IDLE ==> */ A_PE_INVOKE, + /* S_ELECTION ==> */ A_WARN, + /* S_INTEGRATION ==> */ A_PE_INVOKE, + /* S_NOT_DC ==> */ A_ERROR, + /* S_POLICY_ENGINE ==> */ A_PE_INVOKE, + /* S_RECOVERY ==> */ A_ERROR, + /* S_RECOVERY_DC ==> */ A_PE_INVOKE, + /* S_RELEASE_DC ==> */ A_WARN, + /* S_PENDING ==> */ A_ERROR, + /* S_STOPPING ==> */ A_WARN, + /* S_TERMINATE ==> */ A_WARN, + /* S_TRANSITION_ENGINE ==> */ A_PE_INVOKE|A_TE_CANCEL, + }, /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ O_RELEASE|A_ERROR, /* S_ELECTION ==> */ O_RELEASE, /* S_INTEGRATION ==> */ O_RELEASE|A_ERROR, /* S_NOT_DC ==> */ A_ERROR, /* S_POLICY_ENGINE ==> */ O_RELEASE|A_ERROR, /* S_RECOVERY ==> */ O_RELEASE, /* S_RECOVERY_DC ==> */ O_RELEASE|A_ERROR, /* S_RELEASE_DC ==> */ O_RELEASE|A_ERROR, /* S_PENDING ==> */ A_ERROR, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_ERROR, }, /* Got an I_ELECTION_DC */ { /* S_IDLE ==> */ A_WARN|A_ELECTION_VOTE, /* S_ELECTION ==> */ A_LOG|A_DC_TAKEOVER|A_PE_START|A_TE_START|A_JOIN_WELCOME_ALL|A_DC_TIMER_STOP|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, /* S_INTEGRATION ==> */ A_WARN|A_ELECTION_VOTE, /* S_NOT_DC ==> */ A_LOG|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, /* S_POLICY_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, /* S_RECOVERY ==> */ A_WARN|A_ELECTION_VOTE, /* S_RECOVERY_DC ==> */ A_LOG|A_ELECTION_VOTE, /* S_RELEASE_DC ==> */ A_WARN|A_ELECTION_VOTE, /* S_PENDING ==> */ A_LOG|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, }, /* Got an I_ERROR */ { /* S_IDLE ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_ELECTION ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_INTEGRATION ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|O_PE_RESTART|A_RECOVER, /* S_RECOVERY ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_RECOVERY_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_PENDING ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_STOPPING ==> */ A_DC_TIMER_STOP|A_EXIT_1, /* S_TERMINATE ==> */ A_DC_TIMER_STOP|A_EXIT_1, /* S_TRANSITION_ENGINE ==> */ A_DC_TIMER_STOP|O_TE_RESTART|A_RECOVER, }, /* Got an I_FAIL */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_DC_TIMER_STOP|A_WARN, /* S_INTEGRATION ==> */ A_WARN|A_JOIN_WELCOME_ALL, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN|A_JOIN_WELCOME_ALL|A_PE_INVOKE, /* S_RECOVERY ==> */ A_WARN|O_SHUTDOWN, /* S_RECOVERY_DC ==> */ A_WARN|O_SHUTDOWN|O_RELEASE, /* S_RELEASE_DC ==> */ A_WARN|O_SHUTDOWN, /* S_PENDING ==> */ A_DC_TIMER_STOP|A_WARN|O_SHUTDOWN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN|A_EXIT_1, /* S_TRANSITION_ENGINE ==> */ A_WARN|O_TE_RESTART|A_RECOVER, }, /* Got an I_INTEGRATION_TIMEOUT */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_PE_INVOKE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_NOTHING, }, /* Got an I_NODE_JOIN */ { - /* S_IDLE ==> */ A_JOIN_WELCOME|A_PE_INVOKE, + /* S_IDLE ==> */ A_TE_CANCEL|A_JOIN_WELCOME|A_PE_INVOKE, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_JOIN_WELCOME|A_PE_INVOKE, + /* S_INTEGRATION ==> */ A_TE_CANCEL|A_JOIN_WELCOME|A_PE_INVOKE, /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_JOIN_WELCOME|A_PE_INVOKE, + /* S_POLICY_ENGINE ==> */ A_TE_CANCEL|A_JOIN_WELCOME|A_PE_INVOKE, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_JOIN_WELCOME|A_PE_INVOKE, + /* S_RECOVERY_DC ==> */ A_TE_CANCEL|A_JOIN_WELCOME|A_PE_INVOKE, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_JOIN_WELCOME|A_PE_INVOKE, + /* S_TRANSITION_ENGINE ==> */ A_TE_CANCEL|A_JOIN_WELCOME|A_PE_INVOKE, }, /* Got an I_NODE_LEFT */ { - /* S_IDLE ==> */ A_PE_INVOKE, + /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_PE_INVOKE, + /* S_INTEGRATION ==> */ A_LOG, /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_PE_INVOKE, + /* S_POLICY_ENGINE ==> */ A_LOG, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_PE_INVOKE, + /* S_RECOVERY_DC ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_PE_INVOKE, + /* S_TRANSITION_ENGINE ==> */ A_LOG, }, /* Got an I_NODE_LEAVING */ { - /* S_IDLE ==> */ A_NODE_BLOCK|A_PE_INVOKE, + /* S_IDLE ==> */ A_NODE_BLOCK|A_PE_INVOKE|A_TE_CANCEL, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_NODE_BLOCK|A_PE_INVOKE, + /* S_INTEGRATION ==> */ A_NODE_BLOCK|A_PE_INVOKE|A_TE_CANCEL, /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_NODE_BLOCK|A_PE_INVOKE, + /* S_POLICY_ENGINE ==> */ A_NODE_BLOCK|A_PE_INVOKE|A_TE_CANCEL, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_NODE_BLOCK|A_PE_INVOKE, + /* S_RECOVERY_DC ==> */ A_NODE_BLOCK|A_PE_INVOKE|A_TE_CANCEL, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_NODE_BLOCK|A_PE_INVOKE, + /* S_TRANSITION_ENGINE ==> */ A_NODE_BLOCK|A_PE_INVOKE|A_TE_CANCEL, }, /* Got an I_NOT_DC */ { /* S_IDLE ==> */ O_RELEASE|A_DC_TIMER_START, /* S_ELECTION ==> */ A_LOG|A_DC_TIMER_START, /* S_INTEGRATION ==> */ O_RELEASE|A_DC_TIMER_START, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ O_RELEASE|A_DC_TIMER_START, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ O_RELEASE|A_DC_TIMER_START, /* S_RELEASE_DC ==> */ O_RELEASE|A_DC_TIMER_START, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_DC_TIMER_START, }, /* Got an I_RECOVERED */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_DC_TIMER_START, /* S_RECOVERY_DC ==> */ A_JOIN_WELCOME_ALL|A_PE_INVOKE, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, }, /* Got an I_RELEASE_FAIL */ { /* S_IDLE ==> */ A_WARN|O_SHUTDOWN, /* S_ELECTION ==> */ A_WARN|O_SHUTDOWN, /* S_INTEGRATION ==> */ A_WARN|O_SHUTDOWN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ O_SHUTDOWN, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN|O_SHUTDOWN, /* S_RELEASE_DC ==> */ O_SHUTDOWN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN|O_SHUTDOWN, /* S_TERMINATE ==> */ A_WARN|O_SHUTDOWN, /* S_TRANSITION_ENGINE ==> */ A_WARN|O_SHUTDOWN, }, /* Got an I_RELEASE_SUCCESS */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, }, /* Got an I_RESTART */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_LOG|A_ELECTION_TIMEOUT|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_LOG|A_JOIN_WELCOME_ALL|A_PE_INVOKE, /* S_NOT_DC ==> */ A_LOG|A_NOTHING, /* S_POLICY_ENGINE ==> */ A_LOG|A_PE_INVOKE, /* S_RECOVERY ==> */ A_LOG|A_RECOVER, /* S_RECOVERY_DC ==> */ A_LOG|A_RECOVER, /* S_RELEASE_DC ==> */ A_LOG|O_RELEASE, /* S_PENDING ==> */ A_LOG|A_STARTUP, /* S_STOPPING ==> */ A_LOG|O_SHUTDOWN, /* S_TERMINATE ==> */ A_LOG|O_SHUTDOWN, /* S_TRANSITION_ENGINE ==> */ A_LOG|A_TE_INVOKE, }, /* Got an I_REQUEST */ { - /* S_IDLE ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_ELECTION ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_INTEGRATION ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_NOT_DC ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_POLICY_ENGINE ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_RECOVERY ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_RECOVERY_DC ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_RELEASE_DC ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_PENDING ==> */ A_MSG_STORE|A_MSG_PROCESS, - /* S_STOPPING ==> */ A_LOG|A_MSG_STORE|A_MSG_PROCESS, - /* S_TERMINATE ==> */ A_LOG|A_MSG_STORE|A_MSG_PROCESS, - /* S_TRANSITION_ENGINE ==> */ A_MSG_STORE|A_MSG_PROCESS, + /* S_IDLE ==> */ A_MSG_PROCESS, + /* S_ELECTION ==> */ A_MSG_PROCESS, + /* S_INTEGRATION ==> */ A_MSG_PROCESS, + /* S_NOT_DC ==> */ A_MSG_PROCESS, + /* S_POLICY_ENGINE ==> */ A_MSG_PROCESS, + /* S_RECOVERY ==> */ A_MSG_PROCESS, + /* S_RECOVERY_DC ==> */ A_MSG_PROCESS, + /* S_RELEASE_DC ==> */ A_MSG_PROCESS, + /* S_PENDING ==> */ A_MSG_PROCESS, + /* S_STOPPING ==> */ A_LOG|A_MSG_PROCESS, + /* S_TERMINATE ==> */ A_LOG|A_MSG_PROCESS, + /* S_TRANSITION_ENGINE ==> */ A_MSG_PROCESS, }, /* Got an I_ROUTER */ { /* S_IDLE ==> */ A_MSG_ROUTE, /* S_ELECTION ==> */ A_MSG_ROUTE, /* S_INTEGRATION ==> */ A_MSG_ROUTE, /* S_NOT_DC ==> */ A_MSG_ROUTE, /* S_POLICY_ENGINE ==> */ A_MSG_ROUTE, /* S_RECOVERY ==> */ A_MSG_ROUTE, /* S_RECOVERY_DC ==> */ A_MSG_ROUTE, /* S_RELEASE_DC ==> */ A_MSG_ROUTE, /* S_PENDING ==> */ A_MSG_ROUTE, /* S_STOPPING ==> */ A_MSG_ROUTE, /* S_TERMINATE ==> */ A_MSG_ROUTE, /* S_TRANSITION_ENGINE ==> */ A_MSG_ROUTE, }, /* Got an I_SHUTDOWN */ { /* S_IDLE ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_ELECTION ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_INTEGRATION ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_RECOVERY ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_RECOVERY_DC ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_PENDING ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_STOPPING ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_TERMINATE ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_TRANSITION_ENGINE ==> */ A_DC_TIMER_STOP|O_RELEASE, }, /* Got an I_TERMINATE */ { /* S_IDLE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_ELECTION ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_INTEGRATION ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_RECOVERY ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_RECOVERY_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_PENDING ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_STOPPING ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_TERMINATE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_TRANSITION_ENGINE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, }, /* Got an I_STARTUP */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_LOG|A_STARTUP|A_CIB_START|A_LRM_CONNECT|A_CCM_CONNECT|A_HA_CONNECT|A_DC_TIMER_START, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, }, /* Got an I_SUCCESS */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_LOG|A_PE_INVOKE|A_CIB_INVOKE, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_LOG|A_TE_INVOKE, /* S_RECOVERY ==> */ A_RECOVER|A_LOG, /* S_RECOVERY_DC ==> */ A_RECOVER|A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_LOG, }, /* Got an I_WELCOME */ { /* S_IDLE ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_ELECTION ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_INTEGRATION ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_NOT_DC ==> */ O_DC_TICKLE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_POLICY_ENGINE ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_RECOVERY ==> */ A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_RECOVERY_DC ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_RELEASE_DC ==> */ A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_PENDING ==> */ O_DC_TICKLE|A_UPDATE_NODESTATUS|A_JOIN_ACK|A_STARTED|A_UPDATE_NODESTATUS, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, }, /* Got an I_WELCOME_ACK */ { /* S_IDLE ==> */ A_JOIN_PROCESS_ACK, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_JOIN_PROCESS_ACK, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_JOIN_PROCESS_ACK, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_JOIN_PROCESS_ACK, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_JOIN_PROCESS_ACK, }, /* Got an I_WAIT_FOR_EVENT */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_LOG, /* S_NOT_DC ==> */ A_LOG, /* S_POLICY_ENGINE ==> */ A_LOG, /* S_RECOVERY ==> */ A_LOG, /* S_RECOVERY_DC ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_LOG, }, /* Got an I_DC_HEARTBEAT */ { /* S_IDLE ==> */ A_WARN|A_ELECTION_VOTE, /* S_ELECTION ==> */ A_WARN|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_WARN|A_ELECTION_VOTE, /* S_NOT_DC ==> */ O_DC_TICKLE, /* S_POLICY_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, /* S_RECOVERY ==> */ A_NOTHING|O_DC_TICKLE, /* S_RECOVERY_DC ==> */ A_WARN|O_RELEASE|A_DC_TIMER_START, /* S_RELEASE_DC ==> */ A_LOG|A_DC_TIMER_START, /* S_PENDING ==> */ A_LOG|O_DC_TICKLE|A_ANNOUNCE, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, }, /* Got an I_LRM_EVENT */ { /* S_IDLE ==> */ A_LRM_EVENT, /* S_ELECTION ==> */ A_LRM_EVENT, /* S_INTEGRATION ==> */ A_LRM_EVENT, /* S_NOT_DC ==> */ A_LRM_EVENT, /* S_POLICY_ENGINE ==> */ A_LRM_EVENT, /* S_RECOVERY ==> */ A_LRM_EVENT, /* S_RECOVERY_DC ==> */ A_LRM_EVENT, /* S_RELEASE_DC ==> */ A_LRM_EVENT, /* S_PENDING ==> */ A_LRM_EVENT, /* S_STOPPING ==> */ A_LRM_EVENT, /* S_TERMINATE ==> */ A_LRM_EVENT, /* S_TRANSITION_ENGINE ==> */ A_LRM_EVENT, }, }; #endif diff --git a/crm/crmd/fsa_proto.h b/crm/crmd/fsa_proto.h index fa62ed9a4e..4828cc6a67 100644 --- a/crm/crmd/fsa_proto.h +++ b/crm/crmd/fsa_proto.h @@ -1,320 +1,328 @@ -/* $Id: fsa_proto.h,v 1.6 2004/04/12 15:34:50 andrew Exp $ */ +/* $Id: fsa_proto.h,v 1.7 2004/05/10 21:52:57 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 XML_FSA_PROTO__H #define XML_FSA_PROTO__H /* A_ANNOUNCE */ enum crmd_fsa_input do_announce(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data); /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data); /* A_ERROR */ enum crmd_fsa_input do_error(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LOG */ enum crmd_fsa_input do_log(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STARTUP */ enum crmd_fsa_input do_startup(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CIB_START, STOP, RESTART */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_HA_CONNECT */ enum crmd_fsa_input do_ha_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_CONNECT */ enum crmd_fsa_input do_ccm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* 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 cur_input, void *data); /* A_PE_START, STOP, RESTART */ enum crmd_fsa_input do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_TE_START, STOP, RESTART */ enum crmd_fsa_input do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STARTED */ enum crmd_fsa_input do_started(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_MSG_ROUTE */ enum crmd_fsa_input do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_RECOVER */ enum crmd_fsa_input do_recover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECTION_VOTE */ enum crmd_fsa_input do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECTION_COUNT */ enum crmd_fsa_input do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */ enum crmd_fsa_input do_election_timer_ctrl(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_TIMER_STOP */ enum crmd_fsa_input do_dc_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_MSG_STORE */ enum crmd_fsa_input do_msg_store(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_NODE_BLOCK */ enum crmd_fsa_input do_node_block(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_UPDATE_CACHE */ enum crmd_fsa_input do_ccm_update_cache(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_EVENT */ enum crmd_fsa_input do_ccm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_TAKEOVER */ enum crmd_fsa_input do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_RELEASE */ enum crmd_fsa_input do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_WELCOME_ALL */ enum crmd_fsa_input do_send_welcome(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_WELCOME */ enum crmd_fsa_input do_send_welcome(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_ACK */ enum crmd_fsa_input do_ack_welcome(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_PROCESS_ACK */ enum crmd_fsa_input do_process_welcome_ack(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CIB_INVOKE */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* 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 cur_input, void *data); /* A_LRM_EVENT */ 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, void *data); /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); -/* A_TE_INVOKE */ +/* A_TE_INVOKE, A_TE_CANCEL */ enum crmd_fsa_input do_te_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); +/* A_TE_INVOKE */ +enum crmd_fsa_input +do_te_copyto(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input cur_input, + void *data); + /* A_SHUTDOWN_REQ */ enum crmd_fsa_input do_shutdown_req(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_SHUTDOWN */ enum crmd_fsa_input do_shutdown(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STOP */ enum crmd_fsa_input do_stop(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_EXIT_0, A_EXIT_1 */ enum crmd_fsa_input do_exit(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); #endif diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c index bca71910a2..2bceb701f5 100644 --- a/crm/crmd/messages.c +++ b/crm/crmd/messages.c @@ -1,848 +1,865 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include FILE *msg_in_strm = NULL; FILE *router_strm = NULL; fsa_message_queue_t fsa_message_queue = NULL; gboolean relay_message(xmlNodePtr xml_relay_message, gboolean originated_locally); #ifdef MSG_LOG # define ROUTER_RESULT(x) char *msg_text = dump_xml(xml_relay_message);\ if(router_strm == NULL) { \ router_strm = fopen("/tmp/router.log", "w"); \ } \ fprintf(router_strm, "[%d RESULT (%s)]\t%s\t%s\n", \ AM_I_DC, \ xmlGetProp(xml_relay_message, XML_ATTR_REFERENCE),\ x, msg_text); \ fflush(router_strm); \ cl_free(msg_text); #else # define ROUTER_RESULT(x) CRM_DEBUG(x); #endif /* returns the current head of the FIFO queue */ fsa_message_queue_t put_message(xmlNodePtr new_message) { fsa_message_queue_t next_message = (fsa_message_queue_t) cl_malloc(sizeof(struct fsa_message_queue_s)); CRM_DEBUG("Adding msg to queue"); next_message->message = new_message; next_message->next = NULL; if(fsa_message_queue == NULL) { fsa_message_queue = next_message; } else { fsa_message_queue->next = next_message; } CRM_DEBUG("Added msg to queue"); return fsa_message_queue; } /* returns the next message */ fsa_message_queue_t get_message(void) { fsa_message_queue_t next_message = NULL; if(fsa_message_queue != NULL) { next_message = fsa_message_queue; fsa_message_queue = fsa_message_queue->next; next_message->next = NULL; } return next_message; } /* returns the current head of the FIFO queue */ gboolean is_message(void) { return (fsa_message_queue != NULL && fsa_message_queue->message != NULL); } /* A_MSG_STORE */ enum crmd_fsa_input do_msg_store(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { // xmlNodePtr new_message = (xmlNodePtr)data; FNIN(); // put_message(new_message); FNRET(I_NULL); } /* A_MSG_ROUTE */ enum crmd_fsa_input do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; xmlNodePtr xml_message = (xmlNodePtr)data; gboolean routed = FALSE, defer = TRUE, do_process = TRUE; FNIN(); #if 0 // if(cause == C_IPC_MESSAGE) { if (crmd_authorize_message(root_xml_node, msg, curr_client) == FALSE) { CRM_DEBUG("Message not authorized"); do_process = FALSE; } // } #endif if(do_process) { /* try passing the buck first */ routed = relay_message(xml_message, cause==C_IPC_MESSAGE); if(routed == FALSE) { defer = TRUE; /* calculate defer */ result = handle_message(xml_message); switch(result) { case I_NULL: defer = FALSE; break; case I_DC_HEARTBEAT: defer = FALSE; break; /* what else should go here? */ default: CRM_DEBUG("Defering local processing of message"); put_message(xml_message); result = I_REQUEST; break; } } } FNRET(result); } void crmd_ha_input_callback(const struct ha_msg* msg, void* private_data) { const char *from = ha_msg_value(msg, F_ORIG); const char *to = NULL; xmlNodePtr root_xml_node; FNIN(); #ifdef MSG_LOG if(msg_in_strm == NULL) { msg_in_strm = fopen("/tmp/inbound.log", "w"); } #endif if(from == NULL || strcmp(from, fsa_our_uname) == 0) { #ifdef MSG_LOG fprintf(msg_in_strm, "Discarded message [F_SEQ=%s] from ourselves.\n", ha_msg_value(msg, F_SEQ)); #endif FNOUT(); } #ifdef MSG_LOG fprintf(msg_in_strm, "[%s (%s:%s)]\t%s\n", from, ha_msg_value(msg, F_SEQ), ha_msg_value(msg, F_TYPE), ha_msg_value(msg, "xml") ); fflush(msg_in_strm); #endif root_xml_node = find_xml_in_hamessage(msg); to = xmlGetProp(root_xml_node, XML_ATTR_HOSTTO); 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.", - ha_msg_value(msg, F_SEQ)); + fprintf(msg_in_strm, + "Discarding message [F_SEQ=%s] for someone else.", + ha_msg_value(msg, F_SEQ)); #endif FNOUT(); } set_xml_property_copy(root_xml_node, XML_ATTR_HOSTFROM, from); s_crmd_fsa(C_HA_MESSAGE, I_ROUTER, root_xml_node); free_xml(root_xml_node); FNOUT(); } /* * Apparently returning TRUE means "stay connected, keep doing stuff". * Returning FALSE means "we're all done, close the connection" */ gboolean crmd_ipc_input_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; FNIN(); CRM_DEBUG("Processing IPC message from %s", curr_client->table_key); 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:"); FNRET(!hack_return_good); } if (msg == NULL) { CRM_DEBUG("No message this time"); continue; } lpc++; buffer = (char*)msg->msg_body; CRM_DEBUG("Processing xml from %s [text=%s]", curr_client->table_key, buffer); root_xml_node = find_xml_in_ipcmessage(msg, FALSE); if (root_xml_node != NULL) { if (crmd_authorize_message(root_xml_node, msg, curr_client)) { CRM_DEBUG("Message authorized,about to relay"); s_crmd_fsa(C_IPC_MESSAGE, I_ROUTER, root_xml_node); } else { CRM_DEBUG("Message not authorized"); } } else { cl_log(LOG_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_DEBUG("Processed %d messages", lpc); if (client->ch_status == IPC_DISCONNECT) { cl_log(LOG_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_DEBUG("Client had not 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_DEBUG("crm_client was %s detached", det?"successfully":"not"); } cl_free(curr_client->table_key); cl_free(curr_client->sub_sys); cl_free(curr_client->uuid); cl_free(curr_client); } CRM_DEBUG("this client has now left the building."); FNRET(!hack_return_good); } FNRET(hack_return_good); } /* * This method adds a copy of xml_response_data */ gboolean send_request(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation, const char *host_to, const char *sys_to) { gboolean was_sent = FALSE; xmlNodePtr request = NULL; FNIN(); msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS, XML_ATTR_OP, operation, TRUE); request = create_request(msg_options, msg_data, host_to, sys_to, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL, NULL); // xml_message_debug(request, "Final request..."); was_sent = relay_message(request, TRUE); if(was_sent == FALSE) { put_message(request); } free_xml(request); FNRET(was_sent); } /* * This method adds a copy of xml_response_data */ gboolean store_request(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation, const char *host_to, const char *sys_to) { xmlNodePtr request = NULL; FNIN(); msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS, XML_ATTR_OP, operation, TRUE); request = create_request(msg_options, msg_data, host_to, sys_to, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL, NULL); put_message(request); FNRET(TRUE); } gboolean relay_message(xmlNodePtr xml_relay_message, gboolean originated_locally) { int is_for_dc = 0; int is_for_dcib = 0; int is_for_crm = 0; int is_for_cib = 0; int is_local = 0; gboolean dont_cc= TRUE; gboolean processing_complete = FALSE; - const char *host_to = xmlGetProp(xml_relay_message, XML_ATTR_HOSTTO); - const char *sys_to = xmlGetProp(xml_relay_message, XML_ATTR_SYSTO); - const char *sys_cc = get_xml_attr(xml_relay_message, XML_TAG_OPTIONS, - XML_ATTR_SYSCC, FALSE); + const char *host_to = xmlGetProp(xml_relay_message,XML_ATTR_HOSTTO); + const char *sys_to = xmlGetProp(xml_relay_message,XML_ATTR_SYSTO); FNIN(); if(xml_relay_message == NULL) { cl_log(LOG_ERR, "Cannot route empty message"); FNRET(TRUE); } if(strcmp("hello", xml_relay_message->name) == 0) { /* quietly ignore */ FNRET(TRUE); } if(strcmp(XML_MSG_TAG, xml_relay_message->name) != 0) { xml_message_debug(xml_relay_message, "Bad message type, should be crm_message"); cl_log(LOG_ERR, "Ignoring message of type %s", xml_relay_message->name); FNRET(TRUE); } if(sys_to == NULL) { xml_message_debug(xml_relay_message, "Message did not have any value for sys_to"); cl_log(LOG_ERR, "Message did not have any value for %s", XML_ATTR_SYSTO); FNRET(TRUE); } is_for_dc = (strcmp(CRM_SYSTEM_DC, sys_to) == 0); is_for_dcib = (strcmp(CRM_SYSTEM_DCIB, sys_to) == 0); is_for_cib = (strcmp(CRM_SYSTEM_CIB, sys_to) == 0); is_for_crm = (strcmp(CRM_SYSTEM_CRMD, sys_to) == 0); is_local = 0; if(host_to == NULL || strlen(host_to) == 0) { if(is_for_dc) is_local = 0; else if(is_for_crm && originated_locally) is_local = 0; else is_local = 1; } else if(strcmp(fsa_our_uname, host_to) == 0) { is_local=1; } #if 0 CRM_DEBUG("is_local %d", is_local); CRM_DEBUG("is_for_dcib %d", is_for_dcib); CRM_DEBUG("is_for_dc %d", is_for_dc); CRM_DEBUG("is_for_crm %d", is_for_crm); CRM_DEBUG("AM_I_DC %d", AM_I_DC); CRM_DEBUG("sys_to %s", sys_to); CRM_DEBUG("host_to %s", host_to); #endif -/* - if(AM_I_DC && sys_cc != NULL && strcmp(sys_cc, CRM_SYSTEM_DC) == 0) { - dont_cc = FALSE; - } -*/ - (void)sys_cc; if(is_for_dc || is_for_dcib) { if(AM_I_DC) { ROUTER_RESULT("Message result: DC/CRMd process"); processing_complete = FALSE; // more to be done by caller } else if(originated_locally) { ROUTER_RESULT("Message result: External relay to DC"); send_msg_via_ha(xml_relay_message, NULL); processing_complete = TRUE; } else { ROUTER_RESULT("Message result: Discard, not DC"); processing_complete = TRUE; // discard } } else if(is_local && (is_for_crm || is_for_cib)) { ROUTER_RESULT("Message result: CRMd process"); } else if(is_local) { if(dont_cc) { ROUTER_RESULT("Message result: Local relay"); } else { /* The DC should also get this message */ ROUTER_RESULT("Message result: Local relay with CC"); } send_msg_via_ipc(xml_relay_message, sys_to); processing_complete = TRUE & dont_cc; } else { if(dont_cc) { ROUTER_RESULT("Message result: External relay"); } else { /* The DC should also get this message */ ROUTER_RESULT("Message result: External relay with CC"); } send_msg_via_ha(xml_relay_message, host_to); processing_complete = TRUE & dont_cc; } FNRET(processing_complete); } void send_msg_via_ha(xmlNodePtr action, const char *dest_node) { FNIN(); if (action == NULL) FNOUT(); if (validate_crm_message(action, NULL, NULL, NULL) == NULL) { cl_log(LOG_ERR, "Relay message to (%s) via HA was invalid, ignoring", dest_node); FNOUT(); } // CRM_DEBUG("Relaying message to (%s) via HA", dest_node); set_xml_property_copy(action, XML_ATTR_HOSTTO, dest_node); send_xmlha_message(fsa_cluster_conn, action); FNOUT(); } void send_msg_via_ipc(xmlNodePtr action, const char *sys) { IPC_Channel *client_channel; FNIN(); // cl_log(LOG_DEBUG, "relaying msg to sub_sys=%s via IPC", sys); client_channel = (IPC_Channel*)g_hash_table_lookup (ipc_clients, sys); if (client_channel != NULL) { cl_log(LOG_DEBUG, "Sending message via channel %s.", sys); send_xmlipc_message(client_channel, action); } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_CIB) == 0) { cl_log(LOG_ERR, "Sub-system (%s) has been incorporated into the CRMd.", sys); xml_message_debug(action, "Change the way we handle"); relay_message(process_cib_message(action, TRUE), TRUE); } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) { do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, action); } else { cl_log(LOG_ERR, "Unknown Sub-system (%s)... discarding message.", sys); } FNOUT(); } gboolean crmd_authorize_message(xmlNodePtr root_xml_node, IPC_Message *client_msg, crmd_client_t *curr_client) { // check the best case first const char *sys_from = xmlGetProp(root_xml_node, XML_ATTR_SYSFROM); char *uuid = NULL; char *client_name = NULL; char *major_version = NULL; char *minor_version = NULL; const char *filtered_from; gpointer table_key = NULL; gboolean result; FNIN(); if (sys_from != NULL) { gboolean can_reply = FALSE; // no-one has registered with this id filtered_from = sys_from; /* The CIB can have two names on the DC */ if(strcmp(sys_from, CRM_SYSTEM_DCIB) == 0) filtered_from = CRM_SYSTEM_CIB; if (g_hash_table_lookup (ipc_clients, filtered_from) != NULL) can_reply = TRUE; // reply can be routed CRM_DEBUG("Message reply can%s be routed from %s.", can_reply?"":" not", sys_from); FNRET(can_reply); } // otherwise, check if it was a hello message cl_log(LOG_INFO, "received client join msg: %s", (char*)client_msg->msg_body); result = process_hello_message(client_msg, - &uuid, - &client_name, - &major_version, - &minor_version); + &uuid, + &client_name, + &major_version, + &minor_version); if (result == TRUE) { // check version int mav = atoi(major_version); int miv = atoi(minor_version); if (mav < 0 || miv < 0) { cl_log(LOG_ERR, "Client version (%d:%d) is not acceptable", mav, miv); result = FALSE; } cl_free(major_version); cl_free(minor_version); } + struct crm_subsystem_s *the_subsystem = NULL; + if (result == TRUE) { /* if we already have one of those clients * only applies to te, pe etc. not admin clients */ - struct crm_subsystem_s *the_subsystem = NULL; if (client_name == NULL) CRM_DEBUG("Client had not registered with us yet"); else if (strcmp(CRM_SYSTEM_PENGINE, client_name) == 0) the_subsystem = pe_subsystem; else if (strcmp(CRM_SYSTEM_TENGINE, client_name) == 0) the_subsystem = te_subsystem; else if (strcmp(CRM_SYSTEM_CIB, client_name) == 0) the_subsystem = cib_subsystem; if (the_subsystem != NULL) { // do we already have one? - result = (fsa_input_register & the_subsystem->flag) == 0; - set_bit_inplace(&fsa_input_register, the_subsystem->flag); - + result =(fsa_input_register & the_subsystem->flag)==0; if(result) { - the_subsystem->ipc = curr_client->client_channel; + the_subsystem->ipc = + curr_client->client_channel; + } // else we didnt ask for the client to start } else if(client_name != NULL && uuid != NULL) { table_key = (gpointer) generate_hash_key(client_name, uuid); } else { result = FALSE; - cl_log(LOG_ERR, "Bad client details (client_name=%s, uuid=%s)", + cl_log(LOG_ERR, + "Bad client details (client_name=%s, uuid=%s)", client_name, uuid); } - } if(result == TRUE && table_key == NULL) table_key = (gpointer)cl_strdup(client_name); if (result == TRUE) { cl_log(LOG_INFO, "Accepted client %s", (char*)table_key); curr_client->table_key = table_key; curr_client->sub_sys = cl_strdup(client_name); curr_client->uuid = cl_strdup(uuid); g_hash_table_insert (ipc_clients, table_key, curr_client->client_channel); send_hello_message(curr_client->client_channel, "n/a", CRM_SYSTEM_CRMD, "0", "1"); + + cl_log(LOG_INFO, "Updated client list with %s", + (char*)table_key); + + if(the_subsystem != NULL) { + set_bit_inplace(&fsa_input_register, + the_subsystem->flag); + } + + s_crmd_fsa(C_SUBSYSTEM_CONNECT, I_NULL, NULL); + } else { cl_log(LOG_ERR, "Rejected client logon request"); curr_client->client_channel->ch_status = IPC_DISC_PENDING; } if(uuid != NULL) cl_free(uuid); if(client_name != NULL) cl_free(client_name); /* hello messages should never be processed further */ FNRET(FALSE); } enum crmd_fsa_input handle_message(xmlNodePtr stored_msg) { enum crmd_fsa_input next_input = I_NULL; const char *sys_to = get_xml_attr(stored_msg, NULL, XML_ATTR_SYSTO, TRUE); // const char *sys_from = get_xml_attr(stored_msg, NULL, // XML_ATTR_SYSFROM, TRUE); const char *type = get_xml_attr(stored_msg, NULL, XML_ATTR_MSGTYPE, TRUE); const char *op = get_xml_attr(stored_msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); // xml_message_debug(stored_msg, "Processing message"); if(type == NULL || op == NULL) { cl_log(LOG_ERR, "Ignoring message (type=%s), (op=%s)", type, op); xml_message_debug(stored_msg, "Bad message"); } else if(strcmp(type, XML_ATTR_REQUEST) == 0){ if(strcmp(op, CRM_OPERATION_VOTE) == 0) { next_input = I_ELECTION; + } else if(AM_I_DC && strcmp(op, "te_abort") == 0) { + next_input = I_PE_CALC; + + } else if(AM_I_DC + && fsa_state == S_TRANSITION_ENGINE + && strcmp(op, "te_complete") == 0) { + next_input = I_SUCCESS; + } else if(strcmp(op, CRM_OPERATION_HBEAT) == 0) { next_input = I_DC_HEARTBEAT; } else if(strcmp(op, CRM_OPERATION_WELCOME) == 0) { next_input = I_WELCOME; } else if(strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0) { next_input = I_CIB_OP; } else if(strcmp(op, CRM_OPERATION_SHUTDOWN) == 0) { next_input = I_TERMINATE; } else if(strcmp(op, CRM_OPERATION_ANNOUNCE) == 0) { next_input = I_NODE_JOIN; } else if(strcmp(op, CRM_OPERATION_REPLACE) == 0 || strcmp(op, CRM_OPERATION_ERASE) == 0) { next_input = I_CIB_OP; fprintf(router_strm, "Message result: CIB Op\n"); } else if(AM_I_DC && (strcmp(op, CRM_OPERATION_CREATE) == 0 || strcmp(op, CRM_OPERATION_UPDATE) == 0 || strcmp(op, CRM_OPERATION_DELETE) == 0)) { /* updates should only be performed on the DC */ next_input = I_CIB_OP; } else if(strcmp(op, CRM_OPERATION_PING) == 0) { /* eventually do some stuff to figure out * if we /are/ ok */ xmlNodePtr ping = createPingAnswerFragment(sys_to, "ok"); xmlNodePtr wrapper = create_reply(stored_msg, ping); relay_message(wrapper, TRUE); free_xml(wrapper); } else { cl_log(LOG_ERR, "Unexpected request (op=%s) sent to the %s", op, AM_I_DC?"DC":"CRMd"); } } else if(strcmp(type, XML_ATTR_RESPONSE) == 0) { if(strcmp(op, CRM_OPERATION_WELCOME) == 0) { next_input = I_WELCOME_ACK; + } else if(strcmp(op, "pecalc") == 0) { + // results int eh TE being invoked + next_input = I_SUCCESS; + } else if(strcmp(op, CRM_OPERATION_VOTE) == 0 || strcmp(op, CRM_OPERATION_HBEAT) == 0 || strcmp(op, CRM_OPERATION_WELCOME) == 0 || strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OPERATION_SHUTDOWN) == 0 || strcmp(op, CRM_OPERATION_ANNOUNCE) == 0) { next_input = I_NULL; /* } else if(AM_I_DC */ /* && (strcmp(op, CRM_OPERATION_CREATE) == 0 */ /* || strcmp(op, CRM_OPERATION_UPDATE) == 0 */ /* || strcmp(op, CRM_OPERATION_DELETE) == 0 */ /* || strcmp(op, CRM_OPERATION_REPLACE) == 0 */ /* || strcmp(op, CRM_OPERATION_ERASE) == 0)) { */ /* // perhaps we should do somethign with these replies */ /* fprintf(router_strm, "Message result: CIB Reply\n"); */ } else { cl_log(LOG_ERR, "Unexpected response (op=%s) sent to the %s", op, AM_I_DC?"DC":"CRMd"); next_input = I_NULL; } } else { cl_log(LOG_ERR, "Unexpected message type %s", type); } /* CRM_DEBUG("%s: Next input is %s", __FUNCTION__, */ /* fsa_input2string(next_input)); */ return next_input; } void lrm_op_callback (lrm_op_t* op) { CRM_DEBUG("In lrm_op_callback()"); s_crmd_fsa(C_LRM_OP_CALLBACK, I_LRM_EVENT, op); } void lrm_monitor_callback (lrm_mon_t* monitor) { CRM_DEBUG("In lrm_monitor_callback()"); s_crmd_fsa(C_LRM_MONITOR_CALLBACK, I_LRM_EVENT, monitor); } diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c index 33c24c48de..f28c27abff 100644 --- a/crm/crmd/subsystems.c +++ b/crm/crmd/subsystems.c @@ -1,1069 +1,1174 @@ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include // for access #include #include #include // for calls to open #include // for calls to open #include // for calls to open #include // for getpwuid #include // for initgroups #include // for getrlimit #include // for getrlimit #include #include #include #include #include #include #include #include #include #include #include #define CLIENT_EXIT_WAIT 10 static gboolean stop_subsystem (struct crm_subsystem_s *centry); static gboolean start_subsystem(struct crm_subsystem_s *centry); static gboolean run_command (struct crm_subsystem_s *centry, const char *options, gboolean update_pid); xmlNodePtr do_lrm_query(void); GHashTable *xml2list(xmlNodePtr parent, const char **attr_path, int depth); gboolean lrm_dispatch(int fd, gpointer user_data); void do_update_resource(lrm_rsc_t *rsc, int status, int rc, const char *op_type); struct crm_subsystem_s *cib_subsystem = NULL; struct crm_subsystem_s *te_subsystem = NULL; struct crm_subsystem_s *pe_subsystem = NULL; void cleanup_subsystem(struct crm_subsystem_s *the_subsystem) { int pid_status = -1; the_subsystem->ipc = NULL; clear_bit_inplace(&fsa_input_register, the_subsystem->flag); /* Forcing client to die */ kill(the_subsystem->pid, -9); // cleanup the ps entry waitpid(the_subsystem->pid, &pid_status, WNOHANG); the_subsystem->pid = -1; } /* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = cib_subsystem; long long stop_actions = A_CIB_STOP; long long start_actions = A_CIB_START; FNIN(); if(action & stop_actions) { // dont do anything, its embedded now } if(action & start_actions) { if(cur_state != S_STOPPING) { if(startCib(CIB_FILENAME) == FALSE) result = I_FAIL; } else { cl_log(LOG_INFO, "Ignoring request to start %s after shutdown", this_subsys->command); } } FNRET(result); } /* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr cib_msg = NULL; xmlNodePtr answer = NULL; xmlNodePtr tmp1 = NULL; xmlNodePtr tmp2 = NULL; xmlNodePtr new_options = NULL; const char *req_from; const char *section = NULL; FNIN(); if(data != NULL) cib_msg = (xmlNodePtr)data; if(action & A_CIB_INVOKE) { const char *op = xmlGetProp(cib_msg, XML_ATTR_OP); if(safe_str_eq(op, CRM_OPERATION_SHUTDOWN_REQ)){ // create update section tmp2 = create_xml_node(NULL, XML_CIB_TAG_STATE); req_from = xmlGetProp(cib_msg, XML_ATTR_HOSTFROM); set_xml_property_copy(tmp1, "id", req_from); set_xml_property_copy(tmp1, "exp_state", "shutdown"); // create fragment tmp1 = create_cib_fragment(tmp2, NULL); // add to cib_msg add_node_copy(cib_msg, tmp1); free_xml(tmp2); free_xml(tmp1); } set_xml_property_copy(cib_msg, XML_ATTR_SYSTO, "cib"); answer = process_cib_message(cib_msg, TRUE); if(relay_message(answer, TRUE) == FALSE) { cl_log(LOG_ERR, "Confused what to do with cib result"); xml_message_debug(answer, "Couldnt route: "); } - if(AM_I_DC && (strcmp(op, CRM_OPERATION_CREATE) == 0 - || strcmp(op, CRM_OPERATION_UPDATE) == 0 - || strcmp(op, CRM_OPERATION_DELETE) == 0 - || strcmp(op, CRM_OPERATION_REPLACE) == 0 - || strcmp(op, CRM_OPERATION_WELCOME) == 0 - || strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0 - || strcmp(op, CRM_OPERATION_ERASE) == 0)) { + if(op != NULL && AM_I_DC + && (strcmp(op, CRM_OPERATION_CREATE) == 0 + || strcmp(op, CRM_OPERATION_UPDATE) == 0 + || strcmp(op, CRM_OPERATION_DELETE) == 0 + || strcmp(op, CRM_OPERATION_REPLACE) == 0 + || strcmp(op, CRM_OPERATION_WELCOME) == 0 + || strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0 + || strcmp(op, CRM_OPERATION_ERASE) == 0)) { FNRET(I_CIB_UPDATE); } + + if(op == NULL) { + xml_message_debug(cib_msg, "Invalid CIB Message"); + } + // check the answer, see if we are interested in it also #if 0 if(interested in reply) { put_message(answer); FNRET(I_REQUEST); } #endif free_xml(answer); /* experimental */ } else if(action & A_CIB_INVOKE_LOCAL) { answer = process_cib_message(cib_msg, TRUE); put_message(answer); FNRET(I_REQUEST); } else if(action & A_CIB_BUMPGEN) { // check if the response was ok before next bit section = get_xml_attr(cib_msg, XML_TAG_OPTIONS, - XML_ATTR_FILTER_TYPE, FALSE); + XML_ATTR_FILTER_TYPE, FALSE); /* set the section so that we dont always send the * whole thing */ if(section != NULL) { new_options = set_xml_attr(NULL, XML_TAG_OPTIONS, XML_ATTR_FILTER_TYPE, section, TRUE); } answer = process_cib_request(CRM_OPERATION_BUMP, - new_options, NULL); + new_options, NULL); free_xml(new_options); if(answer == NULL) { cl_log(LOG_ERR, "Result of BUMP in %s was NULL", __FUNCTION__); FNRET(I_FAIL); } send_request(NULL, answer, CRM_OPERATION_REPLACE, NULL, CRM_SYSTEM_CRMD); free_xml(answer); } else { cl_log(LOG_ERR, "Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } FNRET(I_NULL); } /* A_PE_START, A_PE_STOP, A_TE_RESTART */ enum crmd_fsa_input do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = pe_subsystem; long long stop_actions = A_PE_STOP; long long start_actions = A_PE_START; FNIN(); if(action & stop_actions) { if(stop_subsystem(this_subsys) == FALSE) result = I_FAIL; else if(this_subsys->pid > 0){ int lpc = CLIENT_EXIT_WAIT; int pid_status = -1; while(lpc-- > 0 && this_subsys->pid > 0 && CL_PID_EXISTS(this_subsys->pid)) { sleep(1); waitpid(this_subsys->pid, &pid_status, WNOHANG); } if(CL_PID_EXISTS(this_subsys->pid)) { cl_log(LOG_ERR, "Process %s is still active with pid=%d", this_subsys->command, this_subsys->pid); result = I_FAIL; } } cleanup_subsystem(this_subsys); } if(action & start_actions) { if(cur_state != S_STOPPING) { if(start_subsystem(this_subsys) == FALSE) { result = I_FAIL; cleanup_subsystem(this_subsys); } } else { cl_log(LOG_INFO, "Ignoring request to start %s while shutting down", this_subsys->command); } } FNRET(result); } /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { FNIN(); stopTimer(integration_timer); - cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", - fsa_action2string(action), action); + + if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){ + + cl_log(LOG_INFO, "Waiting for the PE to connect"); + FNRET(I_WAIT_FOR_EVENT); + + } + xmlNodePtr local_cib = get_cib_copy(); + + CRM_DEBUG("Invoking %s with %p", CRM_SYSTEM_PENGINE, local_cib); + + send_request(NULL, local_cib, "pecalc", + NULL, CRM_SYSTEM_PENGINE); + FNRET(I_NULL); } /* A_TE_START, A_TE_STOP, A_TE_RESTART */ enum crmd_fsa_input do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = te_subsystem; long long stop_actions = A_TE_STOP; long long start_actions = A_TE_START; FNIN(); /* if(action & stop_actions && cur_state != S_STOPPING */ /* && is_set(fsa_input_register, R_TE_PEND)) { */ /* result = I_WAIT_FOR_EVENT; */ /* FNRET(result); */ /* } */ if(action & stop_actions) { if(stop_subsystem(this_subsys) == FALSE) result = I_FAIL; else if(this_subsys->pid > 0){ int lpc = CLIENT_EXIT_WAIT; int pid_status = -1; while(lpc-- > 0 && this_subsys->pid > 0 && CL_PID_EXISTS(this_subsys->pid)) { sleep(1); waitpid(this_subsys->pid, &pid_status, WNOHANG); } if(CL_PID_EXISTS(this_subsys->pid)) { cl_log(LOG_ERR, "Process %s is still active with pid=%d", this_subsys->command, this_subsys->pid); result = I_FAIL; } } cleanup_subsystem(this_subsys); } if(action & start_actions) { if(cur_state != S_STOPPING) { if(start_subsystem(this_subsys) == FALSE) { result = I_FAIL; cleanup_subsystem(this_subsys); } } else { cl_log(LOG_INFO, "Ignoring request to start %s while shutting down", this_subsys->command); } } FNRET(result); } -/* A_TE_INVOKE */ +/* A_TE_COPYTO */ +enum crmd_fsa_input +do_te_copyto(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + xmlNodePtr message = copy_xml_node_recursive((xmlNodePtr)data); + xmlNodePtr opts = find_xml_node(message, "options"); + const char *true_op = xmlGetProp(opts, XML_ATTR_OP); + + FNIN(); + + set_xml_property_copy(opts, XML_ATTR_OP, "event"); + set_xml_property_copy(message, XML_ATTR_SYSTO, CRM_SYSTEM_TENGINE); + set_xml_property_copy(opts, "true_op", true_op); + + relay_message(message, FALSE); + + free_xml(message); + + FNRET(I_NULL); +} + +static xmlNodePtr te_last_input = NULL; + +/* A_TE_INVOKE, A_TE_CANCEL */ enum crmd_fsa_input do_te_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { + xmlNodePtr graph = NULL; + xmlNodePtr msg = (xmlNodePtr)data; FNIN(); - cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", - fsa_action2string(action), action); + if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){ + cl_log(LOG_INFO, "Waiting for the TE to connect"); + if(data != NULL) { + free_xml(te_last_input); + te_last_input = copy_xml_node_recursive(msg); + } + FNRET(I_WAIT_FOR_EVENT); + + } + + if(msg == NULL) { + msg = te_last_input; + } else { + free_xml(te_last_input); + } + + if(action & A_TE_INVOKE) { + graph = find_xml_node(msg, "transition_graph"); + if(graph == NULL) { + FNRET(I_FAIL); + } + + send_request(NULL, graph, "transition", + NULL, CRM_SYSTEM_TENGINE); + } else { + send_request(NULL, graph, "abort", + NULL, CRM_SYSTEM_TENGINE); + } + FNRET(I_NULL); } gboolean crmd_client_connect(IPC_Channel *client_channel, gpointer user_data) { FNIN(); CRM_DEBUG("A client tried to connect... and there was much rejoicing."); if (client_channel == NULL) { cl_log(LOG_ERR, "Channel was NULL"); } else if (client_channel->ch_status == IPC_DISCONNECT) { cl_log(LOG_ERR, "Channel was disconnected"); } else { crmd_client_t *blank_client = (crmd_client_t *)cl_malloc(sizeof(crmd_client_t)); if (blank_client == NULL) { cl_log(LOG_ERR, "Could not allocate memory for a blank crmd_client_t"); FNRET(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; CRM_DEBUG("Adding IPC Channel to main thread."); blank_client->client_source = G_main_add_IPC_Channel(G_PRIORITY_LOW, client_channel, FALSE, crmd_ipc_input_callback, blank_client, default_ipc_input_destroy); } FNRET(TRUE); } static gboolean stop_subsystem(struct crm_subsystem_s* centry) { cl_log(LOG_INFO, "Stopping sub-system \"%s\"", centry->name); if (centry->pid <= 0) { cl_log(LOG_ERR, "OOPS! client %s not running yet", centry->command); } else { cl_log(LOG_INFO, "Sending quit message to %s.", centry->name); send_request(NULL, NULL, "quit", NULL, centry->name); } return TRUE; } static gboolean start_subsystem(struct crm_subsystem_s* centry) { cl_log(LOG_INFO, "Starting sub-system \"%s\"", centry->command); if (centry->pid != 0) { cl_log(LOG_ERR, "OOPS! client %s already running as pid %d" , centry->command, (int) centry->pid); } return run_command(centry, "-r", TRUE); } static gboolean run_command(struct crm_subsystem_s *centry, const char *options, gboolean update_pid) { pid_t pid; struct stat buf; int s_res,size; char *cmd_with_options = NULL; /* * We need to ensure that the exec will succeed before * we bother forking. We don't want to respawn something that * won't exec in the first place. */ if (access(centry->path, F_OK|X_OK) != 0) { cl_perror("Cannot (access) exec %s", centry->path); return FALSE; } s_res = stat(centry->command, &buf); if(s_res != 0) { cl_perror("Cannot (stat) exec %s", centry->command); return FALSE; } /* We need to fork so we can make child procs not real time */ switch(pid=fork()) { case -1: cl_log(LOG_ERR , "start_a_child_client: Cannot fork."); return FALSE; default: /* Parent */ #if 0 NewTrackedProc(pid, 1, PT_LOGVERBOSE , centry, &ManagedChildTrackOps); #else if(update_pid) centry->pid = pid; #endif return TRUE; case 0: /* Child */ break; } /* Child process: start the managed child */ cl_make_normaltime(); setpgid(0,0); /* Limit peak resource usage, maximize success chances */ if (centry->shortrcount > 0) { alarm(0); sleep(1); } size = strlen(options); size += strlen(centry->command); size += 2; // ' ' + \0 cmd_with_options = cl_malloc((1+size)*sizeof(char)); sprintf(cmd_with_options, "%s %s", centry->command, options); cmd_with_options[size] = 0; cl_log(LOG_INFO, "Executing \"%s\" (pid %d)", cmd_with_options, (int) getpid()); if(CL_SIGINTERRUPT(SIGALRM, 0) < 0) { cl_perror("Cannot set interrupt for child process %s", cmd_with_options); }else{ const char * devnull = "/dev/null"; unsigned int j; struct rlimit oflimits; CL_SIGNAL(SIGCHLD, SIG_DFL); alarm(0); CL_IGNORE_SIG(SIGALRM); /* A precautionary measure */ getrlimit(RLIMIT_NOFILE, &oflimits); for (j=0; j < oflimits.rlim_cur; ++j) { close(j); } (void)devnull; (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ (void)execl("/bin/sh", "sh", "-c", cmd_with_options, (const char *)NULL); /* Should not happen */ cl_perror("Cannot exec %s", cmd_with_options); } /* Suppress respawning */ exit(100); // never reached return TRUE; } /* 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, - void *data) + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) { enum crmd_fsa_input failed = I_NULL;//I_FAIL; int ret = HA_OK; FNIN(); if(action & A_LRM_DISCONNECT) { fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); } if(action & A_LRM_CONNECT) { CRM_DEBUG("LRM: connect..."); fsa_lrm_conn = ll_lrm_new("lrm"); if(NULL == fsa_lrm_conn) { return failed; } CRM_DEBUG("LRM: sigon..."); ret = fsa_lrm_conn->lrm_ops->signon(fsa_lrm_conn, "crmd"); if(ret != HA_OK) { cl_log(LOG_ERR, "Failed to sign on to the LRM"); return failed; } CRM_DEBUG("LRM: set_lrm_callback..."); ret = fsa_lrm_conn->lrm_ops->set_lrm_callback(fsa_lrm_conn, lrm_op_callback, lrm_monitor_callback); if(ret != HA_OK) { cl_log(LOG_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_input_destroy); } if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) { cl_log(LOG_ERR, "Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } FNRET(I_NULL); } gboolean lrm_dispatch(int fd, gpointer user_data) { ll_lrm_t *lrm = (ll_lrm_t*)user_data; lrm->lrm_ops->rcvmsg(lrm, FALSE); return TRUE; } xmlNodePtr do_lrm_query(void) { GList* lrm_list = NULL; GList* element = NULL; GList* op_list = NULL; xmlNodePtr agent = NULL; xmlNodePtr data = create_xml_node(NULL, "lrm"); xmlNodePtr agent_list = create_xml_node(data, "lrm_agents"); xmlNodePtr rsc_list; char *rsc_type = NULL; state_flag_t cur_state = 0; const char *this_op = NULL; GList* node = NULL; lrm_list = fsa_lrm_conn->lrm_ops->get_ra_supported(fsa_lrm_conn); if (NULL != lrm_list) { GList* element = g_list_first(lrm_list); while (NULL != element) { rsc_type = (char*)element->data; agent = create_xml_node(agent_list, "lrm_agent"); set_xml_property_copy(agent, "class", rsc_type); /* we dont have these yet */ set_xml_property_copy(agent, "type", NULL); set_xml_property_copy(agent, "version", NULL); element = g_list_next(element); } } g_list_free(lrm_list); lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); rsc_list = create_xml_node(data, "lrm_resources"); if (NULL != lrm_list) { element = g_list_first(lrm_list); } while (NULL != element) { lrm_rsc_t *the_rsc = (lrm_rsc_t*)element->data; /* const char* ra_type; */ /* GHashTable* params; */ xmlNodePtr xml_rsc = create_xml_node(rsc_list, "rsc_state"); set_xml_property_copy(xml_rsc, "id", the_rsc->id); set_xml_property_copy(xml_rsc, "rsc_id", the_rsc->name); set_xml_property_copy(xml_rsc, "node_id",fsa_our_uname); CRM_DEBUG("get_cur_state..."); op_list = the_rsc->ops->get_cur_state(the_rsc, - &cur_state); + &cur_state); CRM_DEBUG("\tcurrent state:%s\n", - cur_state==LRM_RSC_IDLE?"Idel":"Busy"); + cur_state==LRM_RSC_IDLE?"Idel":"Busy"); node = g_list_first(op_list); while(NULL != node){ lrm_op_t* op = (lrm_op_t*)node->data; this_op = op->op_type; if(this_op == NULL || strcmp(this_op, "status") != 0){ const char *status_text = ""; switch(op->status) { case LRM_OP_DONE: status_text = "done"; break; case LRM_OP_CANCELLED: status_text = "cancelled"; break; case LRM_OP_TIMEOUT: status_text = "timeout"; break; case LRM_OP_NOTSUPPORTED: status_text = "not suported"; break; case LRM_OP_ERROR: status_text = "error"; break; } set_xml_property_copy(xml_rsc, "op_result", status_text); set_xml_property_copy(xml_rsc, "rsc_op", this_op); // we only want the last one break; } node = g_list_next(node); } element = g_list_next(element); } if (NULL != lrm_list) { g_list_free(lrm_list); } return data; } /* 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, - void *data) + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) { enum crmd_fsa_input next_input = I_NULL; xmlNodePtr fragment, tmp1; xmlNodePtr msg; const char *rsc_path[] = { "msg_data", "rsc_op", "resource", "instance_attributes", "parameters" }; const char *operation = NULL; rsc_id_t rid; const char *id_from_cib = NULL; const char *crm_op = NULL; lrm_rsc_t *rsc = NULL; lrm_mon_t* mon = NULL; lrm_op_t* op = NULL; FNIN(); +#ifdef USE_FAKE_LRM + msg = (xmlNodePtr)data; + + operation = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -3, + XML_ATTR_OP, TRUE); + + id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, + "id", TRUE); + + crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); + + + if(safe_str_eq(crm_op, "rsc_op")) { + + CRM_DEBUG("performing op %s...", operation); + + xmlNodePtr iter = create_xml_node(iter, "lrm_resource"); + + set_xml_property_copy(iter, XML_ATTR_ID, id_from_cib); + set_xml_property_copy(iter, "last_op", operation); + + if(safe_str_eq(operation, "start")){ + set_xml_property_copy(iter, "op_status", "started"); + } else { + set_xml_property_copy(iter, "op_status", "stopped"); + } + + set_xml_property_copy(iter, "op_code", "0"); + set_xml_property_copy(iter, "op_node", fsa_our_uname); + + send_request(NULL, iter, "event", + NULL, CRM_SYSTEM_TENGINE); + } + + FNRET(I_NULL); +#endif if(action & A_UPDATE_NODESTATUS) { xmlNodePtr data = do_lrm_query(); set_xml_property_copy(data, "replace_lrm", "true"); tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname); fragment = create_cib_fragment(tmp1, NULL); set_xml_property_copy(data, "replace_lrm", "true"); add_node_copy(tmp1, data); send_request(NULL, fragment, CRM_OPERATION_UPDATE, NULL, CRM_SYSTEM_DC); free_xml(fragment); free_xml(tmp1); free_xml(data); FNRET(next_input); } - - - cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", + cl_log(LOG_WARNING, "Action %s (%.16llx) only kind of supported\n", fsa_action2string(action), action); msg = (xmlNodePtr)data; - operation = get_xml_attr_nested(msg, - rsc_path, - DIMOF(rsc_path) -3, - "operation", TRUE); - + operation = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -3, + XML_ATTR_OP, TRUE); + + + id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, + "id", TRUE); - id_from_cib = get_xml_attr_nested(msg, - rsc_path, - DIMOF(rsc_path) -2, - "id", - TRUE); // only the first 16 chars are used by the LRM strncpy(rid, id_from_cib, 16); - - crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, "operation", TRUE); - - rsc = fsa_lrm_conn->lrm_ops->get_rsc( - fsa_lrm_conn, rid); + + 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 && strcmp(crm_op, "lrm_query") == 0) { xmlNodePtr data, tmp1, tmp2, reply; tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname); data = create_cib_fragment(tmp1, NULL); tmp2 = do_lrm_query(); add_node_copy(tmp1, tmp2); reply = create_reply(msg, data); relay_message(reply, TRUE); free_xml(data); free_xml(reply); free_xml(tmp2); free_xml(tmp1); } else if(operation != NULL && strcmp(operation, "monitor") == 0) { if(rsc == NULL) { cl_log(LOG_ERR, "Could not find resource to monitor"); FNRET(I_FAIL); } mon = g_new(lrm_mon_t, 1); mon->op_type = "status"; mon->params = NULL; mon->timeout = 0; mon->user_data = rsc; mon->mode = LRM_MONITOR_SET; mon->interval = 2; mon->target = 1; rsc->ops->set_monitor(rsc,mon); mon = g_new(lrm_mon_t, 1); } else if(operation != NULL) { if(rsc == NULL) { // add it to the list CRM_DEBUG("add_rsc..."); fsa_lrm_conn->lrm_ops->add_rsc( fsa_lrm_conn, rid, get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, "class", TRUE), get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, "type", TRUE), NULL); rsc = fsa_lrm_conn->lrm_ops->get_rsc( fsa_lrm_conn, rid); } if(rsc == NULL) { cl_log(LOG_ERR, "Could not add resource to LRM"); FNRET(I_FAIL); } // now do the op CRM_DEBUG("performing op %s...", operation); op = g_new(lrm_op_t, 1); op->op_type = operation; op->params = xml2list(msg, rsc_path, DIMOF(rsc_path)); op->timeout = 0; op->user_data = rsc; rsc->ops->perform_op(rsc, op); } FNRET(next_input); } GHashTable * xml2list(xmlNodePtr parent, const char**attr_path, int depth) { xmlNodePtr node_iter = NULL; GHashTable *nvpair_hash = g_hash_table_new(&g_str_hash, &g_str_equal); xmlNodePtr nvpair_list = find_xml_node_nested(parent, attr_path, depth); if(nvpair_list != NULL){ node_iter = nvpair_list->children; while(node_iter != NULL) { const char *key = xmlGetProp(node_iter, "name"); const char *value = xmlGetProp(node_iter, "value"); CRM_DEBUG("Added %s=%s", key, value); g_hash_table_insert (nvpair_hash, cl_strdup(key), cl_strdup(value)); node_iter = node_iter->next; } } return nvpair_hash; } void do_update_resource(lrm_rsc_t *rsc, int status, int rc, const char *op_type) { /* - - - - - - + + + + + + */ xmlNodePtr update, iter; char *tmp = NULL; xmlNodePtr fragment, tmp1; update = create_xml_node(NULL, "node_state"); set_xml_property_copy(update, XML_ATTR_ID, fsa_our_uname); iter = create_xml_node(update, "lrm"); iter = create_xml_node(iter, "lrm_resources"); iter = create_xml_node(iter, "lrm_resource"); set_xml_property_copy(iter, XML_ATTR_ID, rsc->id); set_xml_property_copy(iter, "last_op", op_type); tmp = crm_itoa(status); set_xml_property_copy(iter, "op_status", tmp); cl_free(tmp); tmp = crm_itoa(rc); set_xml_property_copy(iter, "op_code", tmp); cl_free(tmp); + set_xml_property_copy(iter, "op_node", fsa_our_uname); tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname); add_node_copy(tmp1, update); fragment = create_cib_fragment(tmp1, NULL); send_request(NULL, fragment, CRM_OPERATION_UPDATE, NULL, CRM_SYSTEM_DCIB); - + free_xml(fragment); free_xml(update); free_xml(tmp1); } 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, void *data) { FNIN(); if(cause == C_LRM_MONITOR_CALLBACK) { lrm_mon_t* monitor = (lrm_mon_t*)data; lrm_rsc_t* rsc = monitor->rsc; switch(monitor->status) { case LRM_OP_DONE: CRM_DEBUG("An LRM monitor operation passed"); FNRET(I_NULL); break; case LRM_OP_CANCELLED: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: case LRM_OP_ERROR: cl_log(LOG_ERR, "An LRM monitor operation failed" " or was aborted"); do_update_resource(rsc, monitor->status, monitor->rc, monitor->op_type); + break; } } else if(cause == C_LRM_OP_CALLBACK) { lrm_op_t* op = (lrm_op_t*)data; lrm_rsc_t* rsc = op->rsc; switch(op->status) { case LRM_OP_CANCELLED: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: case LRM_OP_ERROR: cl_log(LOG_ERR, "An LRM operation failed" " or was aborted"); // keep going case LRM_OP_DONE: do_update_resource(rsc, op->status, op->rc, op->op_type); break; } } else { FNRET(I_FAIL); } FNRET(I_NULL); } diff --git a/crm/pengine/messages.c b/crm/pengine/messages.c deleted file mode 100644 index d2c5218432..0000000000 --- a/crm/pengine/messages.c +++ /dev/null @@ -1,255 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -xmlNodePtr process_pe_message(xmlNodePtr msg); -xmlNodePtr do_calculations(xmlNodePtr msg); - -gboolean -pe_input_dispatch(IPC_Channel *sender, void *user_data) -{ - int lpc = 0; - char *buffer = NULL; - xmlDocPtr doc = NULL; - IPC_Message *msg = NULL; - gboolean all_is_well = TRUE; - xmlNodePtr answer = NULL, root_xml_node = NULL; - const char *sys_to; - const char *type; - - - FNIN(); - - while(sender->ops->is_message_pending(sender)) { - if (sender->ch_status == IPC_DISCONNECT) { - /* The message which was pending for us is that - * the IPC status is now IPC_DISCONNECT */ - break; - } - if (sender->ops->recv(sender, &msg) != IPC_OK) { - perror("Receive failure:"); - FNRET(!all_is_well); - } - if (msg == NULL) { - cl_log(LOG_ERR, "No message this time"); - continue; - } - - lpc++; - - /* the docs say only do this once, but in their code - * they do it every time! - */ -// xmlInitParser(); - - buffer = (char*)msg->msg_body; - cl_log(LOG_DEBUG, "Message %d [text=%s]", lpc, buffer); - doc = xmlParseMemory(cl_strdup(buffer), strlen(buffer)); - - if(doc == NULL) { - cl_log(LOG_INFO, - "XML Buffer was not valid...\n Buffer: (%s)", - buffer); - } - - root_xml_node = xmlDocGetRootElement(doc); - - sys_to= xmlGetProp(root_xml_node, XML_ATTR_SYSTO); - type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE); - if (root_xml_node == NULL) { - cl_log(LOG_ERR, "Root node was NULL!!"); - - } else if(sys_to == NULL) { - cl_log(LOG_ERR, "Value of %s was NULL!!", - XML_ATTR_SYSTO); - - } else if(type == NULL) { - cl_log(LOG_ERR, "Value of %s was NULL!!", - XML_ATTR_MSGTYPE); - - } else if(strcmp(type, XML_ATTR_REQUEST) != 0) { - cl_log(LOG_INFO, - "Message was a response not a request." - " Discarding"); - } else if (strcmp(sys_to, CRM_SYSTEM_PENGINE) == 0) { - answer = process_pe_message(root_xml_node); - if (send_xmlipc_message(sender, answer)==FALSE) - cl_log(LOG_WARNING, - "Cib answer could not be sent"); - } else { - cl_log(LOG_WARNING, - "Received a message destined for %s by mistake", - sys_to); - } - - if(answer != NULL) - free_xml(answer); - - msg->msg_done(msg); - msg = NULL; - } - - // clean up after a break - if(msg != NULL) - msg->msg_done(msg); - - if(root_xml_node != NULL) - free_xml(root_xml_node); - - CRM_DEBUG("Processed %d messages", lpc); - if (sender->ch_status == IPC_DISCONNECT) { - cl_log(LOG_ERR, "The server has left us: Shutting down...NOW"); - - exit(1); // shutdown properly later - - FNRET(!all_is_well); - } - FNRET(all_is_well); -} - -xmlNodePtr -process_pe_message(xmlNodePtr msg) -{ - const char *op = get_xml_attr (msg, XML_TAG_OPTIONS,XML_ATTR_OP, TRUE); - - if(op == NULL){ - // error - } else if(strcmp(op, "pecalc")) { - xmlNodePtr fragment = find_xml_node(msg, XML_TAG_FRAGMENT); - xmlNodePtr input_cib = find_xml_node(fragment, XML_TAG_CIB); - return do_calculations(input_cib); - } else if(strcmp(op, "quit")) { - cl_log(LOG_WARNING, "Received quit message, terminating"); - exit(0); - } - - return NULL; -} - -xmlNodePtr -do_calculations(xmlNodePtr cib_object) -{ - int lpc, lpc2; - - GSListPtr resources = NULL; - GSListPtr nodes = NULL; - GSListPtr node_constraints = NULL; - GSListPtr actions = NULL; - GSListPtr action_constraints = NULL; - GSListPtr stonith_list = NULL; - GSListPtr shutdown_list = NULL; - - GSListPtr colors = NULL; - GSListPtr action_sets = NULL; - - xmlNodePtr graph = NULL; - - pdebug("=#=#=#=#= Stage 0 =#=#=#=#="); - - stage0(cib_object, - &resources, - &nodes, &node_constraints, - &actions, &action_constraints, - &stonith_list, &shutdown_list); - - pdebug("=#=#=#=#= Stage 1 =#=#=#=#="); - stage1(node_constraints, nodes, resources); - - pdebug("=#=#=#=#= Stage 2 =#=#=#=#="); - stage2(resources, nodes, &colors); - - pdebug("========= Nodes ========="); - pdebug_action( - slist_iter(node, node_t, nodes, lpc, - print_node(NULL, node, TRUE) - ) - ); - - pdebug("========= Resources ========="); - pdebug_action( - slist_iter(resource, resource_t, resources, lpc, - print_resource(NULL, resource, TRUE) - ) - ); - - pdebug("=#=#=#=#= Stage 3 =#=#=#=#="); - stage3(colors); - - pdebug("=#=#=#=#= Stage 4 =#=#=#=#="); - stage4(colors); - pdebug("========= Colors ========="); - pdebug_action( - slist_iter(color, color_t, colors, lpc, - print_color(NULL, color, FALSE) - ) - ); - - pdebug("=#=#=#=#= Stage 5 =#=#=#=#="); - stage5(resources); - - pdebug("=#=#=#=#= Stage 6 =#=#=#=#="); - stage6(&actions, &action_constraints, - stonith_list, shutdown_list); - - pdebug("========= Action List ========="); - pdebug_action( - slist_iter(action, action_t, actions, lpc, - print_action(NULL, action, TRUE) - ) - ); - - pdebug("=#=#=#=#= Stage 7 =#=#=#=#="); - stage7(resources, actions, action_constraints, &action_sets); - - pdebug("=#=#=#=#= Summary =#=#=#=#="); - summary(resources); - - pdebug("========= Action Sets ========="); - - pdebug("\t========= Set %d (Un-runnable) =========", -1); - pdebug_action( - slist_iter(action, action_t, actions, lpc, - if(action->optional == FALSE - && action->runnable == FALSE) { - print_action("\t", action, TRUE); - } - ) - ); - - pdebug_action( - slist_iter(action_set, GSList, action_sets, lpc, - pdebug("\t========= Set %d =========", lpc); - slist_iter(action, action_t, action_set, lpc2, - print_action("\t", action, TRUE); - ) - ) - ); - - - pdebug("========= Stonith List ========="); - pdebug_action( - slist_iter(node, node_t, stonith_list, lpc, - print_node(NULL, node, FALSE); - ) - ); - - pdebug("========= Shutdown List ========="); - pdebug_action( - slist_iter(node, node_t, shutdown_list, lpc, - print_node(NULL, node, FALSE); - ) - ); - - pdebug("=#=#=#=#= Stage 8 =#=#=#=#="); - stage8(action_sets, &graph); - - return graph; -} diff --git a/crm/pengine/pengine.c b/crm/pengine/pengine.c index 5e805c9ece..33d8636f1f 100755 --- a/crm/pengine/pengine.c +++ b/crm/pengine/pengine.c @@ -1,1727 +1,1888 @@ #include #include #include #include +#include #include #include #include #include #include +xmlNodePtr do_calculations(xmlNodePtr cib_object); + +gboolean process_pe_message(xmlNodePtr msg, IPC_Channel *sender); + + void color_resource(resource_t *lh_resource, GSListPtr *colors, GSListPtr resources); gboolean create_rsc_to_rsc(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh); gboolean create_ordering(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, GSListPtr *action_constraints); gboolean unpack_constraints(xmlNodePtr xml_constraints, GSListPtr nodes, GSListPtr resources, GSListPtr *node_constraints, GSListPtr *action_constraints); gboolean unpack_resources(xmlNodePtr xml_resources, GSListPtr *resources, GSListPtr *actions, GSListPtr *action_cons, GSListPtr all_nodes); gboolean unpack_nodes(xmlNodePtr xml_nodes, GSListPtr *nodes); gboolean unpack_status(xmlNodePtr status, GSListPtr nodes, GSListPtr rsc_list, GSListPtr *node_constraints); gboolean apply_node_constraints(GSListPtr constraints, GSListPtr resources, GSListPtr nodes); gboolean is_active(rsc_to_node_t *cons); gboolean choose_node_from_list(GSListPtr colors, color_t *color, GSListPtr nodes); gboolean unpack_rsc_to_attr(xmlNodePtr xml_obj, GSListPtr rsc_list, GSListPtr node_list, GSListPtr *node_constraints); gboolean unpack_rsc_to_node(xmlNodePtr xml_obj, GSListPtr rsc_list, GSListPtr node_list, GSListPtr *node_constraints); gboolean unpack_rsc_to_rsc(xmlNodePtr xml_obj, GSListPtr rsc_list, GSListPtr *action_constraints); gboolean choose_color(resource_t *lh_resource, GSListPtr candidate_colors); gboolean strict_postproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color, GSListPtr *colors, GSListPtr resources); gboolean strict_preproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color, GSListPtr *colors, GSListPtr resources); gboolean update_node_weight(rsc_to_node_t *cons, char *id, GSListPtr nodes); gboolean process_node_lrm_state(node_t *node, xmlNodePtr lrm_state, GSListPtr rsc_list, GSListPtr nodes, GSListPtr *node_constraints); GSListPtr match_attrs(xmlNodePtr attr_exp, GSListPtr node_list); gboolean update_runnable(GSListPtr actions); GSListPtr create_action_set(action_t *action); /* GSListPtr rsc_list = NULL; GSListPtr node_list = NULL; GSListPtr node_cons_list = NULL; GSListPtr rsc_cons_list = NULL; GSListPtr action_list = NULL; GSListPtr action_set_list = NULL; GSListPtr action_cons_list = NULL; GSListPtr colors = NULL; GSListPtr stonith_list = NULL; GSListPtr shutdown_list = NULL; color_t *current_color = NULL; xmlNodePtr xml_set_of_sets = NULL; */ color_t *no_color = NULL; int max_valid_nodes = 0; int order_id = 1; int action_id = 1; gboolean pe_debug = FALSE; gboolean pe_debug_saved = FALSE; /* * Unpack everything * At the end you'll have: * - A list of nodes * - A list of resources (each with any dependancies on other resources) * - A list of constraints between resources and nodes * - A list of constraints between start/stop actions * - A list of nodes that need to be stonith'd * - A list of nodes that need to be shutdown * - A list of the possible stop/start actions (without dependancies) */ gboolean stage0(xmlNodePtr cib, GSListPtr *resources, GSListPtr *nodes, GSListPtr *node_constraints, GSListPtr *actions, GSListPtr *action_constraints, GSListPtr *stonith_list, GSListPtr *shutdown_list) { int lpc = 0; xmlNodePtr cib_nodes = get_object_root("nodes", cib); xmlNodePtr cib_status = get_object_root("status", cib); xmlNodePtr cib_resources = get_object_root("resources", cib); xmlNodePtr cib_constraints = get_object_root("constraints", cib); unpack_nodes(safe_val(NULL, cib_nodes, children), nodes); unpack_resources(safe_val(NULL, cib_resources, children), resources, actions, action_constraints, *nodes); unpack_status(safe_val(NULL, cib_status, children), *nodes, *resources, node_constraints); unpack_constraints(safe_val(NULL, cib_constraints, children), *nodes, *resources, node_constraints, action_constraints); slist_iter( node, node_t, *nodes, lpc, if(node->details->shutdown) { *shutdown_list = g_slist_append(*shutdown_list, node); } else if(node->details->unclean) { *stonith_list = g_slist_append(*stonith_list, node); } ); return TRUE; } /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). * * Apply node constraints (ie. filter the "allowed_nodes" part of resources */ gboolean stage1(GSListPtr node_constraints, GSListPtr nodes, GSListPtr resources) { int lpc = 0; slist_iter( node, node_t, nodes, lpc, if(node == NULL) { // error } else if(node->weight >= 0.0 && node->details->online && node->details->type == node_member) { max_valid_nodes++; } ); apply_node_constraints(node_constraints, nodes, resources); return TRUE; } /* * Choose a color for all resources from highest priority and "must" * dependancies to lowest, creating new colors as necessary (returned * as "colors"). * * Some nodes may be colored as a "no_color" meaning that it was unresolvable * given the current node stati and constraints. */ gboolean stage2(GSListPtr sorted_rscs, GSListPtr sorted_nodes, GSListPtr *colors) { int lpc = 0; color_t *current_color = NULL; // Set initial color // Set color.candidate_nodes = all active nodes no_color = create_color(colors, NULL, NULL); current_color = create_color(colors, sorted_nodes, sorted_rscs); // Set resource.color = color (all resources) // Set resource.provisional = TRUE (all resources) slist_iter( this_resource, resource_t, sorted_rscs, lpc, this_resource->color = current_color; this_resource->provisional = TRUE; ); pdebug("initialized resources to default color"); // Take (next) highest resource slist_iter( lh_resource, resource_t, sorted_rscs, lpc, // if resource.provisional == FALSE, repeat if(lh_resource->provisional == FALSE) { // already processed this resource continue; } color_resource(lh_resource, colors, sorted_rscs); // next resource ); return TRUE; } /* * not sure if this is a good idea or not, but eventually we might like * to utilize as many nodes as possible... and this might be a convienient * hook */ gboolean stage3(GSListPtr colors) { // not sure if this is a good idea or not if(g_slist_length(colors) > max_valid_nodes) { // we need to consolidate some } else if(g_slist_length(colors) < max_valid_nodes) { // we can create a few more } return TRUE; } #define color_n_nodes color_n->details->candidate_nodes #define color_n_plus_1_nodes color_n_plus_1->details->candidate_nodes /* * Choose a node for each (if possible) color */ gboolean stage4(GSListPtr colors) { int lpc = 0; color_t *color_n = NULL; color_t *color_n_plus_1 = NULL; for(lpc = 0; lpc < g_slist_length(colors); lpc++) { color_n = color_n_plus_1; color_n_plus_1 = (color_t*)g_slist_nth_data(colors, lpc); pdebug_action(print_color("Choose node for...", color_n, FALSE)); if(color_n == NULL) { continue; } GSListPtr xor = node_list_xor(color_n_nodes, color_n_plus_1_nodes); GSListPtr minus = node_list_minus(color_n_nodes, color_n_plus_1_nodes); if(g_slist_length(xor) == 0 || g_slist_length(minus) == 0) { pdebug("Choose any node from our list"); choose_node_from_list(colors, color_n, color_n_nodes); } else { pdebug("Choose a node not in n+1"); choose_node_from_list(colors, color_n, minus); } } // choose last color if(color_n_plus_1 != NULL) { pdebug_action(print_color("Choose node for last color...", color_n_plus_1, FALSE)); choose_node_from_list(colors, color_n_plus_1, color_n_plus_1_nodes); } pdebug("done %s", __FUNCTION__); return TRUE; } /* * Attach nodes to the actions that need to be taken * * Mark actions "optional" if possible (Ie. if the start and stop are * for the same node) * * Mark unrunnable actions */ gboolean stage5(GSListPtr resources) { pdebug("filling in the nodes to perform the actions on"); int lpc = 0; slist_iter( rsc, resource_t, resources, lpc, print_resource("Processing", rsc, FALSE); if(safe_val(NULL, rsc, stop) == NULL || safe_val(NULL, rsc, start) == NULL) { // error continue; } if(safe_val4(NULL, rsc, color, details, chosen_node) == NULL) { rsc->stop->node = safe_val(NULL, rsc, cur_node); rsc->start->node = NULL; } else if(safe_str_eq(safe_val4(NULL, rsc, cur_node, details, id), safe_val6(NULL, rsc, color ,details, chosen_node, details, id))){ cl_log(LOG_DEBUG, "No change for Resource %s (%s)", safe_val(NULL, rsc, id), safe_val4(NULL, rsc, cur_node, details, id)); rsc->stop->optional = TRUE; rsc->start->optional = TRUE; rsc->stop->node = safe_val(NULL, rsc, cur_node); rsc->start->node = safe_val4(NULL, rsc, color, details, chosen_node); } else if(safe_val4(NULL, rsc, cur_node, details, id) == NULL) { rsc->stop->optional = TRUE; rsc->start->node = safe_val4(NULL, rsc, color, details, chosen_node); } else { rsc->stop->node = safe_val(NULL, rsc, cur_node); rsc->start->node = safe_val4(NULL, rsc, color, details, chosen_node); } if(rsc->stop->node != NULL) { rsc->stop->runnable = TRUE; } if(rsc->start->node != NULL) { rsc->start->runnable = TRUE; } ); return TRUE; } /* * Create dependacies for stonith and shutdown operations */ gboolean stage6(GSListPtr *actions, GSListPtr *action_constraints, GSListPtr stonith_nodes, GSListPtr shutdown_nodes) { int lpc = 0; int llpc = 0; slist_iter( node, node_t, shutdown_nodes, lpc, action_t *down_node = action_new(action_id++, NULL, shutdown_crm); down_node->node = node; down_node->runnable = TRUE; *actions = g_slist_append(*actions, down_node); slist_iter( rsc, resource_t, node->details->running_rsc, llpc, order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); /* stop resources before shutdown */ order->id = order_id++; order->lh_action = rsc->stop; order->rh_action = down_node; order->strength = must; *action_constraints = g_slist_append(*action_constraints, order); ); ); slist_iter( node, node_t, stonith_nodes, lpc, action_t *stonith_node = action_new(action_id++, NULL, stonith_op); stonith_node->node = node; stonith_node->runnable = TRUE; *actions = g_slist_append(*actions, stonith_node); slist_iter( rsc, resource_t, node->details->running_rsc, llpc, order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); /* try stopping the resource before stonithing the node * * if the stop succeeds, the transitioner can then * decided if stonith is needed */ order->id = order_id++; order->lh_action = rsc->stop; order->rh_action = stonith_node; order->strength = must; *action_constraints = g_slist_append(*action_constraints, order); /* stonith before start */ order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); // try stopping the node first order->id = order_id++; order->lh_action = stonith_node; order->rh_action = rsc->start; order->strength = must; *action_constraints = g_slist_append(*action_constraints, order); ); ); return TRUE; } /* * Determin the sets of independant actions and the correct order for the * actions in each set. * * Mark dependancies f un-runnable actions un-runnable * */ gboolean stage7(GSListPtr resources, GSListPtr actions, GSListPtr action_constraints, GSListPtr *action_sets) { int lpc = 0; slist_iter( order, order_constraint_t, action_constraints, lpc, action_wrapper_t *wrapper = (action_wrapper_t*) cl_malloc(sizeof(action_wrapper_t)); wrapper->action = order->rh_action; wrapper->strength = order->strength; order->lh_action->actions_after = g_slist_append(order->lh_action->actions_after, wrapper); wrapper = (action_wrapper_t*) cl_malloc(sizeof(action_wrapper_t)); wrapper->action = order->lh_action; wrapper->strength = order->strength; order->rh_action->actions_before = g_slist_append(order->rh_action->actions_before, wrapper); ); update_runnable(actions); slist_iter( rsc, resource_t, resources, lpc, GSListPtr action_set = NULL; if(rsc->stop->runnable) { action_set = create_action_set(rsc->stop); if(action_set != NULL) { *action_sets = g_slist_append(*action_sets, action_set); } else { pdebug("No actions resulting from %s->stop", rsc->id); } } if(rsc->start->runnable) { action_set = create_action_set(rsc->start); if(action_set != NULL) { *action_sets = g_slist_append(*action_sets, action_set); } else { pdebug("No actions resulting from %s->start", rsc->id); } } ); return TRUE; } /* * Create a dependancy graph to send to the transitioner (via the CRMd) */ gboolean stage8(GSListPtr action_sets, xmlNodePtr *graph) { int lpc = 0; xmlNodePtr xml_action_set = NULL; *graph = create_xml_node(NULL, "transition_graph"); /* errors... slist_iter(action, action_t, action_list, lpc, if(action->optional == FALSE && action->runnable == FALSE) { print_action("Ignoring", action, TRUE); } ); */ int lpc2; slist_iter(action_set, GSList, action_sets, lpc, pdebug("Processing Action Set %d", lpc); xml_action_set = create_xml_node(NULL, "actions"); set_xml_property_copy(xml_action_set, "id", crm_itoa(lpc)); slist_iter(action, action_t, action_set, lpc2, xmlNodePtr xml_action = action2xml(action); xmlAddChild(xml_action_set, xml_action); ) xmlAddChild(*graph, xml_action_set); ); xml_message_debug(*graph, "created action list"); return TRUE; } /* * Print a nice human readable high-level summary of what we're going to do */ gboolean summary(GSListPtr resources) { int lpc = 0; slist_iter( rsc, resource_t, resources, lpc, char *rsc_id = safe_val(NULL, rsc, id); char *node_id = safe_val4(NULL, rsc, cur_node, details, id); char *new_node_id = safe_val6(NULL, rsc, color, details, chosen_node, details, id); if(rsc->runnable == FALSE) { cl_log(LOG_ERR, "Resource %s was not runnable", rsc_id); if(node_id != NULL) { cl_log(LOG_WARNING, "Stopping Resource (%s) on node %s", rsc_id, node_id); } } else if(safe_val4(NULL, rsc, color, details, chosen_node) == NULL) { cl_log(LOG_ERR, "Could not allocate Resource %s", rsc_id); if(node_id != NULL) { cl_log(LOG_WARNING, "Stopping Resource (%s) on node %s", rsc_id, node_id); } } else if(safe_str_eq(node_id, new_node_id)){ cl_log(LOG_DEBUG, "No change for Resource %s (%s)", rsc_id, safe_val4(NULL, rsc, cur_node, details, id)); } else if(node_id == NULL) { cl_log(LOG_INFO, "Starting Resource %s on %s", rsc_id, new_node_id); } else { cl_log(LOG_INFO, "Moving Resource %s from %s to %s", rsc_id, node_id, new_node_id); } ); return TRUE; } gboolean choose_node_from_list(GSListPtr colors, color_t *color, GSListPtr nodes) { /* 1. Sort by weight 2. color.chosen_node = highest wieghted node 3. remove color.chosen_node from all other colors */ int lpc = 0; nodes = g_slist_sort(nodes, sort_node_weight); color->details->chosen_node = (node_t*)g_slist_nth_data(nodes, 0); if(color->details->chosen_node == NULL) { cl_log(LOG_ERR, "Could not allocate a node for color %d", color->id); return FALSE; } slist_iter( color_n, color_t, colors, lpc, node_t *other_node = pe_find_node(color_n->details->candidate_nodes, color->details->chosen_node->details->id); color_n->details->candidate_nodes = g_slist_remove(color_n->details->candidate_nodes, other_node); ); return TRUE; } gboolean unpack_nodes(xmlNodePtr xml_nodes, GSListPtr *nodes) { pdebug("Begining unpack... %s", __FUNCTION__); while(xml_nodes != NULL) { pdebug("Processing node..."); xmlNodePtr xml_obj = xml_nodes; xmlNodePtr attrs = xml_obj->children; const char *id = xmlGetProp(xml_obj, "id"); const char *type = xmlGetProp(xml_obj, "type"); if(attrs != NULL) { attrs = attrs->children; } xml_nodes = xml_nodes->next; if(id == NULL) { cl_log(LOG_ERR, "Must specify id tag in "); continue; } if(type == NULL) { cl_log(LOG_ERR, "Must specify type tag in "); continue; } node_t *new_node = cl_malloc(sizeof(node_t)); new_node->weight = 1.0; new_node->fixed = FALSE; new_node->details = (struct node_shared_s*) cl_malloc(sizeof(struct node_shared_s*)); new_node->details->online = FALSE; new_node->details->unclean = FALSE; new_node->details->shutdown = FALSE; new_node->details->running_rsc = NULL; new_node->details->id = cl_strdup(id); new_node->details->attrs = g_hash_table_new(g_str_hash, g_str_equal); new_node->details->type = node_ping; if(safe_str_eq(type, "node")) { new_node->details->type = node_member; } while(attrs != NULL){ const char *name = xmlGetProp(attrs, "name"); const char *value = xmlGetProp(attrs, "value"); if(name != NULL && value != NULL) { g_hash_table_insert(new_node->details->attrs, cl_strdup(name), cl_strdup(value)); } attrs = attrs->next; } pdebug("Adding node id... %s (%p)", id, new_node); *nodes = g_slist_append(*nodes, new_node); } *nodes = g_slist_sort(*nodes, sort_node_weight); return TRUE; } gboolean unpack_resources(xmlNodePtr xml_resources, GSListPtr *resources, GSListPtr *actions, GSListPtr *action_cons, GSListPtr all_nodes) { pdebug("Begining unpack... %s", __FUNCTION__); while(xml_resources != NULL) { xmlNodePtr xml_obj = xml_resources; const char *id = xmlGetProp(xml_obj, "id"); const char *priority = xmlGetProp(xml_obj, "priority"); float priority_f = atof(priority); xml_resources = xml_resources->next; pdebug("Processing resource..."); if(id == NULL) { cl_log(LOG_ERR, "Must specify id tag in "); continue; } resource_t *new_rsc = cl_malloc(sizeof(resource_t)); new_rsc->xml = xml_obj; // copy first new_rsc->priority = priority_f; new_rsc->candidate_colors = NULL; new_rsc->color = NULL; new_rsc->runnable = TRUE; new_rsc->provisional = TRUE; new_rsc->allowed_nodes = node_list_dup(all_nodes); new_rsc->rsc_cons = NULL; new_rsc->node_cons = NULL; new_rsc->id = cl_strdup(id); action_t *action_stop = action_new(action_id++, new_rsc, stop_rsc); action_t *action_start = action_new(action_id++, new_rsc, start_rsc); new_rsc->stop = action_stop; *actions = g_slist_append(*actions, action_stop); new_rsc->start = action_start; *actions = g_slist_append(*actions, action_start); order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); order->id = order_id++; order->lh_action = action_stop; order->rh_action = action_start; order->strength = startstop; *action_cons = g_slist_append(*action_cons, order); pdebug_action(print_resource("Added", new_rsc, FALSE)); *resources = g_slist_append(*resources, new_rsc); } *resources = g_slist_sort(*resources, sort_rsc_priority); return TRUE; } gboolean unpack_constraints(xmlNodePtr xml_constraints, GSListPtr nodes, GSListPtr resources, GSListPtr *node_constraints, GSListPtr *action_constraints) { pdebug("Begining unpack... %s", __FUNCTION__); while(xml_constraints != NULL) { const char *id = xmlGetProp(xml_constraints, "id"); xmlNodePtr xml_obj = xml_constraints; xml_constraints = xml_constraints->next; if(id == NULL) { cl_log(LOG_ERR, "Constraint must have an id"); continue; } pdebug("Processing constraint %s %s", xml_obj->name,id); if(safe_str_eq("rsc_to_rsc", xml_obj->name)) { unpack_rsc_to_rsc(xml_obj, resources, action_constraints); } else if(safe_str_eq("rsc_to_node", xml_obj->name)) { unpack_rsc_to_node(xml_obj, resources, nodes, node_constraints); } else if(safe_str_eq("rsc_to_attr", xml_obj->name)) { unpack_rsc_to_attr(xml_obj, resources, nodes, node_constraints); } else { cl_log(LOG_ERR, "Unsupported constraint type: %s", xml_obj->name); } } return TRUE; } gboolean apply_node_constraints(GSListPtr constraints, GSListPtr resources, GSListPtr nodes) { pdebug("Applying constraints... %s", __FUNCTION__); int lpc = 0; slist_iter( cons, rsc_to_node_t, constraints, lpc, pdebug_action(print_rsc_to_node("Applying", cons, FALSE)); // take "lifetime" into account if(cons == NULL) { cl_log(LOG_ERR, "Constraint (%d) is NULL", lpc); continue; } else if(is_active(cons) == FALSE) { cl_log(LOG_INFO, "Constraint (%d) is not active", lpc); // warning continue; } resource_t *rsc_lh = cons->rsc_lh; if(rsc_lh == NULL) { cl_log(LOG_ERR, "LHS of rsc_to_node (%s) is NULL", cons->id); continue; } cons->rsc_lh->node_cons = g_slist_append(cons->rsc_lh->node_cons, cons); if(cons->node_list_rh == NULL) { cl_log(LOG_ERR, "RHS of rsc_to_node (%s) is NULL", cons->id); continue; } else { int llpc = 0; slist_iter(node_rh, node_t, cons->node_list_rh, llpc, update_node_weight(cons, node_rh->details->id, nodes)); } /* dont add it to the resource, * the information is in the resouce's node list */ ); return TRUE; } // remove nodes that are down, stopping // create +ve rsc_to_node constraints between resources and the nodes they are running on // anything else? gboolean unpack_status(xmlNodePtr status, GSListPtr nodes, GSListPtr rsc_list, GSListPtr *node_constraints) { pdebug("Begining unpack %s", __FUNCTION__); while(status != NULL) { const char *id = xmlGetProp(status, "id"); const char *state = xmlGetProp(status, "state"); const char *exp_state = xmlGetProp(status, "exp_state"); xmlNodePtr lrm_state = find_xml_node(status, "lrm"); xmlNodePtr attrs = find_xml_node(status, "attributes"); lrm_state = find_xml_node(lrm_state, "lrm_resources"); lrm_state = find_xml_node(lrm_state, "rsc_state"); status = status->next; pdebug("Processing node %s", id); if(id == NULL){ // error continue; } pdebug("Processing node attrs"); node_t *this_node = pe_find_node(nodes, id); while(attrs != NULL){ const char *name = xmlGetProp(attrs, "name"); const char *value = xmlGetProp(attrs, "value"); if(name != NULL && value != NULL && safe_val(NULL, this_node, details) != NULL) { pdebug("Adding %s => %s", name, value); g_hash_table_insert(this_node->details->attrs, cl_strdup(name), cl_strdup(value)); } attrs = attrs->next; } pdebug("determining node state"); if(safe_str_eq(exp_state, "active") && safe_str_eq(state, "active")) { // process resource, make +ve preference this_node->details->online = TRUE; } else { pdebug("remove %s", __FUNCTION__); // remove node from contention this_node->weight = -1; this_node->fixed = TRUE; pdebug("state %s, expected %s", state, exp_state); if(safe_str_eq(state, "shutdown")){ // create shutdown req this_node->details->shutdown = TRUE; } else if(safe_str_eq(exp_state, "active") && safe_str_neq(state, "active")) { // mark unclean in the xml this_node->details->unclean = TRUE; // remove any running resources from being allocated } } pdebug("Processing node lrm state"); process_node_lrm_state(this_node, lrm_state, rsc_list, nodes, node_constraints); } return TRUE; } gboolean is_active(rsc_to_node_t *cons) { return TRUE; } gboolean strict_preproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color, GSListPtr *colors, GSListPtr resources) { resource_t * lh_resource = constraint->rsc_lh; switch(constraint->strength) { case must: if(constraint->rsc_rh->runnable == FALSE) { cl_log(LOG_WARNING, "Resource %s must run on the same node" " as %s (cons %s), but %s is not" " runnable.", constraint->rsc_lh->id, constraint->rsc_rh->id, constraint->id, constraint->rsc_rh->id); constraint->rsc_lh->runnable = FALSE; } break; // x * should * should_not = x case should: if(constraint->rsc_rh->provisional == FALSE) { local_color->local_weight = local_color->local_weight * 2.0; } break; case should_not: if(constraint->rsc_rh->provisional == FALSE) { local_color->local_weight = local_color->local_weight * 0.5; } pdebug("# Colors %d, Nodes %d", g_slist_length(*colors), max_valid_nodes); if(g_slist_length(*colors) < max_valid_nodes // && g_slist_length(lh_resource->candidate_colors)==1 ) { create_color(colors, lh_resource->allowed_nodes, resources); } break; case must_not: if(constraint->rsc_rh->provisional == FALSE) { lh_resource->candidate_colors = g_slist_remove( lh_resource->candidate_colors, local_color); } break; default: // error break; } return TRUE; } gboolean strict_postproc(rsc_to_rsc_t *constraint, color_t *local_color, color_t *other_color, GSListPtr *colors, GSListPtr resources) { print_rsc_to_rsc("Post processing", constraint, FALSE); switch(constraint->strength) { case must: if(constraint->rsc_rh->provisional == TRUE) { constraint->rsc_rh->color = other_color; constraint->rsc_rh->provisional = FALSE; color_resource(constraint->rsc_rh, colors, resources); } // else check for error if(constraint->rsc_lh->runnable == FALSE) { cl_log(LOG_WARNING, "Resource %s must run on the same node" " as %s (cons %s), but %s is not" " runnable.", constraint->rsc_rh->id, constraint->rsc_lh->id, constraint->id, constraint->rsc_lh->id); constraint->rsc_rh->runnable = FALSE; } break; case should: break; case should_not: break; case must_not: if(constraint->rsc_rh->provisional == TRUE) { // check for error } break; default: // error break; } return TRUE; } gboolean choose_color(resource_t *lh_resource, GSListPtr candidate_colors) { int lpc = 0; if(lh_resource->runnable == FALSE) { lh_resource->color = no_color; lh_resource->provisional = FALSE; } else { GSListPtr sorted_colors = g_slist_sort(candidate_colors, sort_color_weight); lh_resource->candidate_colors = sorted_colors; pdebug( "Choose a color from %d possibilities", g_slist_length(sorted_colors)); } if(lh_resource->provisional) { slist_iter( this_color, color_t,lh_resource->candidate_colors, lpc, GSListPtr intersection = node_list_and( this_color->details->candidate_nodes, lh_resource->allowed_nodes); if(g_slist_length(intersection) != 0) { // TODO: merge node weights g_slist_free(this_color->details->candidate_nodes); this_color->details->candidate_nodes = intersection; lh_resource->color = this_color; lh_resource->provisional = FALSE; break; } ); } return !lh_resource->provisional; } gboolean unpack_rsc_to_node(xmlNodePtr xml_obj, GSListPtr rsc_list, GSListPtr node_list, GSListPtr *node_constraints) { xmlNodePtr node_ref = xml_obj->children; rsc_to_node_t *new_con = cl_malloc(sizeof(rsc_to_node_t)); const char *id_lh = xmlGetProp(xml_obj, "from"); const char *id = xmlGetProp(xml_obj, "id"); const char *mod = xmlGetProp(xml_obj, "modifier"); const char *weight = xmlGetProp(xml_obj, "weight"); float weight_f = atof(weight); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); if(rsc_lh == NULL) { cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)", id, id_lh); } new_con->id = cl_strdup(id); new_con->rsc_lh = rsc_lh; new_con->weight = weight_f; if(safe_str_eq(mod, "set")){ new_con->modifier = set; } else if(safe_str_eq(mod, "inc")){ new_con->modifier = inc; } else if(safe_str_eq(mod, "dec")){ new_con->modifier = dec; } else { // error } /* */ // while(node_ref != NULL) { const char *id_rh = xmlGetProp(node_ref, "name"); node_t *node_rh = pe_find_node(node_list, id_rh); if(node_rh == NULL) { // error cl_log(LOG_ERR, "node %s (from %s) not found", id_rh, node_ref->name); continue; } new_con->node_list_rh = g_slist_append(new_con->node_list_rh, node_rh); /* dont add it to the resource, * the information is in the resouce's node list */ node_ref = node_ref->next; } *node_constraints = g_slist_append(*node_constraints, new_con); return TRUE; } gboolean unpack_rsc_to_attr(xmlNodePtr xml_obj, GSListPtr rsc_list, GSListPtr node_list, GSListPtr *node_constraints) { /* Translation: give any node a +ve weight of 20.0 to run rsc2 if: attr "cpu" is set _and_ "kernel"="2.6", _or_ attr "hdd" is set _and_ "kernel"="2.4" Further translation: 2 constraints that give any node a +ve weight of 20.0 to run rsc2 cons1: attr "cpu" is set and "kernel"="2.6" cons2: attr "hdd" is set and "kernel"="2.4" */ xmlNodePtr attr_exp = xml_obj->children; const char *id_lh = xmlGetProp(xml_obj, "from"); const char *mod = xmlGetProp(xml_obj, "modifier"); const char *weight = xmlGetProp(xml_obj, "weight"); const char *id = xmlGetProp(attr_exp, "id"); float weight_f = atof(weight); enum con_modifier a_modifier = modifier_none; resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); if(rsc_lh == NULL) { cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } if(safe_str_eq(mod, "set")){ a_modifier = set; } else if(safe_str_eq(mod, "inc")){ a_modifier = inc; } else if(safe_str_eq(mod, "dec")){ a_modifier = dec; } else { // error } if(attr_exp == NULL) { cl_log(LOG_WARNING, "no attrs for constraint %s", id); } while(attr_exp != NULL) { const char *id_rh = xmlGetProp(attr_exp, "name"); const char *id = xmlGetProp(attr_exp, "id"); rsc_to_node_t *new_con = cl_malloc(sizeof(rsc_to_node_t)); new_con->id = cl_strdup(id); new_con->rsc_lh = rsc_lh; new_con->weight = weight_f; new_con->modifier = a_modifier; new_con->node_list_rh = match_attrs(attr_exp, node_list); if(new_con->node_list_rh == NULL) { // error cl_log(LOG_ERR, "node %s (from %s) not found", id_rh, attr_exp->name); } pdebug_action(print_rsc_to_node("Added", new_con, FALSE)); *node_constraints = g_slist_append(*node_constraints, new_con); /* dont add it to the resource, * the information is in the resouce's node list */ attr_exp = attr_exp->next; } return TRUE; } gboolean update_node_weight(rsc_to_node_t *cons, char *id, GSListPtr nodes) { node_t *node_rh = pe_find_node(cons->rsc_lh->allowed_nodes, id); if(node_rh == NULL) { node_t *node_tmp = pe_find_node(nodes, id); node_rh = node_copy(node_tmp); cons->rsc_lh->allowed_nodes = g_slist_append(cons->rsc_lh->allowed_nodes, node_rh); } if(node_rh == NULL) { // error return FALSE; } if(node_rh->fixed) { // warning cl_log(LOG_WARNING, "Constraint %s is irrelevant as the" " weight of node %s is fixed as %f.", cons->id, node_rh->details->id, node_rh->weight); return TRUE; } pdebug( "Constraint %s: node %s weight %s %f.", cons->id, node_rh->details->id, modifier2text(cons->modifier), node_rh->weight); switch(cons->modifier) { case set: node_rh->weight = cons->weight; node_rh->fixed = TRUE; break; case inc: node_rh->weight += cons->weight; break; case dec: node_rh->weight -= cons->weight; break; case modifier_none: // warning break; } return TRUE; } gboolean process_node_lrm_state(node_t *node, xmlNodePtr lrm_state, GSListPtr rsc_list, GSListPtr nodes, GSListPtr *node_constraints) { pdebug("here %s", __FUNCTION__); while(lrm_state != NULL) { const char *id = xmlGetProp(lrm_state, "id"); const char *rsc_id = xmlGetProp(lrm_state, "rsc_id"); const char *node_id = xmlGetProp(lrm_state, "node_id"); const char *rsc_state = xmlGetProp(lrm_state, "rsc_state"); resource_t *rsc_lh = pe_find_resource(rsc_list, rsc_id); rsc_lh->cur_node = node; node->details->running_rsc = g_slist_append(node->details->running_rsc, rsc_lh); /* it is runnable, but depends on a stonith op if(safe_val3(FALSE, node, details, unclean)) { rsc_lh->runnable = FALSE; } */ if((safe_str_eq(rsc_state, "starting")) || (safe_str_eq(rsc_state, "started"))) { node_t *node_rh; rsc_to_node_t *new_cons = cl_malloc(sizeof(rsc_to_node_t)); new_cons->id = cl_strdup(id); // genereate one new_cons->weight = 100.0; new_cons->modifier = inc; new_cons->rsc_lh = rsc_lh; node_rh = pe_find_node(nodes, node_id); new_cons->node_list_rh = g_slist_append(NULL, node_rh); *node_constraints = g_slist_append(*node_constraints, new_cons); pdebug_action(print_rsc_to_node( "Added", new_cons, FALSE)); } else if(safe_str_eq(rsc_state, "stop_fail")) { // do soemthing } // else no preference lrm_state = lrm_state->next; } return TRUE; } GSListPtr match_attrs(xmlNodePtr attr_exp, GSListPtr node_list) { int lpc = 0; GSListPtr result = NULL; slist_iter( node, node_t, node_list, lpc, xmlNodePtr node_match = attr_exp->children; gboolean accept = TRUE; while(accept && node_match != NULL) { const char *type =xmlGetProp(node_match, "type"); const char *value=xmlGetProp(node_match, "value"); const char *name =xmlGetProp(node_match, "target"); node_match = node_match->next; if(name == NULL || type == NULL) { // error continue; } const char *h_val = (const char*) g_hash_table_lookup(node->details->attrs, name); if(h_val != NULL && safe_str_eq(type, "has_attr")){ accept = TRUE; } else if(h_val == NULL && safe_str_eq(type, "not_attr")) { accept = TRUE; } else if(h_val != NULL && safe_str_eq(type, "attr_value") && safe_str_eq(h_val, value)) { accept = TRUE; } else { accept = FALSE; } } if(accept) { result = g_slist_append(result, node); } ); return result; } gboolean create_rsc_to_rsc(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh) { if(rsc_lh == NULL || rsc_rh == NULL){ // error return FALSE; } rsc_to_rsc_t *new_con = cl_malloc(sizeof(rsc_to_node_t)); rsc_to_rsc_t *inverted_con = NULL; new_con->id = cl_strdup(id); new_con->rsc_lh = rsc_lh; new_con->rsc_rh = rsc_rh; new_con->strength = strength; inverted_con = invert_constraint(new_con); rsc_lh->rsc_cons = g_slist_insert_sorted(rsc_lh->rsc_cons, inverted_con, sort_cons_strength); rsc_rh->rsc_cons = g_slist_insert_sorted(rsc_rh->rsc_cons, new_con, sort_cons_strength); return TRUE; } gboolean create_ordering(const char *id, enum con_strength strength, resource_t *rsc_lh, resource_t *rsc_rh, GSListPtr *action_constraints) { if(rsc_lh == NULL || rsc_rh == NULL){ // error return FALSE; } action_t *lh_stop = rsc_lh->stop; action_t *lh_start = rsc_lh->start; action_t *rh_stop = rsc_rh->stop; action_t *rh_start = rsc_rh->start; order_constraint_t *order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); order->id = order_id++; order->lh_action = lh_stop; order->rh_action = rh_stop; order->strength = strength; *action_constraints = g_slist_append(*action_constraints, order); order = (order_constraint_t*) cl_malloc(sizeof(order_constraint_t)); order->id = order_id++; order->lh_action = rh_start; order->rh_action = lh_start; order->strength = strength; *action_constraints = g_slist_append(*action_constraints, order); return TRUE; } gboolean unpack_rsc_to_rsc(xmlNodePtr xml_obj, GSListPtr rsc_list, GSListPtr *action_constraints) { const char *id_lh = xmlGetProp(xml_obj, "from"); const char *id = xmlGetProp(xml_obj, "id"); resource_t *rsc_lh = pe_find_resource(rsc_list, id_lh); const char *id_rh = xmlGetProp(xml_obj, "to"); resource_t *rsc_rh = pe_find_resource(rsc_list, id_rh); const char *strength = xmlGetProp(xml_obj, "strength"); const char *type = xmlGetProp(xml_obj, "type"); enum con_strength strength_e = ignore; if(rsc_lh == NULL) { cl_log(LOG_ERR, "No resource (con=%s, rsc=%s)", id, id_lh); return FALSE; } if(safe_str_eq(strength, "must")) { strength_e = must; } else if(safe_str_eq(strength, "should")) { strength_e = should; } else if(safe_str_eq(strength, "should_not")) { strength_e = should_not; } else if(safe_str_eq(strength, "must_not")) { strength_e = must_not; } else { // error } if(safe_str_eq(type, "ordering")) { // make an action_cons instead return create_ordering(id, strength_e, rsc_lh, rsc_rh, action_constraints); } return create_rsc_to_rsc(id, strength_e, rsc_lh, rsc_rh); } GSListPtr create_action_set(action_t *action) { int lpc = 0; GSListPtr result = NULL; GSListPtr tmp = NULL; if(action->processed) { return NULL; } pdebug_action(print_action("Create action set for", action, FALSE)); // process actions_before if(action->seen_count == 0) { pdebug("Processing \"before\" for action %d", action->id); slist_iter( other, action_wrapper_t, action->actions_before, lpc, tmp = create_action_set(other->action); pdebug("%d (%d total) \"before\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); ); // add ourselves pdebug("Adding self %d", action->id); if(action->processed == FALSE) { result = g_slist_append(result, action); action->processed = TRUE; } } else { pdebug("Already seen action %d", action->id); pdebug("Processing \"before\" for action %d", action->id); slist_iter( other, action_wrapper_t, action->actions_before, lpc, if(other->action->seen_count > action->seen_count && other->strength == must) { tmp = create_action_set(other->action); pdebug("%d (%d total) \"before\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); } ); // add ourselves pdebug("Adding self %d", action->id); if(action->processed == FALSE) { result = g_slist_append(result, action); action->processed = TRUE; } // add strength == !MUST slist_iter( other, action_wrapper_t, action->actions_before, lpc, tmp = create_action_set(other->action); pdebug("%d (%d total) post-self \"before\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); ); } action->seen_count = action->seen_count + 1; // process actions_after pdebug("Processing \"after\" for action %d", action->id); slist_iter( other, action_wrapper_t, action->actions_after, lpc, tmp = create_action_set(other->action); pdebug("%d (%d total) \"after\" actions for %d)", g_slist_length(tmp), g_slist_length(result),action->id); result = g_slist_concat(result, tmp); ); return result; } gboolean update_runnable(GSListPtr actions) { int lpc = 0, lpc2 = 0; gboolean change = TRUE; while(change) { change = FALSE; slist_iter( action, action_t, actions, lpc, if(action->runnable) { continue; } else if(action->optional) { continue; } slist_iter( other, action_wrapper_t, action->actions_before, lpc2, if(other->action->runnable) { change = TRUE; } other->action->runnable = FALSE; ); ); } return TRUE; } void color_resource(resource_t *lh_resource, GSListPtr *colors, GSListPtr resources) { int lpc = 0; pdebug_action(print_resource("Coloring", lh_resource, FALSE)); if(lh_resource->provisional == FALSE) { // already processed this resource return; } lh_resource->rsc_cons = g_slist_sort(lh_resource->rsc_cons, sort_cons_strength); pdebug("=== Pre-processing"); //------ Pre-processing slist_iter( constraint, rsc_to_rsc_t, lh_resource->rsc_cons, lpc, color_t *other_color = NULL; color_t *local_color = NULL; if(lh_resource->runnable == FALSE) { break; } pdebug_action(print_rsc_to_rsc( "Processing constraint", constraint, FALSE)); if(constraint->rsc_rh == NULL) { cl_log(LOG_ERR, "rsc_rh was NULL for %s", constraint->id); continue; } other_color = constraint->rsc_rh->color; local_color = find_color(lh_resource->candidate_colors, other_color); strict_preproc(constraint, local_color, other_color, colors, resources); ); // filter out nodes with a negative weight filter_nodes(lh_resource); /* Choose a color from the candidates or, * create a new one if no color is suitable * (this may need modification pending further napkin drawings) */ choose_color(lh_resource, lh_resource->candidate_colors); pdebug("* Colors %d, Nodes %d", g_slist_length(*colors), max_valid_nodes); if(lh_resource->provisional && g_slist_length(*colors) < max_valid_nodes) { // Create new color pdebug("Create a new color"); lh_resource->color = create_color(colors, lh_resource->allowed_nodes, resources); lh_resource->provisional = FALSE; } else if(lh_resource->provisional) { cl_log(LOG_ERR, "Could not color resource %s", lh_resource->id); print_resource("ERROR: No color", lh_resource, FALSE); lh_resource->color = no_color; lh_resource->provisional = FALSE; } pdebug_action(print_resource("Post-processing", lh_resource, FALSE)); //------ Post-processing color_t *local_color = lh_resource->color; slist_iter( constraint, rsc_to_rsc_t, lh_resource->rsc_cons, lpc, color_t *other_color = find_color(constraint->rsc_rh->candidate_colors, local_color); strict_postproc(constraint, local_color, other_color, colors, resources); ); pdebug_action(print_resource("Colored", lh_resource, FALSE)); } + +gboolean +process_pe_message(xmlNodePtr msg, IPC_Channel *sender) +{ + const char *op = get_xml_attr (msg, XML_TAG_OPTIONS, + XML_ATTR_OP, TRUE); + + const char *ref = xmlGetProp(msg, XML_ATTR_REFERENCE); + + CRM_DEBUG("Processing %s op (ref=%s)...", op, ref); + + const char *sys_to = xmlGetProp(msg, XML_ATTR_SYSTO); + + if(op == NULL){ + // error + } else if(sys_to == NULL || strcmp(sys_to, "pengine") != 0) { + CRM_DEBUG("Bad sys-to %s", sys_to); + return FALSE; + + } else if(strcmp(op, "pecalc") == 0) { + xmlNodePtr input_cib = find_xml_node(msg, XML_TAG_CIB); + if (send_ipc_reply(sender, msg, + do_calculations(input_cib)) ==FALSE) { + + cl_log(LOG_WARNING, + "Answer could not be sent"); + } + + } else if(strcmp(op, "quit") == 0) { + cl_log(LOG_WARNING, "Received quit message, terminating"); + exit(0); + } + + return TRUE; +} + +xmlNodePtr +do_calculations(xmlNodePtr cib_object) +{ + int lpc, lpc2; + + GSListPtr resources = NULL; + GSListPtr nodes = NULL; + GSListPtr node_constraints = NULL; + GSListPtr actions = NULL; + GSListPtr action_constraints = NULL; + GSListPtr stonith_list = NULL; + GSListPtr shutdown_list = NULL; + + GSListPtr colors = NULL; + GSListPtr action_sets = NULL; + + xmlNodePtr graph = NULL; + + pdebug("=#=#=#=#= Stage 0 =#=#=#=#="); + + stage0(cib_object, + &resources, + &nodes, &node_constraints, + &actions, &action_constraints, + &stonith_list, &shutdown_list); + + pdebug("=#=#=#=#= Stage 1 =#=#=#=#="); + stage1(node_constraints, nodes, resources); + + pdebug("=#=#=#=#= Stage 2 =#=#=#=#="); + stage2(resources, nodes, &colors); + + pdebug("========= Nodes ========="); + pdebug_action( + slist_iter(node, node_t, nodes, lpc, + print_node(NULL, node, TRUE) + ) + ); + + pdebug("========= Resources ========="); + pdebug_action( + slist_iter(resource, resource_t, resources, lpc, + print_resource(NULL, resource, TRUE) + ) + ); + + pdebug("=#=#=#=#= Stage 3 =#=#=#=#="); + stage3(colors); + + pdebug("=#=#=#=#= Stage 4 =#=#=#=#="); + stage4(colors); + pdebug("========= Colors ========="); + pdebug_action( + slist_iter(color, color_t, colors, lpc, + print_color(NULL, color, FALSE) + ) + ); + + pdebug("=#=#=#=#= Stage 5 =#=#=#=#="); + stage5(resources); + + pdebug("=#=#=#=#= Stage 6 =#=#=#=#="); + stage6(&actions, &action_constraints, + stonith_list, shutdown_list); + + pdebug("========= Action List ========="); + pdebug_action( + slist_iter(action, action_t, actions, lpc, + print_action(NULL, action, TRUE) + ) + ); + + pdebug("=#=#=#=#= Stage 7 =#=#=#=#="); + stage7(resources, actions, action_constraints, &action_sets); + + pdebug("=#=#=#=#= Summary =#=#=#=#="); + summary(resources); + + pdebug("========= Action Sets ========="); + + pdebug("\t========= Set %d (Un-runnable) =========", -1); + pdebug_action( + slist_iter(action, action_t, actions, lpc, + if(action->optional == FALSE + && action->runnable == FALSE) { + print_action("\t", action, TRUE); + } + ) + ); + + pdebug_action( + slist_iter(action_set, GSList, action_sets, lpc, + pdebug("\t========= Set %d =========", lpc); + slist_iter(action, action_t, action_set, lpc2, + print_action("\t", action, TRUE); + ) + ) + ); + + + pdebug("========= Stonith List ========="); + pdebug_action( + slist_iter(node, node_t, stonith_list, lpc, + print_node(NULL, node, FALSE); + ) + ); + + pdebug("========= Shutdown List ========="); + pdebug_action( + slist_iter(node, node_t, shutdown_list, lpc, + print_node(NULL, node, FALSE); + ) + ); + + pdebug("=#=#=#=#= Stage 8 =#=#=#=#="); + stage8(action_sets, &graph); + + return graph; +} diff --git a/crm/pengine/penginemain.c b/crm/pengine/penginemain.c index 84eb5b42d8..44bb3b4848 100644 --- a/crm/pengine/penginemain.c +++ b/crm/pengine/penginemain.c @@ -1,236 +1,238 @@ -/* $Id: penginemain.c,v 1.11 2004/05/04 11:51:10 andrew Exp $ */ +/* $Id: penginemain.c,v 1.12 2004/05/10 21:52:57 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYS_NAME "pengine" #define OPTARGS "skrh" #define PID_FILE WORKING_DIR "/"SYS_NAME".pid" #define DAEMON_LOG "/var/log/"SYS_NAME".log" #define DAEMON_DEBUG "/var/log/"SYS_NAME".debug" GMainLoop* mainloop = NULL; const char* crm_system_name = SYS_NAME; void usage(const char* cmd, int exit_status); int init_start(void); void pengine_shutdown(int nsig); -extern gboolean pe_input_dispatch(IPC_Channel *sender, void *user_data); +extern gboolean process_pe_message(xmlNodePtr msg, IPC_Channel *sender); int main(int argc, char ** argv) { int req_restart = FALSE; int req_status = FALSE; int req_stop = FALSE; int argerr = 0; int flag; cl_log_set_entity(crm_system_name); cl_log_enable_stderr(TRUE); cl_log_set_facility(LOG_USER); if (0) { send_ipc_message(NULL, NULL); } while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 's': /* Status */ req_status = TRUE; break; case 'k': /* Stop (kill) */ req_stop = TRUE; break; case 'r': /* Restart */ req_restart = TRUE; break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; default: ++argerr; break; } } 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) { long pid; ll_cluster_t* hb_fd = NULL; int facility; IPC_Channel *crm_ch = NULL; #ifdef REALTIME_SUPPORT static int crm_realtime = 1; #endif if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { cl_log(LOG_CRIT, "already running: [pid %ld].", pid); exit(LSB_EXIT_OK); } cl_log_set_logfile(DAEMON_LOG); // if (crm_debug()) { cl_log_set_debugfile(DAEMON_DEBUG); // } /* change the logging facility to the one used by heartbeat daemon */ hb_fd = ll_cluster_new("heartbeat"); cl_log(LOG_INFO, "Switching to Heartbeat logger"); if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { cl_log_set_facility(facility); } cl_log(LOG_INFO, "Register PID"); register_pid(PID_FILE, FALSE, pengine_shutdown); - crm_ch = init_client_ipc_comms("crmd", pe_input_dispatch, NULL); + crm_ch = init_client_ipc_comms("crmd", + subsystem_input_dispatch, + (void*)process_pe_message); if(crm_ch != NULL) { send_hello_message(crm_ch, "1234", CRM_SYSTEM_PENGINE, "0", "1"); /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); cl_log(LOG_INFO, "Starting %s", 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 g_main_run(mainloop); } else { cl_log(LOG_ERR, "Could not connect to the CRMd"); } return_to_orig_privs(); if (unlink(PID_FILE) == 0) { cl_log(LOG_INFO, "[%s] stopped", crm_system_name); } if(crm_ch != NULL) return 0; return 1; } 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); } void pengine_shutdown(int nsig) { static int shuttingdown = 0; CL_SIGNAL(nsig, pengine_shutdown); if (!shuttingdown) { shuttingdown = 1; } if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); }else{ exit(LSB_EXIT_OK); } } diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c index 094f528f60..7cb6c94360 100644 --- a/crm/tengine/tengine.c +++ b/crm/tengine/tengine.c @@ -1,347 +1,488 @@ #include #include #include #include +#include #include GSListPtr graph = NULL; IPC_Channel *crm_ch = NULL; typedef struct action_list_s { int index; int index_max; GSListPtr actions; } action_list_t; +gboolean initialize_graph(void); +gboolean unpack_graph(xmlNodePtr xml_graph); +gboolean extract_event(xmlNodePtr msg); +gboolean initiate_transition(void); gboolean initiate_action(xmlNodePtr xml_action); gboolean process_graph_event(const char *event_node, const char *event_rsc, const char *event_action, const char *event_status, const char *event_rc); +void send_success(void); +void send_abort(void); +gboolean process_fake_event(xmlNodePtr msg); + + gboolean initialize_graph(void) { while(g_slist_length(graph) > 0) { action_list_t *action_list = g_slist_nth_data(graph, 0); while(g_slist_length(action_list->actions) > 0) { GSListPtr action = g_slist_nth(action_list->actions, 0); g_slist_remove(action_list->actions, action); cl_free(action->data); } g_slist_remove(graph, action_list); } graph = NULL; return TRUE; } gboolean unpack_graph(xmlNodePtr xml_graph) { /* */ - - xmlNodePtr xml_action_list = xml_graph->children; + xmlNodePtr xml_action_list = xml_graph?xml_graph->children:NULL; + if(xml_action_list == NULL) { + // nothing to do + return FALSE; + } + while(xml_action_list != NULL) { xmlNodePtr xml_obj = xml_action_list; xmlNodePtr xml_action = xml_obj->children; action_list_t *action_list = (action_list_t*) cl_malloc(sizeof(action_list_t)); xml_action_list = xml_action_list->next; action_list->index = 0; action_list->index_max = 0; while(xml_action != NULL) { xmlNodePtr action = copy_xml_node_recursive(xml_action); action_list->actions = g_slist_append(action_list->actions, action); action_list->index_max++; } graph = g_slist_append(graph, action_list); } return TRUE; } gboolean -process_event(xmlNodePtr msg) +process_fake_event(xmlNodePtr msg) +{ + xmlNodePtr data = find_xml_node(msg, "lrm_resource"); + return process_graph_event(xmlGetProp(data, "op_node"), + xmlGetProp(data, "id"), + xmlGetProp(data, "last_op"), + xmlGetProp(data, "op_status"), + xmlGetProp(data, "op_code")); +} + +gboolean +extract_event(xmlNodePtr msg) { + gboolean abort = FALSE; + xmlNodePtr iter = NULL; + const char *section = NULL; + const char *event_action = NULL; const char *event_node = NULL; const char *event_rsc = NULL; const char *event_status = NULL; const char *event_rc = NULL; - xmlNodePtr data = find_xml_node(msg, "lrm_resource"); - - if(data != NULL) { - event_action = xmlGetProp(data, "last_op"); - event_node = xmlGetProp(data, "op_node"); - event_rsc = xmlGetProp(data, "id"); - event_status = xmlGetProp(data, "op_status"); - event_rc = xmlGetProp(data, "op_code"); - - return process_graph_event(event_node, event_rsc, event_action, - event_status, event_rc); - } +/* + + + + + +*/ - data = find_xml_node(msg, "crm_events"); + xml_message_debug(msg, "TE Event"); - if(data != NULL) { - event_node = xmlGetProp(data->children, XML_ATTR_ID); - event_status = xmlGetProp(data->children, "state"); - event_rc = xmlGetProp(data->children, "op_code"); - if(safe_str_eq(event_status, "down")) { - event_action = "shutdown"; - } + iter = find_xml_node(msg, XML_TAG_FRAGMENT); + section = xmlGetProp(iter, "section"); + + if(safe_str_neq(section, XML_CIB_TAG_STATUS)) { + // these too are never expected + send_abort(); + return FALSE; + } + + iter = find_xml_node(msg, XML_TAG_CIB); + iter = get_object_root(XML_CIB_TAG_STATUS, iter); + iter = iter->children; + + while(abort == FALSE && iter != NULL) { + xmlNodePtr node_state = iter; + xmlNodePtr child = iter->children; + const char *state = xmlGetProp(node_state, "state"); + iter = iter->next; + + if(state != NULL && child == NULL) { + /* node state update, + * possibly from a shutdown we requested + */ + event_status = state; + event_node = xmlGetProp(node_state, XML_ATTR_ID); + if(safe_str_eq(event_status, "down")) { + event_action = "shutdown"; + } + + abort = !process_graph_event(event_node, + event_rsc, + event_action, + event_status, + event_rc); + + } else if(state != NULL && child != NULL) { + /* this is a complex eventand could not be completely + * due to any request we made + */ + send_abort(); + abort = TRUE; - return process_graph_event(event_node, event_rsc, event_action, - event_status, event_rc); + } else { + child = find_xml_node(node_state, "lrm"); + child = find_xml_node(child, "lrm_resources"); + child = child->children; + + while(abort == FALSE && child != NULL) { + event_action = xmlGetProp(child, "last_op"); + event_node = xmlGetProp(child, "op_node"); + event_rsc = xmlGetProp(child, "id"); + event_status = xmlGetProp(child, "op_status"); + event_rc = xmlGetProp(child, "op_code"); + + abort = !process_graph_event(event_node, + event_rsc, + event_action, + event_status, + event_rc); + + child = child->next; + } + } } - - // error: not (yet?) supported - return FALSE; + return !abort; } gboolean process_graph_event(const char *event_node, const char *event_rsc, const char *event_action, const char *event_status, const char *event_rc) { int lpc; xmlNodePtr action = NULL; // or xmlNodePtr next_action = NULL; // Find the action corresponding to this event slist_iter( action_list, action_list_t, graph, lpc, action = g_slist_nth_data(action_list->actions, action_list->index); /* */ const char *this_action = xmlGetProp(action, "task"); const char *this_node = xmlGetProp(action, "on_node"); const char *this_rsc = xmlGetProp(action->children, "id"); if(safe_str_neq(this_node, event_node)) { continue; } else if(safe_str_neq(this_action, event_action)) { continue; } else if(safe_str_eq(action->name, "rsc_op") && safe_str_eq(this_rsc, event_rsc)) { action_list->index++; next_action = g_slist_nth_data(action_list->actions, action_list->index); } else if(safe_str_eq(action->name, "crm_event")) { action_list->index++; next_action = g_slist_nth_data(action_list->actions, action_list->index); } ); // for the moment all actions succeed if(action == NULL) { // unexpected event, trigger a pe-recompute // possibly do this only for certain types of actions - xmlNodePtr options = create_xml_node(NULL, "options"); - set_xml_property_copy(options, "op", "pe_restart"); - - send_ipc_request(crm_ch, options, NULL, - NULL, "dc", "tengine", - NULL, NULL); - - free_xml(options); + send_abort(); } else if(next_action == NULL) { /* last action in that list, check if there are * anymore actions at all */ gboolean more_to_do = FALSE; slist_iter( action_list, action_list_t, graph, lpc, if(action_list->index <= action_list->index_max){ more_to_do = TRUE; break; } ); if(more_to_do == FALSE) { // indicate to the CRMd that we're done xmlNodePtr options = create_xml_node(NULL, "options"); - set_xml_property_copy(options, "op", "te_complete"); + set_xml_property_copy(options, XML_ATTR_OP, "te_complete"); send_ipc_request(crm_ch, options, NULL, NULL, "dc", "tengine", NULL, NULL); free_xml(options); return TRUE; } // else wait for the next event } else { return initiate_action(next_action); } return FALSE; } gboolean initiate_transition(void) { int lpc; + gboolean anything = FALSE; xmlNodePtr action = NULL; FNIN(); slist_iter( action_list, action_list_t, graph, lpc, action = g_slist_nth_data(action_list->actions, action_list->index); - initiate_action(action); - + if(action != NULL) { + anything = TRUE; + initiate_action(action); + } + action_list->index++; ); - FNRET(TRUE); + FNRET(anything); } gboolean initiate_action(xmlNodePtr xml_action) { // initiate the next action const char *on_node = xmlGetProp(xml_action, "on_node"); const char *id = xmlGetProp(xml_action, "id"); // const char *runnable = xmlGetProp(xml_action, "runnable"); // const char *optional = xmlGetProp(xml_action, "optional"); const char *task = xmlGetProp(xml_action, "task"); FNIN(); cl_log(LOG_INFO, "Invoking action %s (id=%s) on %s", task, id, on_node); if(id == NULL || strlen(id) == 0 || on_node == NULL || strlen(on_node) == 0 || task == NULL || strlen(task) == 0) { // error cl_log(LOG_ERR, "Command: \"%s (id=%s) on %s\" was corrupted.", task, id, on_node); FNRET(FALSE); // } else if(safe_str_eq(xml_action->name, "pseduo_event")){ } else if(safe_str_eq(xml_action->name, "crm_event")){ /* */ xmlNodePtr options = create_xml_node(NULL, "options"); - set_xml_property_copy(options, "op", task); + set_xml_property_copy(options, XML_ATTR_OP, task); send_ipc_request(crm_ch, options, NULL, on_node, "crmd", "tengine", NULL, NULL); free_xml(options); } else if(safe_str_eq(xml_action->name, "rsc_op")){ /* ... */ xmlNodePtr options = create_xml_node(NULL, "options"); xmlNodePtr data = create_xml_node(NULL, "msg_data"); xmlNodePtr rsc_op = create_xml_node(data, "rsc_op"); - set_xml_property_copy(options, "op", "rsc_op"); + set_xml_property_copy(options, XML_ATTR_OP, "rsc_op"); set_xml_property_copy(rsc_op, "id", id); set_xml_property_copy(rsc_op, "task", task); set_xml_property_copy(rsc_op, "on_node", on_node); add_node_copy(rsc_op, xml_action->children); send_ipc_request(crm_ch, options, data, on_node, "lrmd", "tengine", NULL, NULL); free_xml(options); free_xml(data); } else { // error cl_log(LOG_ERR, "Action %s is not (yet?) supported", xml_action->name); FNRET(FALSE); } FNRET(TRUE); } -void -process_te_message(xmlNodePtr msg) +gboolean +process_te_message(xmlNodePtr msg, IPC_Channel *sender) { - const char *op = get_xml_attr (msg, XML_TAG_OPTIONS,XML_ATTR_OP, TRUE); + const char *op = get_xml_attr (msg, XML_TAG_OPTIONS, + XML_ATTR_OP, TRUE); + + const char *sys_to = xmlGetProp(msg, XML_ATTR_SYSTO); + cl_log(LOG_DEBUG, "Processing %s message", op); + if(op == NULL){ // error - } else if(strcmp(op, "transition")) { + } else if(sys_to == NULL || strcmp(sys_to, "tengine") != 0) { + CRM_DEBUG("Bad sys-to %s", sys_to); + return FALSE; + + } else if(strcmp(op, "transition") == 0) { initialize_graph(); - unpack_graph(msg); - initiate_transition(); + + xmlNodePtr graph = find_xml_node(msg, "transition_graph"); + unpack_graph(graph); + if(initiate_transition() == FALSE) { + // nothing to be done.. means we're done. + cl_log(LOG_INFO, "No actions to be taken..." + " transition compelte."); + send_success(); + } - } else if(strcmp(op, "event")) { - process_event(msg); - } else if(strcmp(op, "abort")) { + } else if(strcmp(op, "event") == 0) { + const char *true_op = get_xml_attr (msg, XML_TAG_OPTIONS, + "true_op", TRUE); + if(true_op == NULL) { +#ifdef USE_FAKE_LRM + process_fake_event(msg); +#else + // error +#endif + } else if(strcmp(op, CRM_OPERATION_CREATE) == 0 + || strcmp(op, CRM_OPERATION_DELETE) == 0 + || strcmp(op, CRM_OPERATION_REPLACE) == 0 + || strcmp(op, CRM_OPERATION_WELCOME) == 0 + || strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0 + || strcmp(op, CRM_OPERATION_ERASE) == 0) { + + // these are always unexpected, trigger the PE + send_abort(); + + } else if(strcmp(op, CRM_OPERATION_UPDATE) == 0) { + // this may not be un-expected + extract_event(msg); + + } else { + cl_log(LOG_ERR, + "Did not expect copy of action %s", op); + } + + } else if(strcmp(op, "abort") == 0) { initialize_graph(); - } else if(strcmp(op, "quit")) { + } else if(strcmp(op, "quit") == 0) { cl_log(LOG_WARNING, "Received quit message, terminating"); exit(0); } -/* - answer = process_te_message(root_xml_node); - if (send_xmlipc_message(sender, answer)==FALSE) - cl_log(LOG_WARNING, "Cib answer could not be sent"); -*/ -// return NULL; + return TRUE; +} + +void +send_abort(void) +{ + xmlNodePtr options = create_xml_node(NULL, "options"); + + CRM_DEBUG("Sending \"abort\" message"); + + set_xml_property_copy(options, XML_ATTR_OP, "te_abort"); + + send_ipc_request(crm_ch, options, NULL, + NULL, "dc", "tengine", + NULL, NULL); + + free_xml(options); +} + +void +send_success(void) +{ + xmlNodePtr options = create_xml_node(NULL, "options"); + + CRM_DEBUG("Sending \"complete\" message"); + + set_xml_property_copy(options, XML_ATTR_OP, "te_complete"); + + send_ipc_request(crm_ch, options, NULL, + NULL, "dc", "tengine", + NULL, NULL); + + free_xml(options); } diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h index 0b7e97b511..7c96d043ff 100644 --- a/crm/tengine/tengine.h +++ b/crm/tengine/tengine.h @@ -1,15 +1,10 @@ #ifndef TENGINE__H #define TENGINE__H -extern gboolean initialize_graph(void); -extern gboolean unpack_graph(xmlNodePtr xml_graph); -extern gboolean process_event(xmlNodePtr msg); -extern gboolean initiate_transition(void); -extern gboolean te_input_dispatch(IPC_Channel *sender, void *user_data); -extern void process_te_message(xmlNodePtr msg); +extern gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender); extern IPC_Channel *crm_ch; #endif