diff --git a/crm/admin/adminmain.c b/crm/admin/adminmain.c index 027e751493..dc7eaf8424 100644 --- a/crm/admin/adminmain.c +++ b/crm/admin/adminmain.c @@ -1,636 +1,636 @@ -/* $Id: adminmain.c,v 1.25 2004/06/01 12:25:14 andrew Exp $ */ +/* $Id: adminmain.c,v 1.26 2004/06/01 16:12:49 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 = XML_BOOLEAN_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_OP_ERASE, 0, 0, 0}, {CRM_OP_QUERY, 0, 0, 0}, {CRM_OP_CREATE, 0, 0, 0}, {CRM_OP_REPLACE, 0, 0, 0}, {CRM_OP_STORE, 0, 0, 0}, {CRM_OP_UPDATE, 0, 0, 0}, {CRM_OP_DELETE, 0, 0, 0}, {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"reference", 1, 0, 0}, // common options {XML_ATTR_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_OP_ERASE, long_options[option_index].name) == 0 || strcmp(CRM_OP_CREATE, long_options[option_index].name) == 0 || strcmp(CRM_OP_UPDATE, long_options[option_index].name) == 0 || strcmp(CRM_OP_DELETE, long_options[option_index].name) == 0 || strcmp(CRM_OP_REPLACE, long_options[option_index].name) == 0 || strcmp(CRM_OP_STORE, long_options[option_index].name) == 0 || strcmp(CRM_OP_QUERY, long_options[option_index].name) == 0){ cib_action = crm_strdup(long_options[option_index].name); } else if (strcmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_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 = XML_BOOLEAN_TRUE; break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'i': CRM_DEBUG("Option %c => %s", flag, optarg); id = crm_strdup(optarg); break; case 'o': CRM_DEBUG("Option %c => %s", flag, optarg); obj_type = crm_strdup(optarg); break; case 'C': printf("Option %c is not yet supported\n", flag); ++argerr; break; case 'S': DO_HEALTH = TRUE; status = crm_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"); + CRM_NOTE("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_OP_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_OP_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_OP_ERASE, cib_action) == 0) { set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OP_ERASE); dest_node = status; - CRM_DEBUG("CIB Erase op in progress"); + CRM_NOTE("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"); + CRM_NOTE("Querying the system"); sys_to = CRM_SYSTEM_DC; if (status != NULL) { sys_to = CRM_SYSTEM_CRMD; ping_type = CRM_OP_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 = crm_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); 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"); + CRM_NOTE("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 = crm_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/cib.c b/crm/cib/cib.c index 0524c52a8f..65d2cc9f5d 100644 --- a/crm/cib/cib.c +++ b/crm/cib/cib.c @@ -1,319 +1,315 @@ -/* $Id: cib.c,v 1.37 2004/06/01 12:25:14 andrew Exp $ */ +/* $Id: cib.c,v 1.38 2004/06/01 16:12:49 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 gboolean startCib(const char *filename) { xmlNodePtr cib = readCibXmlFile(filename); if (initializeCib(cib)) { cl_log(LOG_INFO, "CIB Initialization completed successfully"); } else { // free_xml(cib); cl_log(LOG_WARNING, "CIB Initialization failed, " "starting with an empty default."); activateCibXml(createEmptyCib(), filename); } return TRUE; } xmlNodePtr get_cib_copy() { return copy_xml_node_recursive(get_the_CIB()); } /* * The caller should never free the return value */ xmlNodePtr get_object_root(const char *object_type, xmlNodePtr the_root) { const char *node_stack[2]; xmlNodePtr tmp_node = NULL; FNIN(); node_stack[0] = XML_CIB_TAG_CONFIGURATION; node_stack[1] = object_type; if(object_type == NULL || strlen(object_type) == 0) { FNRET(the_root); /* get the whole cib */ } else if(strcmp(object_type, XML_CIB_TAG_STATUS) == 0) { node_stack[0] = XML_CIB_TAG_STATUS; node_stack[1] = NULL; /* these live in a different place */ } tmp_node = find_xml_node_nested(the_root, node_stack, 2); if (tmp_node == NULL) { cl_log(LOG_ERR, "[cib] Section cib[%s[%s]] not present", node_stack[0], node_stack[1]); } FNRET(tmp_node); } xmlNodePtr process_cib_message(xmlNodePtr message, gboolean auto_reply) { xmlNodePtr data; xmlNodePtr reply; enum cib_result result = CIBRES_OK; xmlNodePtr fragment = find_xml_node(message, XML_TAG_FRAGMENT); xmlNodePtr options = find_xml_node(message, XML_TAG_OPTIONS); const char *op = get_xml_attr (message, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); data = cib_process_request(op, options, fragment, &result); CRM_DEBUG("[cib] operation returned result %d", result); if(auto_reply) { reply = create_reply(message, data); free_xml(data); // TODO: put real result in here set_xml_attr(reply, XML_TAG_OPTIONS, XML_ATTR_RESULT, "ok", TRUE); return reply; } return data; } xmlNodePtr process_cib_request(const char *op, const xmlNodePtr options, const xmlNodePtr fragment) { enum cib_result result = CIBRES_OK; return cib_process_request(op, options, fragment, &result); } xmlNodePtr create_cib_fragment(xmlNodePtr update, const char *section) { gboolean whole_cib = FALSE; xmlNodePtr fragment = create_xml_node(NULL, XML_TAG_FRAGMENT); xmlNodePtr cib = NULL; xmlNodePtr object_root = NULL; char *auto_section = pluralSection(update?update->name:NULL); if(update == NULL) { cl_log(LOG_ERR, "No update to create a fragment for"); crm_free(auto_section); return NULL; } else if(section == NULL) { section = auto_section; } else if(strcmp(auto_section, section) != 0) { cl_log(LOG_ERR, "Values for update (tag=%s) and section (%s)" " were not consistent", update->name, section); crm_free(auto_section); return NULL; } if(strcmp(section, "all")==0 && strcmp(update->name, XML_TAG_CIB)==0) { whole_cib = TRUE; } set_xml_property_copy(fragment, XML_ATTR_SECTION, section); if(whole_cib == FALSE) { cib = createEmptyCib(); object_root = get_object_root(section, cib); xmlAddChildList(object_root, xmlCopyNodeList(update)); } else { cib = xmlCopyNodeList(update); } xmlAddChild(fragment, cib); - CRM_DEBUG("Fragment created"); - - xml_message_debug(fragment, "created fragment"); - crm_free(auto_section); return fragment; } char * pluralSection(const char *a_section) { char *a_section_parent = NULL; if (a_section == NULL) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_TAG_CIB) == 0) { a_section_parent = crm_strdup("all"); } else if(strcmp(a_section, XML_CIB_TAG_NODE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_NODES); } else if(strcmp(a_section, XML_CIB_TAG_STATE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_STATUS); } else if(strcmp(a_section, XML_CIB_TAG_CONSTRAINT) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_CONSTRAINTS); } else if(strcmp(a_section, XML_CIB_TAG_RESOURCE) == 0) { a_section_parent = crm_strdup(XML_CIB_TAG_RESOURCES); } else { cl_log(LOG_ERR, "Unknown section %s", a_section); a_section_parent = crm_strdup("all"); } CRM_DEBUG("Plural is %s", a_section_parent); return a_section_parent; } const char * cib_error2string(enum cib_result return_code) { const char *error_msg = NULL; switch(return_code) { case CIBRES_MISSING_ID: error_msg = "The id field is missing"; break; case CIBRES_MISSING_TYPE: error_msg = "The type field is missing"; break; case CIBRES_MISSING_FIELD: error_msg = "A required field is missing"; break; case CIBRES_OBJTYPE_MISMATCH: error_msg = "CIBRES_OBJTYPE_MISMATCH"; break; case CIBRES_FAILED_EXISTS: error_msg = "The object already exists"; break; case CIBRES_FAILED_NOTEXISTS: error_msg = "The object does not exist"; break; case CIBRES_CORRUPT: error_msg = "The CIB is corrupt"; break; case CIBRES_FAILED_NOOBJECT: error_msg = "The update was empty"; break; case CIBRES_FAILED_NOPARENT: error_msg = "The parent object does not exist"; break; case CIBRES_FAILED_NODECOPY: error_msg = "Failed while copying update"; break; case CIBRES_OTHER: error_msg = "CIBRES_OTHER"; break; case CIBRES_OK: error_msg = "ok"; break; case CIBRES_FAILED: error_msg = "Failed"; break; case CIBRES_FAILED_STALE: error_msg = "Discarded old update"; break; case CIBRES_FAILED_ACTIVATION: error_msg = "Activation Failed"; break; case CIBRES_FAILED_NOSECTION: error_msg = "Required section was missing"; break; case CIBRES_FAILED_NOTSUPPORTED: error_msg = "Supplied information is not supported"; break; } if(error_msg == NULL) { cl_log(LOG_ERR, "Unknown CIB Error %d", return_code); error_msg = ""; } return error_msg; } const char * cib_op2string(enum cib_op operation) { const char *operation_msg = NULL; switch(operation) { case 0: operation_msg = "none"; break; case 1: operation_msg = "add"; break; case 2: operation_msg = "modify"; break; case 3: operation_msg = "delete"; break; case CIB_OP_MAX: operation_msg = "invalid operation"; break; } if(operation_msg == NULL) { cl_log(LOG_ERR, "Unknown CIB operation %d", operation); operation_msg = ""; } return operation_msg; } diff --git a/crm/cib/cibio.c b/crm/cib/cibio.c index 95c9304c8e..cd777508f3 100644 --- a/crm/cib/cibio.c +++ b/crm/cib/cibio.c @@ -1,434 +1,428 @@ -/* $Id: cibio.c,v 1.23 2004/06/01 12:25:14 andrew Exp $ */ +/* $Id: cibio.c,v 1.24 2004/06/01 16:12:49 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 // for getNow() #include #include #include const char * local_resource_path[] = { XML_CIB_TAG_STATUS, }; const char * resource_path[] = { XML_CIB_TAG_RESOURCES, }; const char * node_path[] = { XML_CIB_TAG_NODES, }; const char * constraint_path[] = { XML_CIB_TAG_CONSTRAINTS, }; gboolean initialized = FALSE; xmlNodePtr the_cib = NULL; xmlNodePtr node_search = NULL; xmlNodePtr resource_search = NULL; xmlNodePtr constraint_search = NULL; xmlNodePtr status_search = NULL; /* * It is the callers responsibility to free both the new CIB (output) * and the new CIB (input) */ xmlNodePtr createEmptyCib(void) { xmlNodePtr cib_root = NULL, config = NULL, status = NULL; cib_root = create_xml_node(NULL, XML_TAG_CIB); config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION); status = create_xml_node(cib_root, XML_CIB_TAG_STATUS); set_node_tstamp(cib_root); set_node_tstamp(config); set_node_tstamp(status); set_xml_property_copy(cib_root, "version", "1"); set_xml_property_copy(cib_root, "generated", XML_BOOLEAN_TRUE); create_xml_node(config, XML_CIB_TAG_NODES); create_xml_node(config, XML_CIB_TAG_RESOURCES); create_xml_node(config, XML_CIB_TAG_CONSTRAINTS); if (verifyCibXml(cib_root)) { FNRET(cib_root); } cl_log(LOG_CRIT, "The generated CIB did not pass integrity testing!!" " All hope is lost."); FNRET(NULL); } gboolean verifyCibXml(xmlNodePtr cib) { gboolean is_valid = TRUE; xmlNodePtr tmp_node = NULL; FNIN(); if (cib == NULL) { cl_log(LOG_ERR, "XML Buffer was empty."); FNRET(FALSE); } tmp_node = get_object_root(XML_CIB_TAG_NODES, cib); if (tmp_node == NULL) is_valid = FALSE; tmp_node = get_object_root(XML_CIB_TAG_RESOURCES, cib); if (tmp_node == NULL) is_valid = FALSE; tmp_node = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); if (tmp_node == NULL) is_valid = FALSE; tmp_node = get_object_root(XML_CIB_TAG_STATUS, cib); if (tmp_node == NULL) is_valid = FALSE; // more integrity tests FNRET(is_valid); } /* * It is the callers responsibility to free the output of this function */ xmlNodePtr readCibXml(char *buffer) { xmlNodePtr root = string2xml(buffer); if (verifyCibXml(root) == FALSE) { free_xml(root); FNRET(createEmptyCib()); } FNRET(root); } /* * It is the callers responsibility to free the output of this function */ xmlNodePtr readCibXmlFile(const char *filename) { int s_res = -1; struct stat buf; xmlNodePtr root = NULL; FNIN(); if(filename != NULL) { s_res = stat(filename, &buf); } if (s_res == 0) { FILE *cib_file = fopen(filename, "r"); root = file2xml(cib_file); set_xml_property_copy(root, "generated", XML_BOOLEAN_FALSE); fclose(cib_file); } else { cl_log(LOG_WARNING, "Stat of (%s) failed, file does not exist.", CIB_FILENAME); } if (verifyCibXml(root) == FALSE) { free_xml(root); // FNRET(createEmptyCib()); root = NULL; } FNRET(root); } /* * The caller should never free the return value */ xmlNodePtr get_the_CIB(void) { FNIN(); FNRET(the_cib); } gboolean uninitializeCib(void) { xmlNodePtr tmp_cib = the_cib; FNIN(); if(tmp_cib == NULL) { cl_log(LOG_ERR, "The CIB has already been deallocated."); FNRET(FALSE); } initialized = FALSE; the_cib = NULL; node_search = NULL; resource_search = NULL; constraint_search = NULL; status_search = NULL; cl_log(LOG_WARNING, "Deallocating the CIB."); free_xml(tmp_cib); cl_log(LOG_WARNING, "The CIB has been deallocated."); FNRET(TRUE); } /* * This method will not free the old CIB pointer or the new one. * We rely on the caller to have saved a pointer to the old CIB * and to free the old/bad one depending on what is appropriate. */ gboolean initializeCib(xmlNodePtr new_cib) { if (verifyCibXml(new_cib)) { initialized = FALSE; the_cib = new_cib; // update search paths /* not used yet... node_search = get_object_root(XML_CIB_TAG_NODES, new_cib); resource_search = get_object_root(XML_CIB_TAG_RESOURCES, new_cib); constraint_search = get_object_root(XML_CIB_TAG_CONSTRAINTS, new_cib); status_search = get_object_root(XML_CIB_TAG_STATUS, new_cib); */ initialized = TRUE; - CRM_DEBUG("CIB initialized"); + CRM_NOTE("CIB initialized"); FNRET(TRUE); } else { cl_log(LOG_ERR, "CIB Verification failed"); } FNRET(FALSE); } int moveFile(const char *oldname, const char *newname, gboolean backup, char *ext) { /* move 'oldname' to 'newname' by creating a hard link to it * and then removing the original hard link */ int res = 0; struct stat tmp; int s_res = stat(newname, &tmp); FNIN(); - cl_log(LOG_INFO, "Stat of %s (code: %d).", newname, s_res); if (s_res >= 0) { if (backup == TRUE) { char backname[1024]; static const char *back_ext = "bak"; if (ext != NULL) back_ext = (char*)ext; snprintf(backname, sizeof(backname)-1, "%s.%s", newname, back_ext); moveFile(newname, backname, FALSE, NULL); } else { res = unlink(newname); if (res < 0) { perror("Could not remove the current backup of Cib"); FNRET(-1); } } } s_res = stat(oldname, &tmp); - cl_log(LOG_INFO, "Stat of %s (code: %d).", oldname, s_res); if (s_res >= 0) { res = link(oldname, newname); if (res < 0) { perror("Could not create backup of current Cib"); FNRET(-2); } res = unlink(oldname); if (res < 0) { perror("Could not unlink the current Cib"); FNRET(-3); } } FNRET(0); } int activateCibBuffer(char *buffer, const char *filename) { int result = -1; xmlNodePtr local_cib = NULL; FNIN(); local_cib = readCibXml(buffer); result = activateCibXml(local_cib, filename); FNRET(result); } /* * This method will free the old CIB pointer on success and the new one * on failure. */ int activateCibXml(xmlNodePtr new_cib, const char *filename) { int error_code = 0; xmlNodePtr saved_cib = get_the_CIB(); const char *filename_bak = CIB_BACKUP; // calculate xmlDocPtr foo; FNIN(); if (initializeCib(new_cib) == TRUE) { int res = moveFile(filename, filename_bak, FALSE, NULL); if (res < 0) { cl_log(LOG_INFO, "Could not make backup of the current Cib " "(code: %d)... aborting update.", res); error_code = -1; } else { cl_log(LOG_INFO, "Writing CIB out to %s", CIB_FILENAME); if (new_cib->doc == NULL) { - cl_log(LOG_INFO, - "Writing of a node tree with a NULL " - "document will fail, creating a new " - "back link."); foo = xmlNewDoc("1.0"); xmlDocSetRootElement(foo, new_cib); xmlSetTreeDoc(new_cib,foo); } time_t now = time(NULL); char *now_str = asctime(localtime(&now)); set_xml_property_copy(new_cib, "last_written",now_str); free(now_str); /* save it. * set arg 3 to 0 to disable line breaks,1 to enable * res == num bytes saved */ res = xmlSaveFormatFile(filename, new_cib->doc, 1); /* for some reason, reading back after saving with * line-breaks doesnt go real well */ cl_log(LOG_INFO, "Saved %d bytes to the Cib as XML", res); if (res < 0) { // assume 0 is good if (moveFile(filename_bak, filename, FALSE, NULL) < -1) { cl_log(LOG_CRIT, "Could not restore the " "backup of the current Cib " "(code: %d)... panic!", res); error_code = -2; // should probably exit here } else if (initializeCib(saved_cib) == FALSE) { // oh we are so dead cl_log(LOG_CRIT, "Could not re-initialize " "with the old CIB. " "Everything is about to go " "pear shaped"); error_code = -3; } else { cl_log(LOG_CRIT, "Update of Cib failed " "(code: %d)... reverted to " "last known valid version", res); error_code = -4; } } } } else { cl_log(LOG_INFO, "Ignoring invalid or NULL Cib"); error_code = -5; } // Make sure memory is cleaned up appropriately if (error_code != 0) { // CRM_DEBUG("Freeing new CIB %p", new_cib); free_xml(new_cib); } else { // CRM_DEBUG("Freeing saved CIB %p", saved_cib); free_xml(saved_cib); } FNRET(error_code); } diff --git a/crm/cib/cibmessages.c b/crm/cib/cibmessages.c index 057c91a546..25afee803b 100644 --- a/crm/cib/cibmessages.c +++ b/crm/cib/cibmessages.c @@ -1,478 +1,477 @@ -/* $Id: cibmessages.c,v 1.36 2004/06/01 12:25:14 andrew Exp $ */ +/* $Id: cibmessages.c,v 1.37 2004/06/01 16:12:49 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 FILE *msg_cib_strm = NULL; enum cib_result updateList(xmlNodePtr local_cib, xmlNodePtr update_command, xmlNodePtr failed, int operation, const char *section); xmlNodePtr createCibFragmentAnswer(const char *section, xmlNodePtr failed); gboolean replace_section(const char *section, xmlNodePtr tmpCib, xmlNodePtr command); gboolean check_generation(xmlNodePtr newCib, xmlNodePtr oldCib); gboolean update_results(xmlNodePtr failed, xmlNodePtr target, int operation, int return_code); xmlNodePtr cib_process_request(const char *op, const xmlNodePtr options, const xmlNodePtr fragment, enum cib_result *result) { const char *verbose = NULL; const char *section = NULL; const char *output_section = NULL; xmlNodePtr failed = NULL; xmlNodePtr cib_answer = NULL; gboolean update_the_cib = FALSE; int cib_update_op = CIB_OP_NONE; xmlNodePtr tmpCib; char *new_value = NULL; char *old_value = NULL; int int_value = -1; FNIN(); *result = CIBRES_OK; verbose = xmlGetProp(options, XML_ATTR_VERBOSE); section = xmlGetProp(options, XML_ATTR_FILTER_TYPE); failed = create_xml_node(NULL, XML_TAG_FAILED); #ifdef MSG_LOG if(msg_cib_strm == NULL) { msg_cib_strm = fopen("/tmp/cib.log", "w"); } fprintf(msg_cib_strm, "[Input %s]\t%s\n", op, dump_xml_node(fragment, FALSE)); fflush(msg_cib_strm); #endif cl_log(LOG_DEBUG, "[cib] Processing \"%s\" event", op); if(op == NULL) { *result = CIBRES_FAILED; cl_log(LOG_ERR, "No operation specified\n"); } else if(strcmp("noop", op) == 0) { ; } else if(strcmp(CRM_OP_QUIT, op) == 0) { cl_log(LOG_WARNING, "The CRMd has asked us to exit... complying"); exit(0); } else if (strcmp(CRM_OP_PING, op) == 0) { cib_answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok"); } else if (strcmp(CRM_OP_BUMP, op) == 0) { tmpCib = get_cib_copy(); CRM_DEBUG("Handling a %s for section=%s of the cib", CRM_OP_BUMP, section); // modify the timestamp set_node_tstamp(tmpCib); old_value = xmlGetProp(get_the_CIB(), XML_ATTR_GENERATION); if(old_value != NULL) { new_value = (char*)crm_malloc(128*(sizeof(char))); int_value = atoi(old_value); sprintf(new_value, "%d", ++int_value); } else { new_value = crm_strdup("0"); } cl_log(LOG_DEBUG, "Generation %d(%s)->%s", int_value, old_value, new_value); set_xml_property_copy(tmpCib, XML_ATTR_GENERATION, new_value); crm_free(new_value); if(activateCibXml(tmpCib, CIB_FILENAME) >= 0) { verbose = XML_BOOLEAN_TRUE; } else { *result = CIBRES_FAILED; } } else if (strcmp("query", op) == 0) { CRM_DEBUG("Handling a query for section=%s of the cib", section); /* force a pick-up of the relevant section before * returning */ verbose = XML_BOOLEAN_TRUE; } else if (strcmp(CRM_OP_ERASE, op) == 0) { xmlNodePtr new_cib = createEmptyCib(); // Preserve generation counters etc copy_in_properties(new_cib, get_the_CIB()); if (activateCibXml(new_cib, CIB_FILENAME) < 0) { *result = CIBRES_FAILED; } } else if (strcmp(CRM_OP_CREATE, op) == 0) { update_the_cib = TRUE; cib_update_op = CIB_OP_ADD; } else if (strcmp(CRM_OP_UPDATE, op) == 0 || strcmp(CRM_OP_WELCOME, op) == 0 || strcmp(CRM_OP_SHUTDOWN_REQ, op) == 0) { update_the_cib = TRUE; cib_update_op = CIB_OP_MODIFY; } else if (strcmp(CRM_OP_DELETE, op) == 0) { update_the_cib = TRUE; cib_update_op = CIB_OP_DELETE; } else if (strcmp(CRM_OP_REPLACE, op) == 0) { CRM_DEBUG("Replacing section=%s of the cib", section); section = xmlGetProp(fragment, XML_ATTR_SECTION); if (section == NULL || strlen(section) == 0 || strcmp("all", section) == 0) { tmpCib = copy_xml_node_recursive( find_xml_node(fragment, XML_TAG_CIB)); } else { tmpCib = copy_xml_node_recursive(get_the_CIB()); replace_section(section, tmpCib, fragment); } /*if(check_generation(cib_updates, tmpCib) == FALSE) *result = "discarded old update"; else */ if (activateCibXml(tmpCib, CIB_FILENAME) < 0) *result = CIBRES_FAILED; } else { *result = CIBRES_FAILED_NOTSUPPORTED; cl_log(LOG_ERR, "Action [%s] is not supported by the CIB", op); } if (update_the_cib) { - CRM_DEBUG("Backing up CIB"); tmpCib = copy_xml_node_recursive(get_the_CIB()); section = xmlGetProp(fragment, XML_ATTR_SECTION); CRM_DEBUG("Updating section=%s of the cib (op=%s)", section, op); // should we be doing this? // do logging // make changes to a temp copy then activate if(section == NULL) { cl_log(LOG_ERR, "No section specified in %s", XML_ATTR_FILTER_TYPE); *result = CIBRES_FAILED_NOSECTION; } else if(strcmp("all", section) == 0 && cib_update_op == CIB_OP_DELETE) { // delete /* order is no longer important here */ updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_STATUS); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_CONSTRAINTS); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_RESOURCES); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_NODES); } else if(strcmp("all", section) == 0) { /* order is no longer important here */ updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_NODES); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_RESOURCES); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_CONSTRAINTS); updateList(tmpCib, fragment, failed, cib_update_op, XML_CIB_TAG_STATUS); } else { *result = updateList(tmpCib, fragment, failed, cib_update_op, section); } - CRM_DEBUG("Activating temporary CIB"); + CRM_NOTE("Activating temporary CIB"); /* if(check_generation(cib_updates, tmpCib) == FALSE) */ /* status = "discarded old update"; */ /* else */ if (activateCibXml(tmpCib, CIB_FILENAME) < 0) { *result = CIBRES_FAILED_ACTIVATION; } else if (failed->children != NULL) { *result = CIBRES_FAILED; } CRM_DEBUG("CIB update status: %d", *result); } output_section = section; if (failed->children != NULL || *result != CIBRES_OK) { cib_answer = createCibFragmentAnswer(NULL /*"all"*/, failed); } else if (verbose != NULL && strcmp(XML_BOOLEAN_TRUE, verbose) == 0) { cib_answer = createCibFragmentAnswer(output_section, failed); } free_xml(failed); #ifdef MSG_LOG fprintf(msg_cib_strm, "[Reply (%s)]\t%s\n", op, dump_xml_node(cib_answer, FALSE)); fflush(msg_cib_strm); #endif FNRET(cib_answer); } gboolean replace_section(const char *section, xmlNodePtr tmpCib, xmlNodePtr fragment) { xmlNodePtr parent = NULL, cib_updates = NULL, new_section = NULL, old_section = NULL; FNIN(); cib_updates = find_xml_node(fragment, XML_TAG_CIB); /* find the old and new versions of the section */ new_section = get_object_root(section, cib_updates); old_section = get_object_root(section, tmpCib); if(old_section == NULL) { cl_log(LOG_ERR, "The CIB is corrupt, cannot replace missing section %s", section); FNRET(FALSE); } else if(new_section == NULL) { cl_log(LOG_ERR, "The CIB is corrupt, cannot set section %s to nothing", section); FNRET(FALSE); } parent = old_section->parent; /* unlink and free the old one */ unlink_xml_node(old_section); free_xml(old_section); /* add the new copy */ add_node_copy(parent, new_section); FNRET(TRUE); } enum cib_result updateList(xmlNodePtr local_cib, xmlNodePtr update_fragment, xmlNodePtr failed, int operation, const char *section) { xmlNodePtr child = NULL; xmlNodePtr this_section = get_object_root(section, local_cib); xmlNodePtr cib_updates = find_xml_node(update_fragment, XML_TAG_CIB); xmlNodePtr xml_section = get_object_root(section, cib_updates); if (section == NULL || xml_section == NULL) { cl_log(LOG_ERR, "Section %s not found in message." " CIB update is corrupt, ignoring.", section); return CIBRES_FAILED_NOSECTION; } if(CIB_OP_NONE > operation > CIB_OP_MAX) { cl_log(LOG_ERR, "Invalid operation on section %s", section); return CIBRES_FAILED; } set_node_tstamp(this_section); child = xml_section->children; while(child != NULL) { if(operation == CIB_OP_DELETE) { update_results(failed, child, operation, delete_cib_object(this_section, child)); } else if(operation == CIB_OP_MODIFY) { update_results(failed, child, operation, update_cib_object(this_section, child, FALSE)); } else { update_results(failed, child, operation, add_cib_object(this_section, child)); } child = child->next; } if (failed->children != NULL) return CIBRES_FAILED; else return CIBRES_OK; } xmlNodePtr createCibFragmentAnswer(const char *section, xmlNodePtr failed) { xmlNodePtr fragment = create_xml_node(NULL, XML_TAG_FRAGMENT); FNIN(); set_xml_property_copy(fragment, XML_ATTR_SECTION, section); if (section == NULL || strlen(section) == 0 || strcmp("all", section) == 0) { add_node_copy(fragment, get_the_CIB()); } else { xmlNodePtr cib = create_xml_node(fragment, XML_TAG_CIB); add_node_copy(cib, get_object_root(section, get_the_CIB())); copy_in_properties(cib, get_the_CIB()); } if (failed != NULL && failed->children != NULL) { add_node_copy(fragment, failed); } FNRET(fragment); } gboolean check_generation(xmlNodePtr newCib, xmlNodePtr oldCib) { char *new_value = xmlGetProp(newCib, XML_ATTR_GENERATION); char *old_value = xmlGetProp(oldCib, XML_ATTR_GENERATION); int int_new_value = -1; int int_old_value = -1; if(old_value != NULL) int_old_value = atoi(old_value); if(new_value != NULL) int_new_value = atoi(new_value); if(int_new_value >= int_old_value) { return TRUE; } else { cl_log(LOG_ERR, "Generation from update (%d) is older than %d", int_new_value, int_old_value); } return FALSE; } gboolean update_results(xmlNodePtr failed, xmlNodePtr target, int operation, int return_code) { gboolean was_error = FALSE; const char *error_msg = NULL; const char *operation_msg = NULL; xmlNodePtr xml_node; FNIN(); if (return_code != CIBRES_OK) { error_msg = cib_error2string(return_code); operation_msg = cib_op2string(operation); xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB); was_error = TRUE; set_xml_property_copy(xml_node, XML_FAILCIB_ATTR_ID, ID(target)); set_xml_property_copy(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target)); set_xml_property_copy(xml_node, XML_FAILCIB_ATTR_OP, operation_msg); set_xml_property_copy(xml_node, XML_FAILCIB_ATTR_REASON, error_msg); cl_log(LOG_DEBUG, "Action %s failed: %s (cde=%d)", operation_msg, error_msg, return_code); } FNRET(was_error); } diff --git a/crm/common/ipcutils.c b/crm/common/ipcutils.c index 4c0b6803ed..9579f4658f 100644 --- a/crm/common/ipcutils.c +++ b/crm/common/ipcutils.c @@ -1,553 +1,553 @@ -/* $Id: ipcutils.c,v 1.29 2004/06/01 12:25:15 andrew Exp $ */ +/* $Id: ipcutils.c,v 1.30 2004/06/01 16:12:49 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) { int log_level = LOG_DEBUG; 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); crm_free(xml_message); if(res == FALSE) { log_level = LOG_ERR; } cl_log(log_level, "Sending IPC message (ref=%s) to %s@%s %s.", xmlGetProp(msg, XML_ATTR_REFERENCE), xmlGetProp(msg, XML_ATTR_SYSTO), xmlGetProp(msg, XML_ATTR_HOSTTO), res?"succeeded":"failed"); FNRET(res); } gboolean send_xmlha_message(ll_cluster_t *hb_fd, xmlNodePtr root) { int xml_len = -1; int send_result = -1; char *xml_text = NULL; const char *host_to = NULL; const char *sys_to = NULL; struct ha_msg *msg = NULL; gboolean all_is_good = TRUE; gboolean broadcast = FALSE; int log_level = LOG_DEBUG; xmlNodePtr opts = find_xml_node(root, XML_TAG_OPTIONS); const char *op = xmlGetProp(opts, XML_ATTR_OP); #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 (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) { broadcast = TRUE; send_result = hb_fd->llc_ops->sendclustermsg(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 == FALSE) { log_level = LOG_ERR; } if(log_level == LOG_ERR || (safe_str_neq(op, CRM_OP_HBEAT))) { cl_log(log_level, "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"); } #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); crm_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) { int lpc = 0; gboolean all_is_good = TRUE; 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."); all_is_good = FALSE; } 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 *)crm_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, CRM_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..."); + CRM_NOTE("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*)crm_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); 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/xmlutils.c b/crm/common/xmlutils.c index a52411961b..60aa3ad41f 100644 --- a/crm/common/xmlutils.c +++ b/crm/common/xmlutils.c @@ -1,838 +1,836 @@ -/* $Id: xmlutils.c,v 1.30 2004/06/01 12:25:15 andrew Exp $ */ +/* $Id: xmlutils.c,v 1.31 2004/06/01 16:12:49 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 void dump_array(int log_level, const char *message, const char **array, int depth); xmlNodePtr find_xml_node_nested(xmlNodePtr root, const char **search_path, int len) { int j; xmlNodePtr child; xmlNodePtr lastMatch; FNIN(); if (root == NULL) { FNRET(NULL); } if(search_path == NULL) { - CRM_DEBUG("Will never find NULL :)"); + CRM_NOTE("Will never find NULL"); FNRET(NULL); } #ifdef XML_TRACE dump_array(LOG_DEBUG, "Looking for.", search_path, len); #endif child = root->children, lastMatch = NULL; for (j=0; j < len; ++j) { gboolean is_found = FALSE; if (search_path[j] == NULL) { len = j; /* a NULL also means stop searching */ break; } while(child != NULL) { const char * child_name = (const char*)child->name; #ifdef XML_TRACE CRM_DEBUG("comparing (%s) with (%s).", search_path[j], child->name); #endif if (strcmp(child_name, search_path[j]) == 0) { lastMatch = child; child = lastMatch->children; #ifdef XML_TRACE CRM_DEBUG("found node (%s) @line (%ld).", search_path[j], xmlGetLineNo(child)); #endif is_found = TRUE; break; } child = child->next; } if (is_found == FALSE) { #ifdef XML_TRACE CRM_DEBUG( "No more siblings left... %s cannot be found.", search_path[j]); #endif break; } } if (j == len && lastMatch != NULL && strcmp(lastMatch->name, search_path[j-1]) == 0) { #ifdef XML_TRACE CRM_DEBUG("returning node (%s).", xmlGetNodePath(lastMatch)); #endif FNRET(lastMatch); } dump_array(LOG_WARNING, "Could not find the full path to the node you specified.", search_path, len); cl_log(LOG_WARNING,"Closest point was node (%s) starting from %s.", xmlGetNodePath(lastMatch), root?root->name:NULL); FNRET(NULL); } const char * get_xml_attr(xmlNodePtr parent, const char *node_name, const char *attr_name, gboolean error) { if(node_name == NULL) { // get it from the current node return get_xml_attr_nested(parent, NULL, 0, attr_name, error); } return get_xml_attr_nested(parent, &node_name, 1, attr_name, error); } const char * get_xml_attr_nested(xmlNodePtr parent, const char **node_path, int length, const char *attr_name, gboolean error) { const char *attr_value = NULL; xmlNodePtr attr_parent = NULL; if(parent == NULL) { cl_log(LOG_ERR, "Can not find attribute %s in NULL parent", attr_name); return NULL; } if(attr_name == NULL || strlen(attr_name) == 0) { cl_log(LOG_ERR, "Can not find attribute with no name in %s", xmlGetNodePath(parent)); return NULL; } if(length == 0) { attr_parent = parent; } else { attr_parent = find_xml_node_nested(parent, node_path, length); if(attr_parent == NULL && error) { cl_log(LOG_ERR, "No node at the path you specified."); return NULL; } } attr_value = xmlGetProp(attr_parent, attr_name); if((attr_value == NULL || strlen(attr_value) == 0) && error) { cl_log(LOG_ERR, "No value present for %s at %s", attr_name, xmlGetNodePath(attr_parent)); return NULL; } return attr_value; } xmlNodePtr set_xml_attr(xmlNodePtr parent, const char *node_name, const char *attr_name, const char *attr_value, gboolean create) { if(node_name == NULL) { // set it on the current node return set_xml_attr_nested(parent, NULL, 0, attr_name, attr_value, create); } return set_xml_attr_nested(parent, &node_name, 1, attr_name, attr_value, create); } xmlNodePtr set_xml_attr_nested(xmlNodePtr parent, const char **node_path, int length, const char *attr_name, const char *attr_value, gboolean create) { xmlAttrPtr result = NULL; xmlNodePtr attr_parent = NULL; xmlNodePtr create_parent = NULL; xmlNodePtr tmp; if(parent == NULL && create == FALSE) { cl_log(LOG_ERR, "Can not set attribute in NULL parent"); return NULL; } if(attr_name == NULL || strlen(attr_name) == 0) { cl_log(LOG_ERR, "Can not set attribute to %s with no name", attr_value); return NULL; } if(length == 0 && parent != NULL) { attr_parent = parent; } else if(length == 0 || node_path == NULL || *node_path == NULL || strlen(*node_path) == 0) { cl_log(LOG_ERR, "Can not create parent to set attribute %s=%s on", attr_name, attr_value); return NULL; } else { attr_parent = find_xml_node_nested(parent, node_path, length); } if(create && attr_parent == NULL) { int j = 0; attr_parent = parent; for (j=0; j < length; ++j) { if (node_path[j] == NULL) { break; } tmp = find_xml_node(attr_parent, node_path[j]); if(tmp == NULL) { attr_parent = create_xml_node(attr_parent, node_path[j]); if(j==0) { create_parent = attr_parent; } } else { attr_parent = tmp; } } } else if(attr_parent == NULL) { cl_log(LOG_ERR, "Can not find parent to set attribute on"); return NULL; } result = set_xml_property_copy(attr_parent, attr_name, attr_value); if(result == NULL) { cl_log(LOG_WARNING, "Could not set %s=%s at %s", attr_name, attr_value, xmlGetNodePath(attr_parent)); } if(create_parent != NULL) { return create_parent; } return parent; } xmlNodePtr find_xml_node(xmlNodePtr root, const char * search_path) { if(root == NULL) return NULL; return find_xml_node_nested(root, &search_path, 1); } xmlNodePtr find_entity(xmlNodePtr parent, const char *node_name, const char *id, gboolean siblings) { return find_entity_nested(parent, node_name, NULL, NULL, id, siblings); } xmlNodePtr find_entity_nested(xmlNodePtr parent, const char *node_name, const char *elem_filter_name, const char *elem_filter_value, const char *id, gboolean siblings) { xmlNodePtr child; FNIN(); #ifdef XML_TRACE cl_log(LOG_DEBUG, "Looking for %s elem with id=%s.", node_name, id); #endif while(parent != NULL) { #ifdef XML_TRACE CRM_DEBUG("examining (%s).", xmlGetNodePath(parent)); #endif child = parent->children; while(child != NULL) { #ifdef XML_TRACE CRM_DEBUG("looking for (%s) [name].", node_name); #endif if (node_name != NULL && strcmp(child->name, node_name) != 0) { #ifdef XML_TRACE CRM_DEBUG( "skipping entity (%s=%s) [node_name].", xmlGetNodePath(child), child->name); #endif break; } else if (elem_filter_name != NULL && elem_filter_value != NULL) { const char* child_value = (const char*) xmlGetProp(child, elem_filter_name); #ifdef XML_TRACE cl_log(LOG_DEBUG, "comparing (%s) with (%s) [attr_value].", child_value, elem_filter_value); #endif if (strcmp(child_value, elem_filter_value)) { #ifdef XML_TRACE CRM_DEBUG("skipping entity (%s) [attr_value].", xmlGetNodePath(child)); #endif break; } } #ifdef XML_TRACE cl_log(LOG_DEBUG, "looking for entity (%s) in %s.", id, xmlGetNodePath(child)); #endif while(child != NULL) { #ifdef XML_TRACE cl_log(LOG_DEBUG, "looking for entity (%s) in %s.", id, xmlGetNodePath(child)); #endif xmlChar *child_id = xmlGetProp(child, XML_ATTR_ID); if (child_id == NULL) { cl_log(LOG_CRIT, "Entity (%s) has id=NULL..." "Cib not valid!", xmlGetNodePath(child)); } else if (strcmp(id, child_id) == 0) { #ifdef XML_TRACE CRM_DEBUG("found entity (%s).", id); #endif FNRET(child); } child = child->next; } } if (siblings == TRUE) { #ifdef XML_TRACE - CRM_DEBUG("Nothing yet... checking siblings"); + CRM_NOTE("Nothing yet... checking siblings"); #endif parent = parent->next; } else parent = NULL; } cl_log(LOG_INFO, "Couldnt find anything appropriate for %s elem with id=%s.", node_name, id); FNRET(NULL); } void copy_in_properties(xmlNodePtr target, xmlNodePtr src) { if(src == NULL) { cl_log(LOG_WARNING, "No node to copy properties from"); } else if (src->properties == NULL) { cl_log(LOG_INFO, "No properties to copy"); } else if (target == NULL) { cl_log(LOG_WARNING, "No node to copy properties into"); } else { #ifndef USE_BUGGY_LIBXML xmlAttrPtr prop_iter = NULL; FNIN(); prop_iter = src->properties; while(prop_iter != NULL) { const char *local_prop_name = prop_iter->name; const char *local_prop_value = xmlGetProp(src, local_prop_name); set_xml_property_copy(target, local_prop_name, local_prop_value); prop_iter = prop_iter->next; } #else xmlCopyPropList(target, src->properties); #endif } FNOUT(); } char * dump_xml(xmlNodePtr msg) { FNIN(); FNRET(dump_xml_node(msg, FALSE)); } void xml_message_debug(xmlNodePtr msg, const char *text) { char *msg_buffer; FNIN(); if(msg == NULL) { CRM_DEBUG("%s: %s", text==NULL?"":text,""); FNOUT(); } msg_buffer = dump_xml_node(msg, FALSE); CRM_DEBUG("%s: %s", text==NULL?"":text, msg_buffer==NULL?"":msg_buffer); crm_free(msg_buffer); FNOUT(); } char * dump_xml_node(xmlNodePtr msg, gboolean whole_doc) { int lpc = 0; int msg_size = -1; xmlChar *xml_message = NULL; xmlBufferPtr xml_buffer; FNIN(); if (msg == NULL) FNRET(NULL); xmlInitParser(); if (whole_doc) { if (msg->doc == NULL) { xmlDocPtr foo = xmlNewDoc("1.0"); xmlDocSetRootElement(foo, msg); xmlSetTreeDoc(msg,foo); } xmlDocDumpMemory(msg->doc, &xml_message, &msg_size); } else { #ifdef XML_TRACE CRM_DEBUG("mem used by xml: %d", xmlMemUsed()); xmlMemoryDump (); #endif xml_buffer = xmlBufferCreate(); msg_size = xmlNodeDump(xml_buffer, msg->doc, msg, 0, 0); xml_message = (xmlChar*)crm_strdup(xmlBufferContent(xml_buffer)); xmlBufferFree(xml_buffer); if (!xml_message) { cl_log(LOG_ERR, "memory allocation failed in dump_xml_node()"); } } xmlCleanupParser(); // HA wont send messages with newlines in them. for(; xml_message != NULL && lpc < msg_size; lpc++) if (xml_message[lpc] == '\n') xml_message[lpc] = ' '; FNRET((char*)xml_message); } xmlNodePtr add_node_copy(xmlNodePtr new_parent, xmlNodePtr xml_node) { xmlNodePtr node_copy = NULL; FNIN(); if(xml_node != NULL && new_parent != NULL) { node_copy = copy_xml_node_recursive(xml_node); xmlAddChild(new_parent, node_copy); } else if(xml_node == NULL) { cl_log(LOG_ERR, "Could not add copy of NULL node"); } else { cl_log(LOG_ERR, "Could not add copy of node to NULL parent"); } FNRET(node_copy); } xmlAttrPtr set_xml_property_copy(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { const char *parent_name = NULL; const char *local_name = NULL; const char *local_value = NULL; xmlAttrPtr ret_value = NULL; FNIN(); if(node != NULL) { parent_name = node->name; } #ifdef XML_TRACE CRM_DEBUG("[%s] Setting %s to %s", parent_name, name, value); #endif if (name == NULL || strlen(name) <= 0) { ret_value = NULL; } else if(node == NULL) { ret_value = NULL; } else if (value == NULL || strlen(value) <= 0) { ret_value = NULL; xmlUnsetProp(node, local_name); } else { local_value = crm_strdup(value); local_name = crm_strdup(name); ret_value = xmlSetProp(node, local_name, local_value); } FNRET(ret_value); } xmlNodePtr create_xml_node(xmlNodePtr parent, const char *name) { const char *local_name = NULL; const char *parent_name = NULL; xmlNodePtr ret_value = NULL; FNIN(); if (name == NULL || strlen(name) < 1) { ret_value = NULL; } else { local_name = crm_strdup(name); if(parent == NULL) ret_value = xmlNewNode(NULL, local_name); else { parent_name = parent->name; ret_value = xmlNewChild(parent, NULL, local_name, NULL); } } #ifdef XML_TRACE CRM_DEBUG("Created node [%s [%s]]", parent_name, local_name); #endif FNRET(ret_value); } void unlink_xml_node(xmlNodePtr node) { xmlUnlinkNode(node); /* this helps us with frees and really should be being done by * the library call */ node->doc = NULL; } void free_xml(xmlNodePtr a_node) { FNIN(); if (a_node == NULL) ; // nothing to do else if (a_node->doc != NULL) xmlFreeDoc(a_node->doc); else { /* make sure the node is unlinked first */ xmlUnlinkNode(a_node); #if 0 /* set a new doc, wont delete without one? */ xmlDocPtr foo = xmlNewDoc("1.0"); xmlDocSetRootElement(foo, a_node); xmlSetTreeDoc(a_node,foo); xmlFreeDoc(foo); #else xmlFreeNode(a_node); #endif } FNOUT(); } void set_node_tstamp(xmlNodePtr a_node) { char *since_epoch = (char*)crm_malloc(128*(sizeof(char))); FNIN(); sprintf(since_epoch, "%ld", (unsigned long)time(NULL)); set_xml_property_copy(a_node, XML_ATTR_TSTAMP, since_epoch); crm_free(since_epoch); } xmlNodePtr copy_xml_node_recursive(xmlNodePtr src_node) { #if XML_TRACE const char *local_name = NULL; xmlNodePtr local_node = NULL, node_iter = NULL, local_child = NULL; xmlAttrPtr prop_iter = NULL; FNIN(); if(src_node != NULL && src_node->name != NULL) { local_node = create_xml_node(NULL, src_node->name); prop_iter = src_node->properties; while(prop_iter != NULL) { const char *local_prop_name = prop_iter->name; const char *local_prop_value = xmlGetProp(src_node, local_prop_name); set_xml_property_copy(local_node, local_prop_name, local_prop_value); prop_iter = prop_iter->next; } node_iter = src_node->children; while(node_iter != NULL) { local_child = copy_xml_node_recursive(node_iter); if(local_child != NULL) { xmlAddChild(local_node, local_child); CRM_DEBUG("Copied node [%s [%s]", local_name, local_child->name); } node_iter = node_iter->next; } CRM_DEBUG("Returning [%s]", local_node->name); FNRET(local_node); } - CRM_DEBUG("Returning null"); + CRM_NOTE("Returning null"); FNRET(NULL); #else return xmlCopyNode(src_node, 1); #endif } xmlNodePtr string2xml(const char *input) { char ch = 0; int lpc = 0, input_len = strlen(input); gboolean more = TRUE; gboolean inTag = FALSE; xmlNodePtr xml_object = NULL; const char *the_xml; xmlDocPtr doc; xmlBufferPtr xml_buffer = xmlBufferCreate(); for(lpc = 0; (lpc < input_len) && more; lpc++) { ch = input[lpc]; switch(ch) { case EOF: case 0: ch = 0; more = FALSE; xmlBufferAdd(xml_buffer, &ch, 1); break; case '>': case '<': inTag = TRUE; if(ch == '>') inTag = FALSE; xmlBufferAdd(xml_buffer, &ch, 1); break; case '\n': case '\t': case ' ': ch = ' '; if(inTag) { xmlBufferAdd(xml_buffer, &ch, 1); } break; default: xmlBufferAdd(xml_buffer, &ch, 1); break; } } xmlInitParser(); the_xml = xmlBufferContent(xml_buffer); doc = xmlParseMemory(the_xml, strlen(the_xml)); xmlCleanupParser(); if (doc == NULL) { cl_log(LOG_ERR, "Malformed XML [xml=%s]", the_xml); xmlBufferFree(xml_buffer); return NULL; } xmlBufferFree(xml_buffer); xml_object = xmlDocGetRootElement(doc); - xml_message_debug(xml_object, "Created fragment"); - return xml_object; } xmlNodePtr file2xml(FILE *input) { char ch = 0; gboolean more = TRUE; gboolean inTag = FALSE; xmlNodePtr xml_object = NULL; xmlBufferPtr xml_buffer = xmlBufferCreate(); const char *the_xml; xmlDocPtr doc; if(input == NULL) { cl_log(LOG_ERR, "File pointer was NULL"); return NULL; } while (more) { ch = fgetc(input); // cl_log(LOG_DEBUG, "Got [%c]", ch); switch(ch) { case EOF: case 0: ch = 0; more = FALSE; xmlBufferAdd(xml_buffer, &ch, 1); break; case '>': case '<': inTag = TRUE; if(ch == '>') inTag = FALSE; xmlBufferAdd(xml_buffer, &ch, 1); break; case '\n': case '\t': case ' ': ch = ' '; if(inTag) { xmlBufferAdd(xml_buffer, &ch, 1); } break; default: xmlBufferAdd(xml_buffer, &ch, 1); break; } } xmlInitParser(); the_xml = xmlBufferContent(xml_buffer); doc = xmlParseMemory(the_xml, strlen(the_xml)); xmlCleanupParser(); if (doc == NULL) { cl_log(LOG_ERR, "Malformed XML [xml=%s]", the_xml); xmlBufferFree(xml_buffer); return NULL; } xmlBufferFree(xml_buffer); xml_object = xmlDocGetRootElement(doc); xml_message_debug(xml_object, "Created fragment"); return xml_object; } void dump_array(int log_level, const char *message, const char **array, int depth) { int j; if(message != NULL) { cl_log(log_level, "%s", message); } cl_log(log_level, "Contents of the array:"); if(array == NULL || array[0] == NULL || depth == 0) { cl_log(log_level, "\t"); } for (j=0; j < depth && array[j] != NULL; j++) { if (array[j] == NULL) break; cl_log(log_level, "\t--> (%s).", array[j]); } } diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c index ae2453aaf2..fa84d4f149 100644 --- a/crm/crmd/ccm.c +++ b/crm/crmd/ccm.c @@ -1,580 +1,577 @@ /* * 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); gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data); void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data); #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; 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!"); //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; GHashTable *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 *) crm_malloc(sizeof(oc_node_list_t)); FNIN(); 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; if(membership_copy->members_size > 0) { membership_copy->members = g_hash_table_new(g_str_hash, g_str_equal); members = membership_copy->members; for(lpc=0; lpc < membership_copy->members_size; lpc++) { oc_node_t *member = (oc_node_t *) crm_malloc(sizeof(oc_node_t)); member->node_id = oc->m_array[offset+lpc].node_id; member->node_born_on = oc->m_array[offset+lpc].node_born_on; member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); g_hash_table_insert(members, member->node_uname, member); } } else { membership_copy->members = NULL; } /*--*-- New Member Nodes --*--*/ offset = oc->m_in_idx; membership_copy->new_members_size = oc->m_n_in; if(membership_copy->new_members_size > 0) { membership_copy->new_members = g_hash_table_new(g_str_hash, g_str_equal); members = membership_copy->new_members; for(lpc=0; lpc < membership_copy->new_members_size; lpc++) { oc_node_t *member = (oc_node_t *) crm_malloc(sizeof(oc_node_t)); member->node_id = oc->m_array[offset+lpc].node_id; member->node_born_on = oc->m_array[offset+lpc].node_born_on; member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); g_hash_table_insert(members, member->node_uname, member); } } 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) { membership_copy->dead_members = g_hash_table_new(g_str_hash, g_str_equal); members = membership_copy->dead_members; for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) { oc_node_t *member = (oc_node_t *) crm_malloc(sizeof(oc_node_t)); member->node_id = oc->m_array[offset+lpc].node_id; member->node_born_on = oc->m_array[offset+lpc].node_born_on; member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); g_hash_table_insert(members, member->node_uname, member); } } else { membership_copy->dead_members = NULL; } tmp = fsa_membership_copy; fsa_membership_copy = membership_copy; if(AM_I_DC) { // should be sufficient for only the DC to do this free_xml(do_update_cib_nodes(NULL, FALSE)); } /* Free the old copy */ if(tmp != NULL) { if(tmp->members != NULL) g_hash_table_foreach_remove( tmp->members, ghash_node_clfree, NULL); if(tmp->new_members != NULL) g_hash_table_foreach_remove( tmp->new_members, ghash_node_clfree, NULL); if(tmp->dead_members != NULL) g_hash_table_foreach_remove( tmp->dead_members, ghash_node_clfree, NULL); crm_free(tmp); } FNRET(next_input); } 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); CRM_DEBUG("%s ? %s", fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname); if(safe_str_eq(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 *) crm_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; crm_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(); } struct update_data_s { xmlNodePtr updates; const char *state; const char *join; }; xmlNodePtr do_update_cib_nodes(xmlNodePtr updates, gboolean overwrite) { struct update_data_s update_data; update_data.updates = updates; - CRM_DEBUG("Processing the \"down\" list"); update_data.state = XML_BOOLEAN_NO; update_data.join = CRMD_JOINSTATE_DOWN; if(fsa_membership_copy->dead_members != NULL) { g_hash_table_foreach(fsa_membership_copy->dead_members, ghash_update_cib_node, &update_data); } - CRM_DEBUG("Processing the \"in_ccm (all)\" list"); update_data.state = XML_BOOLEAN_YES; update_data.join = NULL; if(overwrite) { update_data.join = CRMD_JOINSTATE_PENDING; } if(fsa_membership_copy->members != NULL) { g_hash_table_foreach(fsa_membership_copy->members, ghash_update_cib_node, &update_data); } /* this is most likely overkill... * * make *sure* that the join status of nodes entering the ccm list * is reset * update_data.join = CRMD_JOINSTATE_PENDING; - CRM_DEBUG("Processing the \"in_ccm (new)\" list"); if(fsa_membership_copy->new_members != NULL) { g_hash_table_foreach(fsa_membership_copy->new_members, ghash_update_cib_node, &update_data); } */ if(update_data.updates != NULL) { xmlNodePtr fragment = create_cib_fragment(update_data.updates, NULL); store_request(NULL, fragment, CRM_OP_UPDATE, CRM_SYSTEM_DCIB); free_xml(fragment); } return update_data.updates; } void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data) { xmlNodePtr tmp1 = NULL; const char *node_uname = (const char*)key; struct update_data_s* data = (struct update_data_s*)user_data; const char *state = data->join; crm_debug("%s processing %s (%s)", __FUNCTION__, node_uname, data->state); if(state != NULL && safe_str_eq(fsa_our_uname, node_uname)) { /* the DC is always a member */ state = CRMD_JOINSTATE_MEMBER; } tmp1 = create_node_state(node_uname, data->state, NULL, state); if(data->updates == NULL) { crm_debug("Creating first update"); data->updates = tmp1; } else { xmlAddNextSibling(data->updates, tmp1); } } gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data) { // value->node_uname is free'd as "key" if(key != NULL) { crm_free(key); } if(value != NULL) { crm_free(value); } return TRUE; } diff --git a/crm/crmd/control.c b/crm/crmd/control.c index 73c3021070..bec444e709 100644 --- a/crm/crmd/control.c +++ b/crm/crmd/control.c @@ -1,416 +1,415 @@ /* * 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_OP_SHUTDOWN_REQ, NULL, CRM_SYSTEM_DC, NULL) == 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"); + cl_log(LOG_INFO, "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, "FSA Hostname: %s", fsa_our_uname); } /* set up the timers */ dc_heartbeat = (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t)); integration_timer= (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t)); election_trigger = (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t)); election_timeout = (fsa_timer_t *)crm_malloc(sizeof(fsa_timer_t)); shutdown_escalation_timmer = (fsa_timer_t *) crm_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*130; shutdown_escalation_timmer->fsa_input = I_TERMINATE; shutdown_escalation_timmer->callback = timer_popped; /* set up the sub systems */ cib_subsystem = (struct crm_subsystem_s*) crm_malloc(sizeof(struct crm_subsystem_s)); cib_subsystem->pid = 0; cib_subsystem->respawn = 1; cib_subsystem->path = crm_strdup(BIN_DIR); cib_subsystem->name = crm_strdup(CRM_SYSTEM_CIB); cib_subsystem->command = BIN_DIR"/cib"; cib_subsystem->flag = R_CIB_CONNECTED; te_subsystem = (struct crm_subsystem_s*) crm_malloc(sizeof(struct crm_subsystem_s)); te_subsystem->pid = 0; te_subsystem->respawn = 1; te_subsystem->path = crm_strdup(BIN_DIR); te_subsystem->name = crm_strdup(CRM_SYSTEM_TENGINE); te_subsystem->command = BIN_DIR"/tengine"; te_subsystem->flag = R_TE_CONNECTED; pe_subsystem = (struct crm_subsystem_s*) crm_malloc(sizeof(struct crm_subsystem_s)); pe_subsystem->pid = 0; pe_subsystem->respawn = 1; pe_subsystem->path = crm_strdup(BIN_DIR); pe_subsystem->name = crm_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"); + cl_log(LOG_WARNING, "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"); + cl_log(LOG_INFO, "exit from shutdown"); exit(LSB_EXIT_OK); } FNOUT(); } diff --git a/crm/crmd/crmdmain.c b/crm/crmd/crmdmain.c index e3238f2119..adddd34bb6 100644 --- a/crm/crmd/crmdmain.c +++ b/crm/crmd/crmdmain.c @@ -1,209 +1,209 @@ -/* $Id: crmdmain.c,v 1.16 2004/06/01 12:25:15 andrew Exp $ */ +/* $Id: crmdmain.c,v 1.17 2004/06/01 16:12:49 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 -const char* crm_system_name = "crmd"; +const char* crm_system_name = CRM_SYSTEM_CRMD; #include #include #include #include #include #define PID_FILE WORKING_DIR"/crm.pid" #define OPTARGS "skrh" void usage(const char* cmd, int exit_status); int init_start(void); void crmd_hamsg_callback(const struct ha_msg* msg, void* private_data); gboolean crmd_tickle_apphb(gpointer data); GMainLoop* crmd_mainloop = NULL; gboolean crm_debug_state = TRUE; 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); 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){ 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; enum crmd_fsa_state state; if ((pid = get_running_pid(PID_FILE, NULL)) > 0) { cl_log(LOG_CRIT, "already running: [pid %ld].", pid); exit(LSB_EXIT_OK); } fsa_state = S_PENDING; state = s_crmd_fsa(C_STARTUP, I_STARTUP, NULL); if (state == S_PENDING) { /* Create the mainloop and run it... */ crmd_mainloop = g_main_new(FALSE); cl_log(LOG_INFO, "Starting %s", crm_system_name); #ifdef REALTIME_SUPPORT static int crm_realtime = 1; 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(crmd_mainloop); return_to_orig_privs(); } else { cl_log(LOG_ERR, "Startup of CRMd failed. Current state: %s", fsa_state2string(state)); } if (unlink(PID_FILE) == 0) { cl_log(LOG_INFO, "[%s] stopped", crm_system_name); } FNRET(state != S_PENDING); } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } gboolean crmd_tickle_apphb(gpointer data) { char app_instance[APPNAME_LEN]; int rc = 0; sprintf(app_instance, "%s_%ld", crm_system_name, (long)getpid()); rc = apphb_hb(); if (rc < 0) { cl_perror("%s apphb_hb failure", app_instance); exit(3); } return TRUE; } diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c index 40ffb2f4e3..395e05994b 100644 --- a/crm/crmd/lrm.c +++ b/crm/crmd/lrm.c @@ -1,627 +1,624 @@ /* * 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 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); /* 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_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..."); + CRM_NOTE("LRM: connect..."); fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM); if(NULL == fsa_lrm_conn) { return failed; } - CRM_DEBUG("LRM: sigon..."); + CRM_NOTE("LRM: sigon..."); ret = fsa_lrm_conn->lrm_ops->signon(fsa_lrm_conn, - "crmd"); + CRM_SYSTEM_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); + CRM_NOTE("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, XML_CIB_TAG_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, XML_ATTR_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, XML_LRM_TAG_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, XML_ATTR_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); CRM_DEBUG("\tcurrent state:%s\n", cur_state==LRM_RSC_IDLE?"Idle":"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_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(); if(action & A_UPDATE_NODESTATUS) { xmlNodePtr data = NULL; #ifndef USE_FAKE_LRM data = do_lrm_query(); #endif set_xml_property_copy(data, "replace", XML_CIB_TAG_LRM); 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); add_node_copy(tmp1, data); /* this only happens locally. the updates are pushed out * as part of the join process */ store_request(NULL, fragment, CRM_OP_UPDATE, CRM_SYSTEM_DC); free_xml(fragment); free_xml(tmp1); free_xml(data); FNRET(next_input); } #ifdef USE_FAKE_LRM if(data == NULL) { FNRET(I_ERROR); } msg = (xmlNodePtr)data; operation = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -3, XML_LRM_ATTR_TASK, TRUE); id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_ID, TRUE); crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); if(safe_str_eq(crm_op, "rsc_op")) { const char *op_status = NULL; xmlNodePtr update = NULL; xmlNodePtr state = create_xml_node(NULL, XML_CIB_TAG_STATE); xmlNodePtr iter = create_xml_node(state, XML_CIB_TAG_LRM); CRM_DEBUG("performing op %s...", operation); // so we can identify where to do the update set_xml_property_copy(state, XML_ATTR_ID, fsa_our_uname); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); iter = create_xml_node(iter, "lrm_resource"); set_xml_property_copy(iter, XML_ATTR_ID, id_from_cib); set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, operation); long int op_code = 0; #if 0 /* introduce a 10% chance of an action failing */ op_code = random(); #endif if((op_code % 10) == 1) { op_code = 1; } else { op_code = 0; } char *op_code_s = crm_itoa(op_code); if(op_code) { // fail if(safe_str_eq(operation, "start")){ op_status = "stopped"; } else { op_status = "started"; } } else { // pass if(safe_str_eq(operation, "start")){ op_status = "started"; } else { op_status = "stopped"; } } set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATE,op_status); set_xml_property_copy(iter, XML_LRM_ATTR_OPCODE, op_code_s); set_xml_property_copy(iter, XML_LRM_ATTR_TARGET, fsa_our_uname); crm_free(op_code_s); update = create_cib_fragment(state, NULL); send_request(NULL, update, CRM_OP_UPDATE, fsa_our_dc, CRM_SYSTEM_DCIB, NULL); } FNRET(I_NULL); #endif 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, XML_ATTR_OP, TRUE); id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_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, 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..."); + CRM_DEBUG("adding rsc %s before operation", rid); 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, XML_ATTR_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, XML_NVPAIR_ATTR_NAME); const char *value = xmlGetProp( node_iter, XML_NVPAIR_ATTR_VALUE); CRM_DEBUG("Added %s=%s", key, value); g_hash_table_insert (nvpair_hash, crm_strdup(key), crm_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, XML_CIB_TAG_LRM); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); iter = create_xml_node(iter, "lrm_resource"); set_xml_property_copy(iter, XML_ATTR_ID, rsc->id); set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, op_type); tmp = crm_itoa(status); set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATE, tmp); crm_free(tmp); tmp = crm_itoa(rc); set_xml_property_copy(iter, XML_LRM_ATTR_OPCODE, tmp); crm_free(tmp); set_xml_property_copy(iter, XML_LRM_ATTR_TARGET, 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_OP_UPDATE, fsa_our_dc, CRM_SYSTEM_DCIB, NULL); 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"); + CRM_NOTE("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/crmd/messages.c b/crm/crmd/messages.c index 65bd4daf22..d52b7a8dce 100644 --- a/crm/crmd/messages.c +++ b/crm/crmd/messages.c @@ -1,938 +1,939 @@ /* * 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 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); \ crm_free(msg_text); #else -# define ROUTER_RESULT(x) CRM_DEBUG(x); +# define ROUTER_RESULT(x) CRM_DEBUG(x, NULL); #endif /* returns the current head of the FIFO queue */ fsa_message_queue_t put_message(xmlNodePtr new_message) { int old_len = g_slist_length(fsa_message_queue); // make sure to free it properly later fsa_message_queue = g_slist_append(fsa_message_queue, copy_xml_node_recursive(new_message)); CRM_DEBUG("Queue len: %d -> %d", old_len, g_slist_length(fsa_message_queue)); if(old_len == g_slist_length(fsa_message_queue)){ cl_log(LOG_ERR, "Couldnt add message to the queue"); } return fsa_message_queue; } /* returns the next message */ xmlNodePtr get_message(void) { xmlNodePtr message = g_slist_nth_data(fsa_message_queue, 0); fsa_message_queue = g_slist_remove(fsa_message_queue, message); return message; } /* returns the current head of the FIFO queue */ gboolean is_message(void) { return (g_slist_length(fsa_message_queue) > 0); } /* 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"); + CRM_NOTE("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)); #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"); + cl_log(LOG_WARNING, "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 { 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) { + cl_log(LOG_WARNING, + "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) { + } 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){ + } 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); + gboolean det = G_main_del_IPC_Channel( + curr_client->client_source); CRM_DEBUG("crm_client was %s detached", det?"successfully":"not"); } crm_free(curr_client->table_key); crm_free(curr_client->sub_sys); crm_free(curr_client->uuid); crm_free(curr_client); } - 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, char **msg_reference) { 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..."); if(msg_reference != NULL) { *msg_reference = crm_strdup(xmlGetProp(request, XML_ATTR_REFERENCE)); } 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 *sys_to) { xmlNodePtr request = NULL; FNIN(); msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS, XML_ATTR_OP, operation, TRUE); crm_debug("Storing op=%s message for later processing", operation); request = create_request(msg_options, msg_data, NULL, sys_to, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL, NULL); put_message(request); free_xml(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); FNIN(); if(xml_relay_message == NULL) { cl_log(LOG_ERR, "Cannot route empty message"); FNRET(TRUE); } if(strcmp(CRM_OP_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(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; const char *op = get_xml_attr(root_xml_node, XML_TAG_OPTIONS, - XML_ATTR_OP, FALSE); + XML_ATTR_OP, TRUE); FNIN(); if (safe_str_neq(CRM_OP_HELLO, op)) { - + if(sys_from == NULL) { return FALSE; } 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); if(can_reply == FALSE) { cl_log(LOG_ERR, "Message not authorized"); } return can_reply; } cl_log(LOG_INFO, "received client join msg: %s", (char*)client_msg->msg_body); result = process_hello_message(root_xml_node, &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; } crm_free(major_version); crm_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 */ if (client_name == NULL) - CRM_DEBUG("Client had not registered with us yet"); + cl_log(LOG_WARNING, + "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; if(result) { 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)", client_name, uuid); } } - if(result == TRUE && table_key == NULL) + if(result == TRUE && table_key == NULL) { table_key = (gpointer)crm_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 = crm_strdup(client_name); curr_client->uuid = crm_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) crm_free(uuid); if(client_name != NULL) crm_free(client_name); /* hello messages should never be processed further */ return 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 *host_from = get_xml_attr(stored_msg, NULL, + const char *host_from= get_xml_attr(stored_msg, NULL, XML_ATTR_HOSTFROM, TRUE); const char *msg_ref = get_xml_attr(stored_msg, NULL, XML_ATTR_REFERENCE, 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"); cl_log(LOG_DEBUG, "Received %s %s in state %s", op, type, fsa_state2string(fsa_state)); 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_OP_VOTE) == 0) { next_input = I_ELECTION; } else if(AM_I_DC && strcmp(op, CRM_OP_TEABORT) == 0) { next_input = I_PE_CALC; } else if(AM_I_DC && strcmp(op, CRM_OP_TECOMPLETE) == 0) { if(fsa_state == S_TRANSITION_ENGINE) { next_input = I_SUCCESS; /* silently ignore? probably means the TE is signaling OK too early } else { cl_log(LOG_WARNING, "Op %s is only valid in state %s (%s)", op, fsa_state2string(S_TRANSITION_ENGINE), fsa_state2string(fsa_state)); */ } } else if(strcmp(op, CRM_OP_HBEAT) == 0) { next_input = I_DC_HEARTBEAT; } else if(strcmp(op, CRM_OP_WELCOME) == 0) { next_input = I_WELCOME; } else if(strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { /* create cib fragment and add to message */ /* handle here to avoid potential version issues * where the shutdown message/proceedure may have * been changed in later versions. * * This way the DC is always in control of the shutdown */ xmlNodePtr frag = NULL; time_t now = time(NULL); char *now_s = crm_itoa((int)now); xmlNodePtr node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); cl_log(LOG_INFO, "Creating shutdown request for %s", host_from); set_xml_property_copy( node_state, XML_ATTR_ID, host_from); set_xml_property_copy( node_state, XML_CIB_ATTR_SHUTDOWN, now_s); set_xml_property_copy( node_state, XML_CIB_ATTR_EXPSTATE, CRMD_STATE_INACTIVE); frag = create_cib_fragment(node_state, NULL); xmlAddChild(stored_msg, frag); free_xml(node_state); crm_free(now_s); next_input = I_CIB_OP; } else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) { next_input = I_TERMINATE; } else if(strcmp(op, CRM_OP_ANNOUNCE) == 0) { next_input = I_NODE_JOIN; } else if(strcmp(op, CRM_OP_REPLACE) == 0 || strcmp(op, CRM_OP_ERASE) == 0) { next_input = I_CIB_OP; fprintf(router_strm, "Message result: CIB Op\n"); } else if(AM_I_DC && (strcmp(op, CRM_OP_CREATE) == 0 || strcmp(op, CRM_OP_UPDATE) == 0 || strcmp(op, CRM_OP_DELETE) == 0)) { /* updates should only be performed on the DC */ next_input = I_CIB_OP; } else if(strcmp(op, CRM_OP_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_OP_WELCOME) == 0) { next_input = I_WELCOME_ACK; } else if(AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) { if(fsa_state == S_POLICY_ENGINE && safe_str_eq(msg_ref, fsa_pe_ref)) { next_input = I_SUCCESS; } else if(fsa_state != S_POLICY_ENGINE) { cl_log(LOG_ERR, "Reply to %s is only valid in state %s", op, fsa_state2string(S_POLICY_ENGINE)); } else { CRM_DEBUG("Skipping superceeded reply from %s", sys_from); } } else if(strcmp(op, CRM_OP_VOTE) == 0 || strcmp(op, CRM_OP_HBEAT) == 0 || strcmp(op, CRM_OP_WELCOME) == 0 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0 || strcmp(op, CRM_OP_ANNOUNCE) == 0) { next_input = I_NULL; } else if(strcmp(op, CRM_OP_CREATE) == 0 || strcmp(op, CRM_OP_UPDATE) == 0 || strcmp(op, CRM_OP_DELETE) == 0 || strcmp(op, CRM_OP_REPLACE) == 0 || strcmp(op, CRM_OP_ERASE) == 0) { /* perhaps we should do somethign with these replies, * especially check that the actions passed */ /* 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 51f9a7c5d2..7705a5215e 100644 --- a/crm/crmd/subsystems.c +++ b/crm/crmd/subsystems.c @@ -1,644 +1,641 @@ /* * 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); struct crm_subsystem_s *cib_subsystem = NULL; struct crm_subsystem_s *te_subsystem = NULL; struct crm_subsystem_s *pe_subsystem = NULL; /* 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 new_options = NULL; const char *section = NULL; FNIN(); if(data != NULL) { cib_msg = (xmlNodePtr)data; } if(action & A_CIB_INVOKE) { const char *op = get_xml_attr(cib_msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); xml_message_debug(cib_msg, "[CIB] Invoking with"); if(cib_msg == NULL) { cl_log(LOG_ERR, "No message for CIB command"); FNRET(I_NULL); // I_ERROR } 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(op != NULL && AM_I_DC && (strcmp(op, CRM_OP_CREATE) == 0 || strcmp(op, CRM_OP_UPDATE) == 0 || strcmp(op, CRM_OP_DELETE) == 0 || strcmp(op, CRM_OP_REPLACE) == 0 || strcmp(op, CRM_OP_WELCOME) == 0 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_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) { xml_message_debug(cib_msg, "[CIB] Invoking with"); if(cib_msg == NULL) { cl_log(LOG_ERR, "No message for CIB command"); FNRET(I_NULL); // I_ERROR } 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); /* 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_OP_BUMP, 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_OP_REPLACE, NULL, CRM_SYSTEM_CRMD, NULL); 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); } char *fsa_pe_ref = NULL; /* 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); 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); if(fsa_pe_ref) { crm_free(fsa_pe_ref); fsa_pe_ref = NULL; } send_request(NULL, local_cib, CRM_OP_PECALC, NULL, CRM_SYSTEM_PENGINE, &fsa_pe_ref); 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); } static xmlNodePtr te_last_input = NULL; static xmlNodePtr te_lastcc = NULL; /* 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 = NULL; xmlNodePtr opts = NULL; const char *true_op = NULL; FNIN(); if(data != NULL) { message = copy_xml_node_recursive((xmlNodePtr)data); opts = find_xml_node(message, XML_TAG_OPTIONS); true_op = xmlGetProp(opts, XML_ATTR_OP); set_xml_property_copy(opts, XML_ATTR_OP, CRM_OP_EVENTCC); set_xml_property_copy(opts, XML_ATTR_TRUEOP, true_op); set_xml_property_copy(message, XML_ATTR_SYSTO, CRM_SYSTEM_TENGINE); } 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_lastcc); te_lastcc = message; } FNRET(I_WAIT_FOR_EVENT); } if(message == NULL) { message = te_lastcc; te_lastcc = NULL; } else { free_xml(te_lastcc); } relay_message(message, FALSE); // only free it if it was a local copy if(data == NULL) { free_xml(message); } FNRET(I_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(); 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; te_last_input = NULL; } 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, CRM_OP_TRANSITION, NULL, CRM_SYSTEM_TENGINE, NULL); } else { send_request(NULL, graph, CRM_OP_ABORT, NULL, CRM_SYSTEM_TENGINE, NULL); } // only free it if it was a local copy if(data == NULL) { free_xml(msg); } 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 *)crm_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, CRM_OP_QUIT, NULL, centry->name, NULL); } return TRUE; } static gboolean start_subsystem(struct crm_subsystem_s* centry) { pid_t pid; struct stat buf; int s_res; 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); } /* * 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 */ centry->pid = pid; 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); } cl_log(LOG_INFO, "Executing \"%s\" (pid %d)", centry->command, (int) getpid()); if(CL_SIGINTERRUPT(SIGALRM, 0) < 0) { cl_perror("Cannot set interrupt for child process %s", centry->command); }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", centry->command, (const char *)NULL); /* Should not happen */ cl_perror("Cannot exec %s", centry->command); } /* Suppress respawning */ exit(100); // never reached return TRUE; } diff --git a/crm/pengine/penginemain.c b/crm/pengine/penginemain.c index ae385862e9..b81042be35 100644 --- a/crm/pengine/penginemain.c +++ b/crm/pengine/penginemain.c @@ -1,238 +1,238 @@ -/* $Id: penginemain.c,v 1.13 2004/06/01 12:25:16 andrew Exp $ */ +/* $Id: penginemain.c,v 1.14 2004/06/01 16:12:50 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 CRM_SYSTEM_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 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", + crm_ch = init_client_ipc_comms(CRM_SYSTEM_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/tenginemain.c b/crm/tengine/tenginemain.c index 7d988e4ea2..61dd5ea2b4 100644 --- a/crm/tengine/tenginemain.c +++ b/crm/tengine/tenginemain.c @@ -1,237 +1,237 @@ -/* $Id: tenginemain.c,v 1.13 2004/05/06 12:11:59 andrew Exp $ */ +/* $Id: tenginemain.c,v 1.14 2004/06/01 16:12:50 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 #define OPTARGS "skrh" #define PID_FILE WORKING_DIR "/transitioner.pid" #define DAEMON_LOG "/var/log/transitioner.log" #define DAEMON_DEBUG "/var/log/transitioner.debug" GMainLoop* mainloop = NULL; const char* crm_system_name = "transitioner"; void usage(const char* cmd, int exit_status); int init_start(void); void tengine_shutdown(int nsig); 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; #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, tengine_shutdown); - crm_ch = init_client_ipc_comms("crmd", + crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, subsystem_input_dispatch, (void*)process_te_message); if(crm_ch != NULL) { send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "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 tengine_shutdown(int nsig) { static int shuttingdown = 0; CL_SIGNAL(nsig, tengine_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/ttest.c b/crm/tengine/ttest.c index c160666ff7..665a5c46ce 100644 --- a/crm/tengine/ttest.c +++ b/crm/tengine/ttest.c @@ -1,152 +1,152 @@ -/* $Id: ttest.c,v 1.2 2004/05/23 19:54:04 andrew Exp $ */ +/* $Id: ttest.c,v 1.3 2004/06/01 16:12:50 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 #define OPTARGS "V?i:o:D:C:S:HA:U:M:I:EWRFt:m:a:d:w:c:r:p:s:" #include #include #include extern gboolean unpack_graph(xmlNodePtr xml_graph); extern gboolean initiate_transition(void); extern gboolean initialize_graph(void); int main(int argc, char **argv) { int argerr = 0; int flag; cl_log_set_entity("ttest"); cl_log_enable_stderr(TRUE); cl_log_set_facility(LOG_USER); while (1) { int option_index = 0; static struct option long_options[] = { // Top-level Options {"daemon", 0, 0, 0}, {0, 0, 0, 0} }; 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"); 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': printf("option %d", flag); 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) { cl_log(LOG_ERR, "%d errors in option parsing", argerr); } cl_log(LOG_INFO, "=#=#=#=#= Getting XML =#=#=#=#="); mtrace(); - CRM_DEBUG("Initializing graph..."); + CRM_NOTE("Initializing graph..."); initialize_graph(); xmlNodePtr xml_graph = file2xml(stdin); - CRM_DEBUG("Unpacking graph..."); + CRM_NOTE("Unpacking graph..."); unpack_graph(xml_graph); - CRM_DEBUG("Initiating transition..."); + CRM_NOTE("Initiating transition..."); if(initiate_transition() == FALSE) { // nothing to be done.. means we're done. cl_log(LOG_INFO, "No actions to be taken..." " transition compelte."); } initialize_graph(); free_xml(xml_graph); muntrace(); - CRM_DEBUG("Transition complete..."); + CRM_NOTE("Transition complete..."); return 0; }