diff --git a/crm/cib/cibmessages.c b/crm/cib/cibmessages.c index 17d98532df..05ac3cb5c6 100644 --- a/crm/cib/cibmessages.c +++ b/crm/cib/cibmessages.c @@ -1,472 +1,466 @@ -/* $Id: cibmessages.c,v 1.40 2004/06/03 07:52:16 andrew Exp $ */ +/* $Id: cibmessages.c,v 1.41 2004/06/04 09:18:30 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 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; *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 crm_debug("[cib] Processing \"%s\" event", op); if(op == NULL) { *result = CIBRES_FAILED; crm_err("No operation specified\n"); } else if(strcmp("noop", op) == 0) { ; } else if(strcmp(CRM_OP_QUIT, op) == 0) { crm_warn( "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_verbose("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"); } crm_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_verbose("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_verbose("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; crm_err("Action [%s] is not supported by the CIB", op); } if (update_the_cib) { tmpCib = copy_xml_node_recursive(get_the_CIB()); section = xmlGetProp(fragment, XML_ATTR_SECTION); crm_verbose("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) { crm_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_trace("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_verbose("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 return cib_answer; } gboolean replace_section(const char *section, xmlNodePtr tmpCib, xmlNodePtr fragment) { xmlNodePtr parent = NULL, cib_updates = NULL, new_section = NULL, old_section = NULL; - 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) { crm_err("The CIB is corrupt, cannot replace missing section %s", section); return FALSE; } else if(new_section == NULL) { crm_err("The CIB is corrupt, cannot set section %s to nothing", section); return 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); return 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) { crm_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) { crm_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)); + 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)); + update_results( + failed, child, operation, + update_cib_object(this_section, child, FALSE)); } else { - update_results(failed, child, operation, - add_cib_object(this_section, child)); + 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); 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); } return 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 { crm_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; 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_ID, ID(target)); - set_xml_property_copy(xml_node, - XML_FAILCIB_ATTR_OBJTYPE, - TYPE(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_OP, operation_msg); - set_xml_property_copy(xml_node, - XML_FAILCIB_ATTR_REASON, - error_msg); - - crm_debug( - "Action %s failed: %s (cde=%d)", - operation_msg, - error_msg, - return_code); + set_xml_property_copy( + xml_node, XML_FAILCIB_ATTR_REASON, error_msg); + + crm_debug("Action %s failed: %s (cde=%d)", + operation_msg, error_msg, return_code); } return was_error; } diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c index e74dac7794..473ad79ad1 100644 --- a/crm/crmd/callbacks.c +++ b/crm/crmd/callbacks.c @@ -1,317 +1,327 @@ /* * 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 FILE *msg_in_strm = NULL; xmlNodePtr find_xml_in_hamessage(const struct ha_msg* msg); 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; #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 return; } #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 return; } 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); return; } /* * 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; crm_verbose("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:"); return !hack_return_good; } if (msg == NULL) { crm_err("No message this time"); continue; } lpc++; buffer = (char*)msg->msg_body; crm_verbose("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)) { s_crmd_fsa(C_IPC_MESSAGE, I_ROUTER, root_xml_node); } } else { crm_info("IPC Message was not valid... discarding."); } free_xml(root_xml_node); msg->msg_done(msg); msg = NULL; buffer = NULL; root_xml_node = NULL; } crm_verbose("Processed %d messages", lpc); if (client->ch_status == IPC_DISCONNECT) { crm_info("received HUP from %s", curr_client->table_key); if (curr_client != NULL) { struct crm_subsystem_s *the_subsystem = NULL; if (curr_client->sub_sys == NULL) { crm_warn("Client hadn't registered with us yet"); } else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) { the_subsystem = pe_subsystem; } else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) { the_subsystem = te_subsystem; } else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){ the_subsystem = cib_subsystem; } if(the_subsystem != NULL) { cleanup_subsystem(the_subsystem); } // else that was a transient client if (curr_client->table_key != NULL) { /* * Key is destroyed below: * curr_client->table_key * Value is cleaned up by: * G_main_del_IPC_Channel */ g_hash_table_remove( ipc_clients, curr_client->table_key); } if(curr_client->client_source != NULL) { gboolean det = G_main_del_IPC_Channel( curr_client->client_source); crm_verbose("crm_client was %s detached", det?"successfully":"not"); } crm_free(curr_client->table_key); crm_free(curr_client->sub_sys); crm_free(curr_client->uuid); crm_free(curr_client); } return !hack_return_good; } return hack_return_good; } void lrm_op_callback (lrm_op_t* op) { s_crmd_fsa(C_LRM_OP_CALLBACK, I_LRM_EVENT, op); } void lrm_monitor_callback (lrm_mon_t* monitor) { s_crmd_fsa(C_LRM_MONITOR_CALLBACK, I_LRM_EVENT, monitor); } void -CrmdClientStatus(const char * node, const char * client, +crmd_client_status_callback(const char * node, const char * client, const char * status, void * private) { const char *join = NULL; const char *extra = NULL; xmlNodePtr update = NULL; xmlNodePtr fragment = NULL; if(safe_str_eq(status, JOINSTATUS)){ status = ONLINESTATUS; extra = XML_CIB_ATTR_CLEAR_SHUTDOWN; } else if(safe_str_eq(status, LEAVESTATUS)){ status = OFFLINESTATUS; join = CRMD_JOINSTATE_DOWN; extra = XML_CIB_ATTR_CLEAR_SHUTDOWN; } crm_notice("Status update: Client %s/%s now has status [%s]\n", node, client, status); if(AM_I_DC) { update = create_node_state(node, NULL, status, join); if(extra != NULL) { set_xml_property_copy(update, extra, XML_BOOLEAN_TRUE); } fragment = create_cib_fragment(update, NULL); store_request(NULL, fragment, CRM_OP_UPDATE, CRM_SYSTEM_DCIB); free_xml(fragment); free_xml(update); s_crmd_fsa(C_CRMD_STATUS_CALLBACK, I_NULL, NULL); } else { crm_err("Got client status callback in non-DC mode"); } } xmlNodePtr find_xml_in_hamessage(const struct ha_msg* msg) { const char *xml; xmlDocPtr doc; xmlNodePtr root; if (msg == NULL) { crm_info("**** ha_crm_msg_callback called on a NULL message"); return NULL; } #if 0 crm_debug("[F_TYPE=%s]", ha_msg_value(msg, F_TYPE)); crm_debug("[F_ORIG=%s]", ha_msg_value(msg, F_ORIG)); crm_debug("[F_TO=%s]", ha_msg_value(msg, F_TO)); crm_debug("[F_COMMENT=%s]", ha_msg_value(msg, F_COMMENT)); crm_debug("[F_XML=%s]", ha_msg_value(msg, "xml")); // crm_debug("[F_=%s]", ha_msg_value(ha_msg, F_)); #endif if (strcmp("CRM", ha_msg_value(msg, F_TYPE)) != 0) { crm_info("Received a (%s) message by mistake.", ha_msg_value(msg, F_TYPE)); return NULL; } xml = ha_msg_value(msg, "xml"); if (xml == NULL) { crm_info("No XML attached to this message."); return NULL; } doc = xmlParseMemory(xml, strlen(xml)); if (doc == NULL) { crm_info("XML Buffer was not valid."); return NULL; } root = xmlDocGetRootElement(doc); if (root == NULL) { crm_info("Root node was NULL."); return NULL; } return root; } + +gboolean lrm_dispatch(int fd, gpointer user_data) +{ + ll_lrm_t *lrm = (ll_lrm_t*)user_data; + lrm->lrm_ops->rcvmsg(lrm, FALSE); + return TRUE; +} + + diff --git a/crm/crmd/crmd.h b/crm/crmd/crmd.h index eaf8cc8b20..d124c770d7 100644 --- a/crm/crmd/crmd.h +++ b/crm/crmd/crmd.h @@ -1,44 +1,30 @@ -/* $Id: crmd.h,v 1.6 2004/06/02 12:31:34 andrew Exp $ */ +/* $Id: crmd.h,v 1.7 2004/06/04 09:18:30 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CRMD__H #define CRMD__H #include extern GMainLoop *crmd_mainloop; extern const char *crm_system_name; extern GHashTable *ipc_clients; -extern GHashTable *pending_remote_replies; - -extern void msg_ccm_join(const struct ha_msg *msg, void *foo); - -extern gboolean crmd_client_connect(IPC_Channel *newclient, - gpointer user_data); - -extern void crmd_ha_input_callback(const struct ha_msg* msg, - void* private_data); - -extern gboolean crmd_ipc_input_callback(IPC_Channel *client, - gpointer user_data); - - #endif diff --git a/crm/crmd/crmd_callbacks.h b/crm/crmd/crmd_callbacks.h index f9f80aec80..ac988f66fe 100644 --- a/crm/crmd/crmd_callbacks.h +++ b/crm/crmd/crmd_callbacks.h @@ -1,38 +1,51 @@ /* * 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 extern void crmd_ha_input_callback(const struct ha_msg* msg, void* private_data); /* * Apparently returning TRUE means "stay connected, keep doing stuff". * Returning FALSE means "we're all done, close the connection" */ extern gboolean crmd_ipc_input_callback(IPC_Channel *client, gpointer user_data); +gboolean lrm_dispatch(int fd, gpointer user_data); + extern void lrm_op_callback (lrm_op_t* op); extern void lrm_monitor_callback (lrm_mon_t* monitor); -extern void CrmdClientStatus(const char * node, const char * client, +extern void crmd_client_status_callback(const char * node, const char * client, const char * status, void * private); + +extern void msg_ccm_join(const struct ha_msg *msg, void *foo); + +extern gboolean crmd_client_connect(IPC_Channel *newclient, + gpointer user_data); + +extern void crmd_ha_input_callback(const struct ha_msg* msg, + void* private_data); + +extern gboolean crmd_ipc_input_callback(IPC_Channel *client, + gpointer user_data); diff --git a/crm/crmd/crmd_fsa.h b/crm/crmd/crmd_fsa.h index b8236d2e75..dfed079518 100644 --- a/crm/crmd/crmd_fsa.h +++ b/crm/crmd/crmd_fsa.h @@ -1,125 +1,111 @@ -/* $Id: crmd_fsa.h,v 1.21 2004/06/02 16:03:34 andrew Exp $ */ +/* $Id: crmd_fsa.h,v 1.22 2004/06/04 09:18:30 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CRMD_FSA__H #define CRMD_FSA__H #include #include #include #include #include #include #include struct ccm_data { const oc_ev_membership_t *oc; oc_ed_t *event; }; struct oc_node_list_s { int members_size; GHashTable *members; // contents: oc_node_t * int new_members_size; GHashTable *new_members; // contents: oc_node_t * int dead_members_size; GHashTable *dead_members; // contents: oc_node_t * }; /* copy from struct client_child in heartbeat.h * * Plus a couple of other things */ typedef struct oc_node_list_s oc_node_list_t; struct crm_subsystem_s { pid_t pid; /* Process id of child process */ int respawn; /* Respawn it if it dies? */ int respawncount; /* Last time we respawned this command */ int shortrcount; /* How many times has it respawned too fast? */ const char* command; /* What command to run? */ const char* path; /* Path (argv[0])? */ /* extras */ const char* name; IPC_Channel *ipc; /* How can we communicate with it */ long long flag; /* */ }; typedef struct fsa_timer_s fsa_timer_t; struct fsa_timer_s { guint source_id; /* timer source id */ uint period_ms; /* timer period */ enum crmd_fsa_input fsa_input; gboolean (*callback)(gpointer data); }; - - extern enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause, enum crmd_fsa_input initial_input, void *data); -extern long long clear_flags(long long actions, - enum crmd_fsa_cause cause, - enum crmd_fsa_state cur_state, - enum crmd_fsa_input cur_input); - -extern gboolean do_dc_heartbeat(gpointer data); - - /* Global FSA stuff */ extern enum crmd_fsa_state fsa_state; extern oc_node_list_t *fsa_membership_copy; extern ll_cluster_t *fsa_cluster_conn; extern ll_lrm_t *fsa_lrm_conn; extern long long fsa_input_register; extern const char *fsa_our_uname; extern char *fsa_pe_ref; // the last invocation of the PE extern const char *fsa_our_dc; +extern fsa_message_queue_t fsa_message_queue; extern fsa_timer_t *election_trigger; /* */ extern fsa_timer_t *election_timeout; /* */ extern fsa_timer_t *shutdown_escalation_timmer; /* */ extern fsa_timer_t *dc_heartbeat; extern fsa_timer_t *integration_timer; extern struct crm_subsystem_s *cib_subsystem; extern struct crm_subsystem_s *te_subsystem; extern struct crm_subsystem_s *pe_subsystem; -extern enum crmd_fsa_input send_cib_status_update(xmlNodePtr update); +// these two should be moved elsewhere... extern xmlNodePtr do_update_cib_nodes(xmlNodePtr updates, gboolean overwrite); -extern enum crmd_fsa_input invoke_local_cib(xmlNodePtr msg_options, - xmlNodePtr msg_data, - const char *operation); - -extern void CrmdClientStatus(const char * node, const char * client, - const char * status, void * private); +extern gboolean do_dc_heartbeat(gpointer data); #define AM_I_DC is_set(fsa_input_register, R_THE_DC) #define AM_I_OPERATIONAL (is_set(fsa_input_register, R_STARTING)==FALSE) #include #include #endif diff --git a/crm/crmd/election.c b/crm/crmd/election.c index a36c97b431..d9a9ff38e1 100644 --- a/crm/crmd/election.c +++ b/crm/crmd/election.c @@ -1,383 +1,384 @@ /* * 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 void ghash_count_vote(gpointer key, gpointer value, gpointer user_data); /* A_ELECTION_VOTE */ enum crmd_fsa_input do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input election_result = I_NULL; /* dont vote if we're in one of these states or wanting to shut down */ switch(cur_state) { case S_RECOVERY: case S_RECOVERY_DC: case S_STOPPING: case S_RELEASE_DC: case S_TERMINATE: return I_NULL; // log warning break; default: if(is_set(fsa_input_register, R_SHUTDOWN)) { return I_NULL; // log warning } break; } send_request(NULL, NULL, CRM_OP_VOTE, NULL, CRM_SYSTEM_CRMD, NULL); return election_result; } gboolean do_dc_heartbeat(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; // crm_debug("#!!#!!# Heartbeat timer just popped!"); gboolean was_sent = send_request(NULL, NULL, CRM_OP_HBEAT, NULL, CRM_SYSTEM_CRMD, NULL); if(was_sent == FALSE) { // this is bad stopTimer(timer); // dont make it go off again s_crmd_fsa(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL); } return TRUE; } struct election_data_s { const char *winning_uname; unsigned int winning_bornon; }; /* A_ELECTION_COUNT */ enum crmd_fsa_input do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { gboolean we_loose = FALSE; xmlNodePtr vote = (xmlNodePtr)data; enum crmd_fsa_input election_result = I_NULL; const char *vote_from = xmlGetProp(vote, XML_ATTR_HOSTFROM); if(vote_from == NULL || strcmp(vote_from, fsa_our_uname) == 0) { // dont count our own vote return election_result; } if(fsa_membership_copy->members_size < 1) { // if even we are not in the cluster then we should not vote return I_FAIL; } oc_node_t *our_node = (oc_node_t*) g_hash_table_lookup(fsa_membership_copy->members, fsa_our_uname); oc_node_t *your_node = (oc_node_t*) g_hash_table_lookup(fsa_membership_copy->members, vote_from); #if 0 crm_debug("%s (bornon=%d), our bornon (%d)", vote_from, our_node->born, my_born); crm_debug("%s %s %s", fsa_our_uname, strcmp(fsa_our_uname, vote_from) < 0?"<":">=", vote_from); #endif if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_debug("Election fail: we are shutting down"); we_loose = TRUE; } else if(our_node == NULL) { crm_debug("Election fail: we dont exist in the CCM list"); we_loose = TRUE; } else if(your_node == NULL) { crm_err("The other side doesnt exist in the CCM list"); } else if(your_node->node_born_on < our_node->node_born_on) { crm_debug("Election fail: born_on"); we_loose = TRUE; } else if(your_node->node_born_on == our_node->node_born_on && strcmp(fsa_our_uname, vote_from) > 0) { crm_debug("Election fail: uname"); we_loose = TRUE; } else { struct election_data_s election_data; election_data.winning_uname = NULL; election_data.winning_bornon = -1; // maximum integer crm_trace("We might win... we should vote (possibly again)"); election_result = I_DC_TIMEOUT; // new "default" g_hash_table_foreach(fsa_membership_copy->members, ghash_count_vote, &election_data); crm_debug("Election winner should be %s (born_on=%d)", election_data.winning_uname, election_data.winning_bornon); if(safe_str_eq(election_data.winning_uname, fsa_our_uname)){ crm_debug("Election win: lowest born_on and uname"); election_result = I_ELECTION_DC; } } if(we_loose) { if(fsa_input_register & R_THE_DC) { crm_debug("Give up the DC"); election_result = I_RELEASE_DC; } else { crm_debug("We werent the DC anyway"); election_result = I_NOT_DC; } } if(we_loose || election_result == I_ELECTION_DC) { // cancel timer, its been decided stopTimer(election_timeout); } return election_result; } /* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */ // we won enum crmd_fsa_input do_election_timer_ctrl(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { if(action & A_ELECT_TIMER_START) { startTimer(election_timeout); } else if(action & A_ELECT_TIMER_STOP || action & A_ELECTION_TIMEOUT) { stopTimer(election_timeout); } else { crm_err("unexpected action %s", fsa_action2string(action)); } if(action & A_ELECTION_TIMEOUT) { crm_trace("The election timer went off, we win!"); return I_ELECTION_DC; } return I_NULL; } /* A_DC_TIMER_STOP, A_DC_TIMER_START */ enum crmd_fsa_input do_dc_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { gboolean timer_op_ok = TRUE; if(action & A_DC_TIMER_STOP) { timer_op_ok = stopTimer(election_trigger); } /* dont start a timer that wasnt already running */ if(action & A_DC_TIMER_START && timer_op_ok) { startTimer(election_trigger); } return I_NULL; } /* A_DC_TAKEOVER */ enum crmd_fsa_input do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr update = NULL, fragment = NULL; crm_trace("################## Taking over the DC ##################"); set_bit_inplace(&fsa_input_register, R_THE_DC); crm_verbose("Am I the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO); fsa_our_dc = NULL; set_bit_inplace(&fsa_input_register, R_JOIN_OK); set_bit_inplace(&fsa_input_register, R_INVOKE_PE); clear_bit_inplace(&fsa_input_register, R_CIB_DONE); clear_bit_inplace(&fsa_input_register, R_HAVE_CIB); startTimer(dc_heartbeat); if (fsa_cluster_conn->llc_ops->set_cstatus_callback( - fsa_cluster_conn, CrmdClientStatus, NULL)!=HA_OK){ + fsa_cluster_conn, crmd_client_status_callback, NULL)!=HA_OK){ crm_err("Cannot set client status callback\n"); crm_err("REASON: %s\n", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); } /* store our state in the CIB (since some fields will not be * filled in because the DC doesnt go through the join process * with itself * * bypass the TE for now, it will be informed in good time */ update = create_node_state( fsa_our_uname, NULL, ONLINESTATUS, CRMD_JOINSTATE_MEMBER); set_xml_property_copy( update,XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE); fragment = create_cib_fragment(update, NULL); store_request(NULL, fragment, CRM_OP_UPDATE, CRM_SYSTEM_DCIB); free_xml(update); free_xml(fragment); /* Async get client status information in the cluster */ fsa_cluster_conn->llc_ops->client_status( fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1); return I_NULL; } /* A_DC_RELEASE */ enum crmd_fsa_input do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; crm_trace("################## Releasing the DC ##################"); stopTimer(dc_heartbeat); if (fsa_cluster_conn->llc_ops->set_cstatus_callback( fsa_cluster_conn, NULL, NULL)!=HA_OK){ crm_err("Cannot unset client status callback\n"); crm_err("REASON: %s\n", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); result = I_ERROR; } if(action & A_DC_RELEASE) { clear_bit_inplace(&fsa_input_register, R_THE_DC); /* get a new CIB from the new DC */ clear_bit_inplace(&fsa_input_register, R_HAVE_CIB); } else if (action & A_DC_RELEASED) { if(cur_state == S_STOPPING) { result = I_SHUTDOWN; // necessary? result = I_RELEASE_SUCCESS; } #if 0 else if( are there errors ) { // we cant stay up if not healthy // or perhaps I_ERROR and go to S_RECOVER? result = I_SHUTDOWN; } #endif else result = I_RELEASE_SUCCESS; } else { crm_err("Warning, do_dc_release invoked for action %s", fsa_action2string(action)); } crm_verbose("Am I still the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO); return result; } void ghash_count_vote(gpointer key, gpointer value, gpointer user_data) { struct election_data_s *election_data = (struct election_data_s *)user_data; oc_node_t *cur_node = (oc_node_t*)value; const char *node_uname = (const char*)key; if(election_data->winning_bornon > cur_node->node_born_on) { election_data->winning_uname = node_uname; election_data->winning_bornon = cur_node->node_born_on; } else if(election_data->winning_bornon == cur_node->node_born_on && (election_data->winning_uname == NULL || strcmp(election_data->winning_uname, node_uname) > 0)) { election_data->winning_uname = node_uname; election_data->winning_bornon = cur_node->node_born_on; } } diff --git a/crm/crmd/fsa.c b/crm/crmd/fsa.c index 6564799cdc..26ee8a1c08 100644 --- a/crm/crmd/fsa.c +++ b/crm/crmd/fsa.c @@ -1,599 +1,602 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include long long do_state_transition(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, enum crmd_fsa_input current_input, void *data); -// delete this -extern fsa_message_queue_t fsa_message_queue; +long long clear_flags(long long actions, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input cur_input); + #ifdef DOT_FSA_ACTIONS # ifdef FSA_TRACE # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ crm_verbose("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data==NULL?XML_BOOLEAN_NO:XML_BOOLEAN_YES, \ fsa_input2string(next_input)); \ fflush(dot_strm); \ crm_verbose("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data==NULL?XML_BOOLEAN_NO:XML_BOOLEAN_YES, \ fsa_input2string(next_input)); \ fflush(dot_strm); \ } # endif #else # ifdef FSA_TRACE # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ crm_verbose("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ crm_verbose("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ } # endif #endif #define ELSEIF_FSA_ACTION(x,y) else IF_FSA_ACTION(x,y) const char *dot_intro = "digraph \"g\" {\n" " size = \"30,30\"\n" " graph [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " bb = \"0,0,398.922306,478.927856\"\n" " color = \"black\"\n" " ]\n" " node [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " shape = \"ellipse\"\n" " color = \"black\"\n" " ]\n" " edge [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " color = \"black\"\n" " ]\n" "// special nodes\n" " \"S_PENDING\" \n" " [\n" " color = \"blue\"\n" " fontcolor = \"blue\"\n" " ]\n" " \"S_TERMINATE\" \n" " [\n" " color = \"red\"\n" " fontcolor = \"red\"\n" " ]\n" "\n" "// DC only nodes\n" " \"S_RECOVERY_DC\" [ fontcolor = \"green\" ]\n" " \"S_INTEGRATION\" [ fontcolor = \"green\" ]\n" " \"S_POLICY_ENGINE\" [ fontcolor = \"green\" ]\n" " \"S_TRANSITION_ENGINE\" [ fontcolor = \"green\" ]\n" " \"S_RELEASE_DC\" [ fontcolor = \"green\" ]\n" " \"S_IDLE\" [ fontcolor = \"green\" ]\n"; static FILE *dot_strm = NULL; enum crmd_fsa_state fsa_state; oc_node_list_t *fsa_membership_copy; ll_cluster_t *fsa_cluster_conn; ll_lrm_t *fsa_lrm_conn; long long fsa_input_register; long long fsa_actions = A_NOTHING; const char *fsa_our_uname; const char *fsa_our_dc; fsa_timer_t *election_trigger = NULL; /* */ fsa_timer_t *election_timeout = NULL; /* */ fsa_timer_t *shutdown_escalation_timmer = NULL; /* */ fsa_timer_t *integration_timer = NULL; fsa_timer_t *dc_heartbeat = NULL; enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause, enum crmd_fsa_input initial_input, void *data) { long long actions = fsa_actions; long long new_actions = A_NOTHING; long long last_action = A_NOTHING; enum crmd_fsa_input last_input = initial_input; enum crmd_fsa_input cur_input; enum crmd_fsa_input next_input; enum crmd_fsa_state last_state, cur_state, next_state, starting_state; starting_state = fsa_state; cur_input = initial_input; next_input = initial_input; last_state = starting_state; cur_state = starting_state; next_state = starting_state; #ifdef FSA_TRACE crm_verbose("FSA invoked with Cause: %s\n\tState: %s, Input: %s", fsa_cause2string(cause), fsa_state2string(cur_state), fsa_input2string(cur_input)); #endif #ifdef DOT_FSA_ACTIONS if(dot_strm == NULL) { dot_strm = fopen("/tmp/live.dot", "w"); fprintf(dot_strm, "%s", dot_intro); } #endif /* * Process actions in order of priority but do only one * action at a time to avoid complicating the ordering. * * Actions may result in a new I_ event, these are added to * (not replace) existing actions before the next iteration. * */ while(next_input != I_NULL || actions != A_NOTHING || is_message()) { if(next_input == I_WAIT_FOR_EVENT) { /* we may be waiting for an a-sync task to "happen" * and until it does, we cant do anything else * * Re-add the last action */ actions |= last_action; crm_info("Wait until something else happens"); break; } #ifdef FSA_TRACE crm_verbose("FSA while loop:\tState: %s, Input: %s", fsa_state2string(cur_state), fsa_input2string(cur_input)); #endif /* update input variables */ cur_input = next_input; if(cur_input != I_NULL) { last_input = cur_input; } /* get the next batch of actions */ new_actions = crmd_fsa_actions[cur_input][cur_state]; if(new_actions != A_NOTHING) { #ifdef FSA_TRACE crm_verbose("Adding actions %.16llx", new_actions); #endif actions |= new_actions; } /* logging : *before* the state is changed */ IF_FSA_ACTION(A_ERROR, do_log) ELSEIF_FSA_ACTION(A_WARN, do_log) ELSEIF_FSA_ACTION(A_LOG, do_log) /* update state variables */ next_state = crmd_fsa_state[cur_input][cur_state]; last_state = cur_state; cur_state = next_state; fsa_state = next_state; /* start doing things... */ /* * Hook for change of state. * Allows actions to be added or removed when entering a state */ if(last_state != cur_state){ actions = do_state_transition(actions, cause, last_state, cur_state, last_input, data); } /* this is always run, some inputs/states may make various * actions irrelevant/invalid */ actions = clear_flags(actions, cause, cur_state, cur_input); /* regular action processing in order of action priority * * Make sure all actions that connect to required systems * are performed first */ if(actions == A_NOTHING) { crm_info("Nothing to do"); next_input = I_NULL; /* // check registers, see if anything is pending if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_verbose("(Re-)invoking shutdown"); next_input = I_SHUTDOWN; } else if(is_set(fsa_input_register, R_INVOKE_PE)) { crm_verbose("Invoke the PE somehow"); } */ } /* get out of here NOW! before anything worse happens */ ELSEIF_FSA_ACTION(A_EXIT_1, do_exit) ELSEIF_FSA_ACTION(A_STARTUP, do_startup) ELSEIF_FSA_ACTION(A_CIB_START, do_cib_control) ELSEIF_FSA_ACTION(A_HA_CONNECT, do_ha_control) ELSEIF_FSA_ACTION(A_LRM_CONNECT,do_lrm_control) ELSEIF_FSA_ACTION(A_CCM_CONNECT,do_ccm_control) /* sub-system start */ ELSEIF_FSA_ACTION(A_TE_START, do_te_control) ELSEIF_FSA_ACTION(A_PE_START, do_pe_control) /* sub-system restart */ ELSEIF_FSA_ACTION(O_CIB_RESTART,do_cib_control) ELSEIF_FSA_ACTION(O_PE_RESTART, do_pe_control) ELSEIF_FSA_ACTION(O_TE_RESTART, do_te_control) ELSEIF_FSA_ACTION(A_STARTED, do_started) /* DC Timer */ ELSEIF_FSA_ACTION(O_DC_TIMER_RESTART, do_dc_timer_control) ELSEIF_FSA_ACTION(A_DC_TIMER_STOP, do_dc_timer_control) ELSEIF_FSA_ACTION(A_DC_TIMER_START, do_dc_timer_control) /* * Highest priority actions */ ELSEIF_FSA_ACTION(A_CIB_BUMPGEN, do_cib_invoke) ELSEIF_FSA_ACTION(A_TE_COPYTO, do_te_copyto) ELSEIF_FSA_ACTION(A_MSG_ROUTE, do_msg_route) ELSEIF_FSA_ACTION(A_RECOVER, do_recover) - ELSEIF_FSA_ACTION(A_UPDATE_NODESTATUS, do_lrm_invoke) + ELSEIF_FSA_ACTION(A_UPDATE_NODESTATUS, do_update_node_status) ELSEIF_FSA_ACTION(A_JOIN_ACK, do_ack_welcome) ELSEIF_FSA_ACTION(A_SHUTDOWN_REQ, do_shutdown_req) ELSEIF_FSA_ACTION(A_ELECTION_VOTE, do_election_vote) ELSEIF_FSA_ACTION(A_ELECT_TIMER_STOP, do_election_timer_ctrl) ELSEIF_FSA_ACTION(A_ELECT_TIMER_START, do_election_timer_ctrl) ELSEIF_FSA_ACTION(A_ELECTION_COUNT, do_election_count_vote) ELSEIF_FSA_ACTION(A_ELECTION_TIMEOUT, do_election_timer_ctrl) /* * "Get this over with" actions */ ELSEIF_FSA_ACTION(A_MSG_STORE, do_msg_store) /* * High priority actions * Update the cache first */ ELSEIF_FSA_ACTION(A_CCM_UPDATE_CACHE, do_ccm_update_cache) ELSEIF_FSA_ACTION(A_CCM_EVENT, do_ccm_event) /* * Medium priority actions */ ELSEIF_FSA_ACTION(A_DC_TAKEOVER, do_dc_takeover) ELSEIF_FSA_ACTION(A_DC_RELEASE, do_dc_release) ELSEIF_FSA_ACTION(A_JOIN_WELCOME_ALL, do_send_welcome_all) ELSEIF_FSA_ACTION(A_JOIN_WELCOME, do_send_welcome) ELSEIF_FSA_ACTION(A_JOIN_PROCESS_ACK, do_process_welcome_ack) /* * Low(er) priority actions * Make sure the CIB is always updated before invoking the * PE, and the PE before the TE */ ELSEIF_FSA_ACTION(A_CIB_INVOKE_LOCAL, do_cib_invoke) ELSEIF_FSA_ACTION(A_CIB_INVOKE, do_cib_invoke) ELSEIF_FSA_ACTION(A_LRM_INVOKE, do_lrm_invoke) ELSEIF_FSA_ACTION(A_LRM_EVENT, do_lrm_event) ELSEIF_FSA_ACTION(A_TE_CANCEL, do_te_invoke) ELSEIF_FSA_ACTION(A_PE_INVOKE, do_pe_invoke) ELSEIF_FSA_ACTION(A_TE_INVOKE, do_te_invoke) ELSEIF_FSA_ACTION(A_ANNOUNCE, do_announce) /* sub-system stop */ ELSEIF_FSA_ACTION(A_PE_STOP, do_pe_control) ELSEIF_FSA_ACTION(A_TE_STOP, do_te_control) ELSEIF_FSA_ACTION(A_DC_RELEASED, do_dc_release) ELSEIF_FSA_ACTION(A_HA_DISCONNECT, do_ha_control) ELSEIF_FSA_ACTION(A_CCM_DISCONNECT, do_ccm_control) ELSEIF_FSA_ACTION(A_LRM_DISCONNECT, do_lrm_control) ELSEIF_FSA_ACTION(A_CIB_STOP, do_cib_control) /* time to go now... */ /* Some of these can probably be consolidated */ ELSEIF_FSA_ACTION(A_SHUTDOWN, do_shutdown) ELSEIF_FSA_ACTION(A_STOP, do_stop) /* exit gracefully */ ELSEIF_FSA_ACTION(A_EXIT_0, do_exit) // ELSEIF_FSA_ACTION(A_, do_) else if((actions & A_MSG_PROCESS) != 0 || is_message()) { xmlNodePtr stored_msg = NULL; crm_verbose("Checking messages... %d", g_list_length(fsa_message_queue)); stored_msg = get_message(); if(is_message() == FALSE) { actions = clear_bit(actions, A_MSG_PROCESS); } if(stored_msg == NULL) { crm_err("Invalid stored message"); continue; } /* * This is where we should clean up old messages * The problem is that we dont always know the * type of the data (and therefore the correct way * to free it). A wrapper is probably required. */ data = stored_msg; #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t// %s:\t%s\t(data? %s)", fsa_input2string(cur_input), fsa_action2string(A_MSG_PROCESS), stored_msg==NULL?XML_BOOLEAN_NO:XML_BOOLEAN_YES); fflush(dot_strm); #endif #ifdef FSA_TRACE crm_verbose("Invoking action %s (%.16llx)", fsa_action2string(A_MSG_PROCESS), A_MSG_PROCESS); #endif //#ifdef FSA_TRACE xml_message_debug(stored_msg,"FSA processing message"); //#endif next_input = handle_message(stored_msg); #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t(result=%s)\n", fsa_input2string(next_input)); #endif crm_verbose("Result of action %s was %s", fsa_action2string(A_MSG_PROCESS), fsa_input2string(next_input)); /* Error checking and reporting */ } else if(cur_input != I_NULL && is_set(actions, A_NOTHING)) { crm_warn( "No action specified for input,state (%s,%s)", fsa_input2string(cur_input), fsa_state2string(cur_state)); next_input = I_NULL; } else if(cur_input == I_NULL && is_set(actions, A_NOTHING)) { #ifdef FSA_TRACE crm_info("Nothing left to do"); #endif } else { crm_err("Action %s (0x%llx) not supported ", fsa_action2string(actions), actions); next_input = I_ERROR; } if(is_message()) { actions |= A_MSG_PROCESS; } } #ifdef FSA_TRACE crm_verbose("################# Exiting the FSA (%s) ##################", fsa_state2string(fsa_state)); #endif #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t// ### Exiting the FSA (%s)\n", fsa_state2string(fsa_state)); fflush(dot_strm); #endif // cleanup inputs? fsa_actions = actions; return fsa_state; } long long do_state_transition(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, enum crmd_fsa_input current_input, void *data) { long long tmp = actions; const char *state_from = fsa_state2string(cur_state); const char *state_to = fsa_state2string(next_state); const char *input = fsa_input2string(current_input); time_t now = time(NULL); if(cur_state == next_state) { crm_err("%s called in state %s with no transtion", __FUNCTION__, state_from); return A_NOTHING; } // if(current_input != I_NULL // && (current_input != I_DC_HEARTBEAT || cur_state != S_NOT_DC)){ fprintf(dot_strm, "\t\"%s\" -> \"%s\" [ label =\"%s\" ] // %s", state_from, state_to, input, asctime(localtime(&now))); fflush(dot_strm); //} crm_info("State transition \"%s\" -> \"%s\" [ cause =\"%s\" %s ]", state_from, state_to, input, asctime(localtime(&now))); switch(next_state) { case S_PENDING: break; case S_NOT_DC: if(is_set(fsa_input_register, R_SHUTDOWN)){ crm_info("(Re)Issuing shutdown request now" " that we have a new DC"); tmp = set_bit(tmp, A_SHUTDOWN_REQ); } tmp = clear_bit(tmp, A_RECOVER); break; case S_RECOVERY_DC: case S_RECOVERY: tmp = set_bit(tmp, A_RECOVER); break; default: tmp = clear_bit(tmp, A_RECOVER); break; } if(tmp != actions) { crm_info("Action b4 %.16llx ", actions); crm_info("Action after %.16llx ", tmp); actions = tmp; } return actions; } long long clear_flags(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input) { if(is_set(fsa_input_register, R_SHUTDOWN)){ clear_bit_inplace(&actions, A_DC_TIMER_START); } switch(cur_state) { case S_IDLE: break; case S_ELECTION: break; case S_INTEGRATION: break; case S_NOT_DC: break; case S_POLICY_ENGINE: break; case S_RECOVERY: break; case S_RECOVERY_DC: break; case S_RELEASE_DC: break; case S_PENDING: break; case S_STOPPING: break; case S_TERMINATE: break; case S_TRANSITION_ENGINE: break; case S_ILLEGAL: break; } return actions; } diff --git a/crm/crmd/fsa_proto.h b/crm/crmd/fsa_proto.h index 704f929f73..01f440f295 100644 --- a/crm/crmd/fsa_proto.h +++ b/crm/crmd/fsa_proto.h @@ -1,320 +1,329 @@ -/* $Id: fsa_proto.h,v 1.8 2004/06/01 12:25:16 andrew Exp $ */ +/* $Id: fsa_proto.h,v 1.9 2004/06/04 09:18:30 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef XML_FSA_PROTO__H #define XML_FSA_PROTO__H /* A_ANNOUNCE */ enum crmd_fsa_input do_announce(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data); /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data); /* A_ERROR */ enum crmd_fsa_input do_error(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LOG */ enum crmd_fsa_input do_log(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STARTUP */ enum crmd_fsa_input do_startup(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CIB_START, STOP, RESTART */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_HA_CONNECT */ enum crmd_fsa_input do_ha_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_CONNECT */ enum crmd_fsa_input do_ccm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LRM_CONNECT */ enum crmd_fsa_input do_lrm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_PE_START, STOP, RESTART */ enum crmd_fsa_input do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_TE_START, STOP, RESTART */ enum crmd_fsa_input do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STARTED */ enum crmd_fsa_input do_started(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_MSG_ROUTE */ enum crmd_fsa_input do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_RECOVER */ enum crmd_fsa_input do_recover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECTION_VOTE */ enum crmd_fsa_input do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECTION_COUNT */ enum crmd_fsa_input do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */ enum crmd_fsa_input do_election_timer_ctrl(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_TIMER_STOP */ enum crmd_fsa_input do_dc_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_MSG_STORE */ enum crmd_fsa_input do_msg_store(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_UPDATE_CACHE */ enum crmd_fsa_input do_ccm_update_cache(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_EVENT */ enum crmd_fsa_input do_ccm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_TAKEOVER */ enum crmd_fsa_input do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_RELEASE */ enum crmd_fsa_input do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_WELCOME_ALL */ enum crmd_fsa_input do_send_welcome_all(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_WELCOME */ enum crmd_fsa_input do_send_welcome(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_ACK */ enum crmd_fsa_input do_ack_welcome(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_JOIN_PROCESS_ACK */ enum crmd_fsa_input do_process_welcome_ack(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CIB_INVOKE */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); + +/* A_UPDATE_NODESTATUS */ +enum crmd_fsa_input +do_update_node_status(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input cur_input, + void *data); + /* A_LRM_INVOKE */ enum crmd_fsa_input do_lrm_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LRM_EVENT */ enum crmd_fsa_input do_lrm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_TE_INVOKE, A_TE_CANCEL */ enum crmd_fsa_input do_te_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_TE_INVOKE */ enum crmd_fsa_input do_te_copyto(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_SHUTDOWN_REQ */ enum crmd_fsa_input do_shutdown_req(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_SHUTDOWN */ enum crmd_fsa_input do_shutdown(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STOP */ enum crmd_fsa_input do_stop(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_EXIT_0, A_EXIT_1 */ enum crmd_fsa_input do_exit(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); #endif diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c index 75604ad10d..16f8b6e81d 100644 --- a/crm/crmd/lrm.c +++ b/crm/crmd/lrm.c @@ -1,606 +1,660 @@ /* * 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 #include #include #include #include +#include #include -xmlNodePtr do_lrm_query(void); +xmlNodePtr do_lrm_query(gboolean); + +gboolean build_suppported_RAs(xmlNodePtr xml_agent_list); + +gboolean build_active_RAs(xmlNodePtr rsc_list); + +void do_update_resource( + lrm_rsc_t *rsc, int status, int rc, const char *op_type); + +enum crmd_fsa_input do_lrm_rsc_op( + lrm_rsc_t *rsc, rsc_id_t rid, const char *operation, xmlNodePtr msg); + +enum crmd_fsa_input do_lrm_monitor(lrm_rsc_t *rsc); + +enum crmd_fsa_input do_fake_lrm_op(gpointer data); GHashTable *xml2list(xmlNodePtr parent, const char **attr_path, int depth); -gboolean lrm_dispatch(int fd, gpointer user_data); +const char *rsc_path[] = +{ + "msg_data", + "rsc_op", + "resource", + "instance_attributes", + "parameters" +}; -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; - if(action & A_LRM_DISCONNECT) { fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); } if(action & A_LRM_CONNECT) { crm_trace("LRM: connect..."); fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM); if(NULL == fsa_lrm_conn) { return failed; } crm_trace("LRM: sigon..."); ret = fsa_lrm_conn->lrm_ops->signon(fsa_lrm_conn, CRM_SYSTEM_CRMD); if(ret != HA_OK) { crm_err("Failed to sign on to the LRM"); return failed; } crm_trace("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) { crm_err("Failed to set LRM callbacks"); return failed; } /* TODO: create a destroy handler that causes * some recovery to happen */ G_main_add_fd(G_PRIORITY_LOW, fsa_lrm_conn->lrm_ops->inputfd(fsa_lrm_conn), FALSE, lrm_dispatch, fsa_lrm_conn, default_ipc_input_destroy); } if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return 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) +gboolean +build_suppported_RAs(xmlNodePtr xml_agent_list) { int lpc = 0, llpc = 0; - GList *types = NULL; GList *classes = NULL; - GList *op_list = NULL; - GList *lrm_list = NULL; - - state_flag_t cur_state = 0; - const char *this_op = NULL; - xmlNodePtr xml_agent = NULL; - xmlNodePtr xml_data = create_xml_node(NULL, XML_CIB_TAG_LRM); - xmlNodePtr rsc_list = create_xml_node(xml_data,XML_LRM_TAG_RESOURCES); - xmlNodePtr xml_agent_list = create_xml_node(xml_data, "lrm_agents"); - - /* Build a list of supported agents */ - classes = fsa_lrm_conn->lrm_ops->get_rsc_class_supported( - fsa_lrm_conn); + + classes = fsa_lrm_conn->lrm_ops->get_rsc_class_supported(fsa_lrm_conn); slist_iter( class, char, classes, lpc, types = fsa_lrm_conn->lrm_ops->get_rsc_type_supported( fsa_lrm_conn, class); slist_iter( type, char, types, llpc, xml_agent = create_xml_node( xml_agent_list, "lrm_agent"); set_xml_property_copy(xml_agent, "class", class); set_xml_property_copy(xml_agent, XML_ATTR_TYPE, type); /* we dont have this yet */ - set_xml_property_copy(xml_agent, "version", NULL); + set_xml_property_copy(xml_agent, "version", "1"); ) g_list_free(types); ); g_list_free(classes); - /* Build a list of active (not always running) resources */ + return TRUE; +} + + +gboolean +build_active_RAs(xmlNodePtr rsc_list) +{ + int lpc = 0, llpc = 0; + + GList *op_list = NULL; + GList *lrm_list = NULL; + + state_flag_t cur_state = 0; + const char *this_op = NULL; + lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); slist_iter( the_rsc, lrm_rsc_t, lrm_list, lpc, -/* GHashTable* params; */ +/* GHashTable* params; */ xmlNodePtr xml_rsc = create_xml_node(rsc_list, "rsc_state"); const char *status_text = ""; set_xml_property_copy(xml_rsc, XML_ATTR_ID, the_rsc->id); set_xml_property_copy(xml_rsc, "type", the_rsc->type); set_xml_property_copy(xml_rsc, "class", the_rsc->class); set_xml_property_copy(xml_rsc, "node_id", fsa_our_uname); op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); crm_verbose("\tcurrent state:%s\n", cur_state==LRM_RSC_IDLE?"Idle":"Busy"); slist_iter( op, lrm_op_t, op_list, llpc, this_op = op->op_type; gboolean found = FALSE; if(found == FALSE && safe_str_neq(this_op, "status")){ 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; } } if(found) { set_xml_property_copy( xml_rsc, "rsc_op", this_op); /* we only want the last one */ break; } ) set_xml_property_copy(xml_rsc, "op_result", status_text); g_list_free(op_list); ); g_list_free(lrm_list); + + return TRUE; +} + +xmlNodePtr +do_lrm_query(gboolean is_replace) +{ + xmlNodePtr xml_result= NULL; + xmlNodePtr xml_state = create_xml_node(NULL, XML_CIB_TAG_STATE); + xmlNodePtr xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM); + xmlNodePtr rsc_list = create_xml_node(xml_data,XML_LRM_TAG_RESOURCES); + xmlNodePtr xml_agent_list = create_xml_node(xml_data, "lrm_agents"); + + /* Build a list of supported agents */ + build_suppported_RAs(xml_agent_list); - return xml_data; + /* Build a list of active (not always running) resources */ + build_active_RAs(rsc_list); + + if(is_replace) { + set_xml_property_copy(xml_data, "replace", XML_CIB_TAG_LRM); + } + + set_xml_property_copy(xml_state, XML_ATTR_ID, fsa_our_uname); + xml_result = create_cib_fragment(xml_state, NULL); + + return xml_result; +} + +/* A_UPDATE_NODESTATUS */ +enum crmd_fsa_input +do_update_node_status(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + xmlNodePtr update = NULL, + fragment = NULL, + tmp1 = NULL; + fragment = NULL; + if(action & A_UPDATE_NODESTATUS) { + +#ifndef USE_FAKE_LRM + update = do_lrm_query(TRUE); +#else + tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); + set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname); + update = create_cib_fragment(tmp1, NULL); +#endif + /* this only happens locally. the updates are pushed out + * as part of the join process + */ + store_request(NULL, update, CRM_OP_UPDATE, CRM_SYSTEM_DC); + free_xml(update); + + return I_NULL; + } + + return I_ERROR; } /* 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; - - - - 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); - - return next_input; - } #ifdef USE_FAKE_LRM - if(data == NULL) { - return 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_verbose("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(); + return do_fake_lrm_op(data); #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); - } - - return I_NULL; -#endif - crm_err("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); + 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); + 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, reply; - 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); - + data = do_lrm_query(FALSE); 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) { - crm_err("Could not find resource to monitor"); - return I_FAIL; - } + next_input = do_lrm_monitor(rsc); - 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_verbose("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) { - crm_err("Could not add resource to LRM"); - return I_FAIL; - } + next_input = do_lrm_rsc_op(rsc, rid, operation, msg); - // now do the op - crm_verbose("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); + } else { + next_input = I_ERROR; } return next_input; } + +enum crmd_fsa_input +do_lrm_rsc_op( + lrm_rsc_t *rsc, rsc_id_t rid, const char *operation, xmlNodePtr msg) +{ + lrm_op_t* op = NULL; + + if(rsc == NULL) { + // add it to the list + crm_verbose("adding rsc %s before operation", rid); + fsa_lrm_conn->lrm_ops->add_rsc( + fsa_lrm_conn, rid, + 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) { + crm_err("Could not add resource to LRM"); + return I_FAIL; + } + + // now do the op + crm_verbose("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); + + return I_NULL; +} + +enum crmd_fsa_input +do_lrm_monitor(lrm_rsc_t *rsc) +{ + lrm_mon_t* mon = NULL; + + if(rsc == NULL) { + crm_err("Could not find resource to monitor"); + return 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); + + return I_NULL; +} + + 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_verbose("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) { 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_trace("An LRM monitor operation passed"); return I_NULL; break; case LRM_OP_CANCELLED: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: case LRM_OP_ERROR: crm_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: crm_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 { return I_FAIL; } return I_NULL; } + +enum crmd_fsa_input +do_fake_lrm_op(gpointer data) +{ + xmlNodePtr msg = NULL; + const char *crm_op = NULL; + const char *operation = NULL; + const char *id_from_cib = NULL; + + if(data == NULL) { + return 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_verbose("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); + } + + return I_NULL; +} diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c index b59f1cd3e5..4f1ebf0639 100644 --- a/crm/crmd/subsystems.c +++ b/crm/crmd/subsystems.c @@ -1,628 +1,629 @@ /* * 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 #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; 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 { crm_info("Ignoring request to start %s after shutdown", this_subsys->command); } } return 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; 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) { crm_err("No message for CIB command"); return 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) { crm_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)) { return 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); return 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) { crm_err("No message for CIB command"); return I_NULL; // I_ERROR } answer = process_cib_message(cib_msg, TRUE); put_message(answer); return 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) { crm_err("Result of BUMP in %s was NULL", __FUNCTION__); return I_FAIL; } send_request(NULL, answer, CRM_OP_REPLACE, NULL, CRM_SYSTEM_CRMD, NULL); free_xml(answer); } else { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return 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; 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)) { crm_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 { crm_info("Ignoring request to start %s while shutting down", this_subsys->command); } } return 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) { stopTimer(integration_timer); if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){ crm_info("Waiting for the PE to connect"); return I_WAIT_FOR_EVENT; } xmlNodePtr local_cib = get_cib_copy(); crm_verbose("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); return 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; /* if(action & stop_actions && cur_state != S_STOPPING */ /* && is_set(fsa_input_register, R_TE_PEND)) { */ /* result = I_WAIT_FOR_EVENT; */ /* return 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)) { crm_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 { crm_info("Ignoring request to start %s while shutting down", this_subsys->command); } } return 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; 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){ crm_info("Waiting for the TE to connect"); if(data != NULL) { free_xml(te_lastcc); te_lastcc = message; } return 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); } return 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; if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){ crm_info("Waiting for the TE to connect"); if(data != NULL) { free_xml(te_last_input); te_last_input = copy_xml_node_recursive(msg); } return 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) { return 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); } return I_NULL; } gboolean crmd_client_connect(IPC_Channel *client_channel, gpointer user_data) { if (client_channel == NULL) { crm_err("Channel was NULL"); } else if (client_channel->ch_status == IPC_DISCONNECT) { crm_err("Channel was disconnected"); } else { crmd_client_t *blank_client = (crmd_client_t *)crm_malloc(sizeof(crmd_client_t)); if (blank_client == NULL) { crm_err("Could not allocate memory for a blank crmd_client_t"); return FALSE; } client_channel->ops->set_recv_qlen(client_channel, 100); client_channel->ops->set_send_qlen(client_channel, 100); blank_client->client_channel = client_channel; blank_client->sub_sys = NULL; blank_client->uuid = NULL; blank_client->table_key = NULL; blank_client->client_source = G_main_add_IPC_Channel(G_PRIORITY_LOW, client_channel, FALSE, crmd_ipc_input_callback, blank_client, default_ipc_input_destroy); } return TRUE; } static gboolean stop_subsystem(struct crm_subsystem_s* centry) { crm_info("Stopping sub-system \"%s\"", centry->name); if (centry->pid <= 0) { crm_err("OOPS! client %s not running yet", centry->command); } else { crm_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; crm_info("Starting sub-system \"%s\"", centry->command); if (centry->pid != 0) { crm_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: crm_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); } crm_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; }