diff --git a/crm/cib/cibprimatives.c b/crm/cib/cibprimatives.c index 3a485a68ee..8a83cbfe51 100644 --- a/crm/cib/cibprimatives.c +++ b/crm/cib/cibprimatives.c @@ -1,577 +1,590 @@ -/* $Id: cibprimatives.c,v 1.24 2004/04/15 00:34:06 msoffen Exp $ */ +/* $Id: cibprimatives.c,v 1.25 2004/04/15 08:31:13 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 /* * In case of confusion, this is the memory management policy for * all functions in this file. * * All add/modify functions use copies of supplied data. * It is therefore appropriate that the callers free the supplied data * at some point after the function has finished. * * All delete functions will handle the freeing of deleted data * but not the function arguments. */ void update_node_state(xmlNodePtr existing_node, xmlNodePtr update); //--- Resource int addResource(xmlNodePtr cib, xmlNodePtr anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Adding " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return add_cib_object(root, anXmlNode); } xmlNodePtr findResource(xmlNodePtr cib, const char *id) { xmlNodePtr root = NULL, ret = NULL; FNIN(); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); ret = find_entity(root, XML_CIB_TAG_RESOURCE, id, FALSE); FNRET(ret); } int updateResource(xmlNodePtr cib, xmlNodePtr anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Updating " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return update_cib_object(root, anXmlNode, FALSE); } int delResource(xmlNodePtr cib, xmlNodePtr delete_spec) { const char *id = ID(delete_spec); xmlNodePtr root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Deleting " XML_CIB_TAG_RESOURCE " (%s)...", id); root = get_object_root(XML_CIB_TAG_RESOURCES, cib); return delete_cib_object(root, delete_spec); } //--- Constraint int addConstraint(xmlNodePtr cib, xmlNodePtr anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Adding " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return add_cib_object(root, anXmlNode); } xmlNodePtr findConstraint(xmlNodePtr cib, const char *id) { xmlNodePtr root = NULL, ret = NULL; FNIN(); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); ret = find_entity(root, XML_CIB_TAG_CONSTRAINT, id, FALSE); FNRET(ret); } int updateConstraint(xmlNodePtr cib, xmlNodePtr anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Updating " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return update_cib_object(root, anXmlNode, FALSE); } int delConstraint(xmlNodePtr cib, xmlNodePtr delete_spec) { const char *id = ID(delete_spec); xmlNodePtr root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Deleting " XML_CIB_TAG_CONSTRAINT " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return delete_cib_object(root, delete_spec); } //--- HaNode int addHaNode(xmlNodePtr cib, xmlNodePtr anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Adding " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_NODES, cib); return add_cib_object(root, anXmlNode); } xmlNodePtr findHaNode(xmlNodePtr cib, const char *id) { xmlNodePtr root = NULL, ret = NULL; FNIN(); root = get_object_root(XML_CIB_TAG_NODES, cib); ret = find_entity(root, XML_CIB_TAG_NODE, id, FALSE); FNRET(ret); } int updateHaNode(xmlNodePtr cib, cibHaNode *anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Updating " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_NODES, cib); return update_cib_object(root, anXmlNode, FALSE); } int delHaNode(xmlNodePtr cib, xmlNodePtr delete_spec) { const char *id = ID(delete_spec); xmlNodePtr root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Deleting " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); return delete_cib_object(root, delete_spec); } //--- Status int addStatus(xmlNodePtr cib, xmlNodePtr anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Adding " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return add_cib_object(root, anXmlNode); } xmlNodePtr findStatus(xmlNodePtr cib, const char *id) { xmlNodePtr root = NULL, ret = NULL; root = get_object_root(XML_CIB_TAG_STATUS, cib); ret = find_entity(root, XML_CIB_TAG_STATE, id, FALSE); FNRET(ret); } int updateStatus(xmlNodePtr cib, xmlNodePtr anXmlNode) { const char *id = ID(anXmlNode); xmlNodePtr root; if (id == NULL || strlen(id) < 1) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Updating " XML_CIB_TAG_NODE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return update_cib_object(root, anXmlNode, FALSE); } int delStatus(xmlNodePtr cib, xmlNodePtr delete_spec) { const char *id = ID(delete_spec); xmlNodePtr root; if(id == NULL || strlen(id) == 0) { return CIBRES_MISSING_ID; } CRM_DEBUG2("Deleting " XML_CIB_TAG_STATE " (%s)...", id); root = get_object_root(XML_CIB_TAG_STATUS, cib); return delete_cib_object(root, delete_spec); } int delete_cib_object(xmlNodePtr parent, xmlNodePtr delete_spec) { const char *object_name = NULL; const char *object_id = NULL; xmlNodePtr equiv_node = NULL; xmlNodePtr children = NULL; int result = CIBRES_OK; if(delete_spec == NULL) { return CIBRES_FAILED_NOOBJECT; } else if(parent == NULL) { return CIBRES_FAILED_NOPARENT; } object_name = delete_spec->name; object_id = xmlGetProp(delete_spec, XML_ATTR_ID); children = delete_spec->children; if(object_id == NULL) { // placeholder object equiv_node = find_xml_node(parent, object_name); } else { equiv_node = find_entity(parent, object_name, object_id, FALSE); } if(equiv_node == NULL) { return CIBRES_FAILED_NOTEXISTS; } else if(children == NULL) { // only leaves are deleted unlink_xml_node(equiv_node); free_xml(equiv_node); } else { while(children != NULL) { int tmp_result = delete_cib_object(equiv_node, children); // only the first error is likely to be interesting if(tmp_result != CIBRES_OK && result == CIBRES_OK) { result = tmp_result; } children = children->next; } } return result; } int add_cib_object(xmlNodePtr parent, xmlNodePtr new_obj) { const char *object_name = NULL; const char *object_id = NULL; xmlNodePtr equiv_node = NULL; xmlNodePtr children = NULL; if(new_obj == NULL) { return CIBRES_FAILED_NOOBJECT; } else if(parent == NULL) { return CIBRES_FAILED_NOPARENT; } object_name = new_obj->name; object_id = xmlGetProp(new_obj, XML_ATTR_ID); children = new_obj->children; if(object_id == NULL) { // placeholder object equiv_node = find_xml_node(parent, object_name); } else { equiv_node = find_entity(parent, object_name, object_id, FALSE); } if(equiv_node != NULL) { return CIBRES_FAILED_EXISTS; } else if(add_node_copy(parent, new_obj) == NULL) { return CIBRES_FAILED_NODECOPY; } return CIBRES_OK; } int update_cib_object(xmlNodePtr parent, xmlNodePtr new_obj, gboolean force) { const char *object_name = NULL; const char *object_id = NULL; xmlNodePtr equiv_node = NULL; xmlNodePtr children = NULL; int result = CIBRES_OK; if(new_obj == NULL) { return CIBRES_FAILED_NOOBJECT; } else if(parent == NULL) { return CIBRES_FAILED_NOPARENT; } object_name = new_obj->name; object_id = xmlGetProp(new_obj, XML_ATTR_ID); children = new_obj->children; if(object_id == NULL) { // placeholder object equiv_node = find_xml_node(parent, object_name); } else { equiv_node = find_entity(parent, object_name, object_id, FALSE); } if(equiv_node != NULL) { if(force == FALSE) { const char *ts_existing = NULL; const char *ts_new = NULL; /* default to false? * * that would mean every node would have to * carry a timestamp */ gboolean is_update = TRUE; ts_existing = TSTAMP(equiv_node); ts_new = TSTAMP(new_obj); if(ts_new != NULL && ts_existing != NULL) { is_update = (strcmp(ts_new, ts_existing) > 0); } if(is_update == FALSE) { cl_log(LOG_ERR, "Ignoring old update to <%s id=\"%s\">" "(%s vs. %s)", object_name, object_id, ts_new, ts_existing); return CIBRES_FAILED_STALE; } } if(safe_str_eq(XML_CIB_TAG_STATE, object_name)){ update_node_state(equiv_node, new_obj); } else { copy_in_properties(equiv_node, new_obj); } while(children != NULL) { int tmp_result = update_cib_object(equiv_node, children,force); // only the first error is likely to be interesting if(tmp_result != CIBRES_OK && result == CIBRES_OK) { result = tmp_result; } children = children->next; } } else if(add_node_copy(parent, new_obj) == NULL) { return CIBRES_FAILED_NODECOPY; } return result; } void update_node_state(xmlNodePtr target, xmlNodePtr update) { gboolean any_updates = FALSE; + gboolean replace_lrm = FALSE; const char *old_state = xmlGetProp(target, "state"); const char *old_unclean = xmlGetProp(target, "unclean"); const char *source = NULL; const char *unclean = NULL; const char *exp_state = NULL; const char *state = NULL; xmlAttrPtr prop_iter = NULL; FNIN(); prop_iter = update->properties; while(prop_iter != NULL) { const char *local_prop_name = prop_iter->name; const char *local_prop_value = xmlGetProp(update, local_prop_name); if(local_prop_name == NULL) { // error + } else if(strcmp(local_prop_name, "replace_lrm") == 0) { + replace_lrm = TRUE; + any_updates = TRUE; + } else if(strcmp(local_prop_name, "source") == 0) { source = local_prop_value; } else if(strcmp(local_prop_name, "state") == 0) { state = local_prop_value; } else { any_updates = TRUE; set_xml_property_copy(target, local_prop_name, local_prop_value); } prop_iter = prop_iter->next; } unclean = xmlGetProp(target, "unclean"); exp_state = xmlGetProp(target, "exp_state"); if(safe_str_eq(state, "in_ccm")) { if(safe_str_eq(old_state, "active")) { state = "active"; } else { any_updates = TRUE; } } else if(safe_str_eq(state, "down")) { any_updates = TRUE; if(safe_str_neq(exp_state, "down")) { // TODO: Set the actual time // TODO: Only if not set? if(old_unclean == NULL) { set_xml_property_copy(target, "unclean", "time"); } // TODO: unset source? } } else if(state != NULL) { any_updates = TRUE; } + + if(replace_lrm) { + xmlNodePtr lrm = find_xml_node(target, "lrm"); + xmlUnlinkNode(lrm); + free_xml(lrm); + + } + set_xml_property_copy(target, "state", state); if(any_updates) { set_node_tstamp(target); set_xml_property_copy(target, "source", source); } } diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c index 9a2e217e04..ff6cc13782 100644 --- a/crm/crmd/ccm.c +++ b/crm/crmd/ccm.c @@ -1,502 +1,509 @@ /* * 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 void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); #include #include #include +#include #include #include int register_with_ccm(ll_cluster_t *hb_cluster); void msg_ccm_join(const struct ha_msg *msg, void *foo); void crmd_ccm_input_callback(oc_ed_t event, void *cookie, size_t size, const void *data); void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event); gboolean ccm_dispatch(int fd, gpointer user_data); void new_node_state(xmlNodePtr node_updates, const char *uname, const char *state); #define CCM_EVENT_DETAIL 1 oc_ev_t *fsa_ev_token; /* A_CCM_CONNECT */ enum crmd_fsa_input do_ccm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { int ret; /* fd_set rset; */ int fsa_ev_fd; FNIN(); if(action & A_CCM_DISCONNECT){ oc_ev_unregister(fsa_ev_token); } if(action & A_CCM_CONNECT) { cl_log(LOG_INFO, "Registering with CCM"); oc_ev_register(&fsa_ev_token); cl_log(LOG_INFO, "Setting up CCM callbacks"); oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS, crmd_ccm_input_callback, NULL); oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/); cl_log(LOG_INFO, "Activating CCM token"); ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd); if (ret){ cl_log(LOG_INFO, "CCM Activation failed... unregistering"); oc_ev_unregister(fsa_ev_token); return(I_FAIL); } cl_log(LOG_INFO, "CCM Activation passed... all set to go!"); /* FD_ZERO(&rset); */ /* FD_SET(fsa_ev_fd, &rset); */ //GFDSource* G_main_add_fd(G_PRIORITY_LOW, fsa_ev_fd, FALSE, ccm_dispatch, fsa_ev_token, default_ipc_input_destroy); } if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) { cl_log(LOG_ERR, "Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } FNRET(I_NULL); } /* A_CCM_EVENT */ enum crmd_fsa_input do_ccm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input return_input = I_NULL; const oc_ev_membership_t *oc = ((struct ccm_data *)data)->oc; oc_ed_t event = *((struct ccm_data *)data)->event; FNIN(); cl_log(LOG_INFO,"event=%s", event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP": event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY": event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED": event==OC_EV_MS_EVICTED?"EVICTED": "NO QUORUM MEMBERSHIP"); if(CCM_EVENT_DETAIL) { ccm_event_detail(oc, event); } if (OC_EV_MS_EVICTED == event) { /* get out... NOW! */ return_input = I_SHUTDOWN; } if(return_input == I_SHUTDOWN) { ; /* ignore everything, the new DC will handle it */ } else { /* My understanding is that we will never get both * node leaving *and* node joining callbacks at the * same time. * * This logic would need to change if this is not * the case */ if(oc->m_n_out !=0) { return_input = I_NODE_LEFT; } else if(oc->m_n_in !=0) { /* delay the I_NODE_JOIN until they acknowledge our * DC status and send us their CIB */ return_input = I_NULL; } else { cl_log(LOG_INFO, "So why are we here? What CCM event happened?"); } } FNRET(return_input); } /* A_CCM_UPDATE_CACHE */ /* * Take the opportunity to update the node status in the CIB as well * (but only if we are the DC) */ enum crmd_fsa_input do_ccm_update_cache(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { + enum crmd_fsa_input next_input = I_NULL; int lpc, offset; oc_node_t *members = NULL; oc_ed_t event = *((struct ccm_data *)data)->event; const oc_ev_membership_t *oc = ((struct ccm_data *)data)->oc; oc_node_list_t *tmp = NULL, *membership_copy = (oc_node_list_t *) cl_malloc(sizeof(oc_node_list_t)); xmlNodePtr update_list = create_xml_node(NULL, XML_CIB_TAG_STATE); FNIN(); set_xml_property_copy(update_list, XML_ATTR_ID, fsa_our_uname); cl_log(LOG_INFO,"Updating CCM cache after a \"%s\" event.", event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP": event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY": event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED": event==OC_EV_MS_EVICTED?"EVICTED": "NO QUORUM MEMBERSHIP"); /*--*-- All Member Nodes --*--*/ offset = oc->m_memb_idx; membership_copy->members_size = oc->m_n_member; CRM_DEBUG2("Number of members: %d", membership_copy->members_size); if(membership_copy->members_size > 0) { int size = membership_copy->members_size; size = size * sizeof(oc_node_t); CRM_DEBUG2("Allocing %d", size); membership_copy->members = (oc_node_t *)cl_malloc(size); members = membership_copy->members; for(lpc=0; lpc < membership_copy->members_size; lpc++) { members[lpc].node_id = oc->m_array[offset+lpc].node_id; members[lpc].node_born_on = oc->m_array[offset+lpc].node_born_on; members[lpc].node_uname = cl_strdup(oc->m_array[offset+lpc].node_uname); new_node_state(update_list, members[lpc].node_uname, "in_ccm"); } } else { membership_copy->members = NULL; } /*--*-- New Member Nodes --*--*/ offset = oc->m_in_idx; membership_copy->new_members_size = oc->m_n_in; CRM_DEBUG2("Number of new members: %d", membership_copy->new_members_size); if(membership_copy->new_members_size > 0) { int size = membership_copy->new_members_size; size = size * sizeof(oc_node_t); CRM_DEBUG2("Allocing %d", size); membership_copy->new_members = (oc_node_t *)cl_malloc(size); members = membership_copy->new_members; for(lpc=0; lpc < membership_copy->new_members_size; lpc++) { members[lpc].node_id = oc->m_array[offset+lpc].node_id; members[lpc].node_born_on = oc->m_array[offset+lpc].node_born_on; members[lpc].node_uname = cl_strdup(oc->m_array[offset+lpc].node_uname); new_node_state(update_list, members[lpc].node_uname, "in_ccm"); } } else { membership_copy->new_members = NULL; } /*--*-- Recently Dead Member Nodes --*--*/ offset = oc->m_out_idx; membership_copy->dead_members_size = oc->m_n_out; if(membership_copy->dead_members_size > 0) { int size = membership_copy->dead_members_size; size = size * sizeof(oc_node_t); membership_copy->dead_members = (oc_node_t *)cl_malloc(size); members = membership_copy->dead_members; for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) { members[lpc].node_id = oc->m_array[offset+lpc].node_id; members[lpc].node_born_on = oc->m_array[offset+lpc].node_born_on; members[lpc].node_uname = cl_strdup(oc->m_array[offset+lpc].node_uname); new_node_state(update_list, members[lpc].node_uname, "down"); } } else { membership_copy->dead_members = NULL; } if(AM_I_DC) { // should be sufficient for only the DC to do this - send_cib_status_update(update_list); + xmlNodePtr fragment = create_cib_fragment(update_list, NULL); + + send_request(NULL, fragment, CRM_OPERATION_UPDATE, + NULL, CRM_SYSTEM_DCIB); + + free_xml(fragment); } tmp = fsa_membership_copy; fsa_membership_copy = membership_copy; /* Free the old copy */ if(tmp != NULL) { if(tmp->members != NULL) cl_free(tmp->members); if(tmp->new_members != NULL) cl_free(tmp->new_members); if(tmp->dead_members != NULL) cl_free(tmp->dead_members); cl_free(tmp); } - FNRET(I_NULL); + FNRET(next_input); } /* * node_updates must be pre-constructed (non-NULL) */ void new_node_state(xmlNodePtr node_updates, const char *uname, const char *state) { xmlNodePtr tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); set_node_tstamp(tmp1); set_xml_property_copy(tmp1, XML_ATTR_ID, uname); set_xml_property_copy(tmp1, "source", fsa_our_uname); set_xml_property_copy(tmp1, "state", state); xmlAddSibling(node_updates, tmp1); } void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event) { int member_id = -1; gboolean member = FALSE; 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"); int lpc; int node_list_size = oc->m_n_member; for(lpc=0; lpcm_array[oc->m_memb_idx+lpc].node_uname, oc->m_array[oc->m_memb_idx+lpc].node_id, oc->m_array[oc->m_memb_idx+lpc].node_born_on); if(fsa_our_uname != NULL && strcmp(fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname)) { member = TRUE; member_id = oc->m_array[oc->m_memb_idx+lpc].node_id; } } if (member == FALSE) { cl_log(LOG_WARNING, "MY NODE IS NOT IN CCM THE MEMBERSHIP LIST"); } else { cl_log(LOG_INFO, "MY NODE ID IS %d", member_id); } cl_log(LOG_INFO, "NEW MEMBERS"); if (oc->m_n_in==0) cl_log(LOG_INFO, "\tNONE"); for(lpc=0; lpcm_n_in; lpc++) { cl_log(LOG_INFO,"\t%s [nodeid=%d, born=%d]", oc->m_array[oc->m_in_idx+lpc].node_uname, oc->m_array[oc->m_in_idx+lpc].node_id, oc->m_array[oc->m_in_idx+lpc].node_born_on); } cl_log(LOG_INFO, "MEMBERS LOST"); if (oc->m_n_out==0) cl_log(LOG_INFO, "\tNONE"); for(lpc=0; lpcm_n_out; lpc++) { cl_log(LOG_INFO,"\t%s [nodeid=%d, born=%d]", oc->m_array[oc->m_out_idx+lpc].node_uname, oc->m_array[oc->m_out_idx+lpc].node_id, oc->m_array[oc->m_out_idx+lpc].node_born_on); if(fsa_our_uname != NULL && strcmp(fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname)) { cl_log(LOG_ERR, "We're not part of the cluster anymore"); } } cl_log(LOG_INFO, "-----------------------"); } int register_with_ccm(ll_cluster_t *hb_cluster) { FNRET(0); } gboolean ccm_dispatch(int fd, gpointer user_data) { oc_ev_t *ccm_token = (oc_ev_t*)user_data; oc_ev_handle_event(ccm_token); return TRUE; } void crmd_ccm_input_callback(oc_ed_t event, void *cookie, size_t size, const void *data) { struct ccm_data *event_data = NULL; FNIN(); if(data != NULL) { event_data = (struct ccm_data *) cl_malloc(sizeof(struct ccm_data)); event_data->event = &event; event_data->oc = (const oc_ev_membership_t *)data; s_crmd_fsa(C_CCM_CALLBACK, I_CCM_EVENT, (void*)event_data); event_data->event = NULL; event_data->oc = NULL; cl_free(event_data); } else { cl_log(LOG_INFO, "CCM Callback with NULL data... " "I dont /think/ this is bad"); } oc_ev_callback_done(cookie); FNOUT(); } void msg_ccm_join(const struct ha_msg *msg, void *foo) { FNIN(); cl_log(LOG_INFO, "\n###### Recieved ccm_join message..."); if (msg != NULL) { cl_log(LOG_INFO, "[type=%s]", ha_msg_value(msg, F_TYPE)); cl_log(LOG_INFO, "[orig=%s]", ha_msg_value(msg, F_ORIG)); cl_log(LOG_INFO, "[to=%s]", ha_msg_value(msg, F_TO)); cl_log(LOG_INFO, "[status=%s]", ha_msg_value(msg, F_STATUS)); cl_log(LOG_INFO, "[info=%s]", ha_msg_value(msg, F_COMMENT)); cl_log(LOG_INFO, "[rsc_hold=%s]", ha_msg_value(msg, F_RESOURCES)); cl_log(LOG_INFO, "[stable=%s]", ha_msg_value(msg, F_ISSTABLE)); cl_log(LOG_INFO, "[rtype=%s]", ha_msg_value(msg, F_RTYPE)); cl_log(LOG_INFO, "[ts=%s]", ha_msg_value(msg, F_TIME)); cl_log(LOG_INFO, "[seq=%s]", ha_msg_value(msg, F_SEQ)); cl_log(LOG_INFO, "[generation=%s]", ha_msg_value(msg, F_HBGENERATION)); // cl_log(LOG_INFO, "[=%s]", ha_msg_value(msg, F_)); } FNOUT(); } diff --git a/crm/crmd/crmd_fsa.h b/crm/crmd/crmd_fsa.h index 1653f5e20a..8426785f34 100644 --- a/crm/crmd/crmd_fsa.h +++ b/crm/crmd/crmd_fsa.h @@ -1,129 +1,129 @@ -/* $Id: crmd_fsa.h,v 1.14 2004/04/12 15:34:50 andrew Exp $ */ +/* $Id: crmd_fsa.h,v 1.15 2004/04/15 08:31:13 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_CRM_FSA__H #define XML_CRM_FSA__H #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; oc_node_t *members; int new_members_size; oc_node_t *new_members; int dead_members_size; oc_node_t *dead_members; // struct oc_node_list_s *next; }; /* 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); /* Utilities */ extern long long toggle_bit (long long action_list, long long action); extern long long clear_bit (long long action_list, long long action); extern long long set_bit (long long action_list, long long action); extern void toggle_bit_inplace(long long *action_list, long long action); extern void clear_bit_inplace (long long *action_list, long long action); extern void set_bit_inplace (long long *action_list, long long action); extern gboolean is_set(long long action_list, long long action); extern gboolean startTimer(fsa_timer_t *timer); extern gboolean stopTimer(fsa_timer_t *timer); extern gboolean timer_popped(gpointer data); 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 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 void cleanup_subsystem(struct crm_subsystem_s *the_subsystem); -extern void send_cib_status_update(xmlNodePtr update); +extern enum crmd_fsa_input send_cib_status_update(xmlNodePtr update); #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 #endif diff --git a/crm/crmd/crmd_messages.h b/crm/crmd/crmd_messages.h index 4e2edf02a0..e9b06257a1 100644 --- a/crm/crmd/crmd_messages.h +++ b/crm/crmd/crmd_messages.h @@ -1,82 +1,88 @@ /* * 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_CRM_MESSAGES__H #define XML_CRM_MESSAGES__H #include #include #include #include struct fsa_message_queue_s { gboolean processed; xmlNodePtr message; struct fsa_message_queue_s *next; }; typedef struct fsa_message_queue_s *fsa_message_queue_t; fsa_message_queue_t put_message(xmlNodePtr new_message); fsa_message_queue_t get_message(void); gboolean is_message(void); extern gboolean relay_message(xmlNodePtr xml_relay_message, gboolean originated_locally); 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); extern void process_message(xmlNodePtr root_xml_node, gboolean originated_locally, const char *src_node_name); extern gboolean crm_dc_process_message(xmlNodePtr whole_message, xmlNodePtr action, const char *host_from, const char *sys_from, const char *sys_to, const char *op, gboolean dc_mode); extern void send_msg_via_ha(xmlNodePtr action, const char *dest_node); extern void send_msg_via_ipc(xmlNodePtr action, const char *sys); extern gboolean add_pending_outgoing_reply(const char *originating_node_name, const char *crm_msg_reference, const char *sys_to, const char *sys_from); extern gboolean crmd_authorize_message(xmlNodePtr root_xml_node, IPC_Message *client_msg, crmd_client_t *curr_client); extern gboolean send_request(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation, const char *host_to, const char *sys_to); +extern gboolean store_request(xmlNodePtr msg_options, + xmlNodePtr msg_data, + const char *operation, + const char *host_to, + const char *sys_to); + extern enum crmd_fsa_input handle_message(xmlNodePtr stored_msg); extern void lrm_op_callback (lrm_op_t* op); extern void lrm_monitor_callback (lrm_mon_t* monitor); #endif diff --git a/crm/crmd/election.c b/crm/crmd/election.c index 126145e483..179092e92c 100644 --- a/crm/crmd/election.c +++ b/crm/crmd/election.c @@ -1,568 +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 */ #include #include #include #include #include #include #include #include #include #include #include GHashTable *joined_nodes = NULL; /* 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; FNIN(); /* 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: FNRET(I_NULL); // log warning break; default: if(is_set(fsa_input_register, R_SHUTDOWN)) { FNRET(I_NULL); // log warning } break; } send_request(NULL, NULL, CRM_OPERATION_VOTE, NULL, CRM_SYSTEM_CRMD); FNRET(election_result); } gboolean timer_popped(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; cl_log(LOG_INFO, "#!!#!!# Timer %s just popped!", fsa_input2string(timer->fsa_input)); stopTimer(timer); // dont make it go off again s_crmd_fsa(C_TIMER_POPPED, timer->fsa_input, NULL); return TRUE; } gboolean do_dc_heartbeat(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; // cl_log(LOG_DEBUG, "#!!#!!# Heartbeat timer just popped!"); gboolean was_sent = send_request(NULL, NULL, CRM_OPERATION_HBEAT, NULL, CRM_SYSTEM_CRMD); 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; } /* 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; unsigned int my_born = -1, your_born = -1; int lpc = 0, my_index = -1, your_index = -1; enum crmd_fsa_input election_result = I_NULL; const char *vote_from = xmlGetProp(vote, XML_ATTR_HOSTFROM); const char *lowest_uname = NULL; int lowest_bornon = 0; FNIN(); if(vote_from == NULL || strcmp(vote_from, fsa_our_uname) == 0) { // dont count our own vote FNRET(election_result); } if(fsa_membership_copy->members_size < 1) { // if even we are not in the cluster then we should not vote FNRET(I_FAIL); } lowest_uname = fsa_membership_copy->members[0].node_uname; lowest_bornon = fsa_membership_copy->members[0].node_born_on; for(; lpc < fsa_membership_copy->members_size; lpc++) { const char *node_uname = fsa_membership_copy->members[lpc].node_uname; int this_born_on = fsa_membership_copy->members[lpc].node_born_on; if(node_uname == NULL) { continue; } if(strcmp(vote_from, node_uname) == 0) { your_born = this_born_on; your_index = lpc; } else if (strcmp(fsa_our_uname, node_uname) == 0) { my_born = this_born_on; my_index = lpc; } if(lowest_bornon > this_born_on) { lowest_uname = node_uname; lowest_bornon = this_born_on; } else if(lowest_bornon == this_born_on && strcmp(lowest_uname, node_uname) > 0) { lowest_uname = node_uname; lowest_bornon = this_born_on; } } #if 0 cl_log(LOG_DEBUG, "%s (bornon=%d), our bornon (%d)", vote_from, your_born, my_born); cl_log(LOG_DEBUG, "%s %s %s", fsa_our_uname, strcmp(fsa_our_uname, vote_from) < 0?"<":">=", vote_from); #endif cl_log(LOG_DEBUG, "Election winner should be %s (born_on=%d)", lowest_uname, lowest_bornon); if(lowest_uname != NULL && strcmp(lowest_uname, fsa_our_uname) == 0){ cl_log(LOG_DEBUG, "Election win: lowest born_on and uname"); election_result = I_ELECTION_DC; } else if(your_born < my_born) { cl_log(LOG_DEBUG, "Election fail: born_on"); we_loose = TRUE; } else if(your_born == my_born && strcmp(fsa_our_uname, vote_from) > 0) { cl_log(LOG_DEBUG, "Election fail: uname"); we_loose = TRUE; } else { CRM_DEBUG("We might win... we should vote (possibly again)"); election_result = I_DC_TIMEOUT; } if(we_loose) { if(fsa_input_register & R_THE_DC) { cl_log(LOG_DEBUG, "Give up the DC"); election_result = I_RELEASE_DC; } else { cl_log(LOG_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); } FNRET(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) { FNIN(); if(action & A_ELECT_TIMER_START) { CRM_DEBUG("Starting the election timer..."); startTimer(election_timeout); } else if(action & A_ELECT_TIMER_STOP || action & A_ELECTION_TIMEOUT) { CRM_DEBUG("Stopping the election timer..."); stopTimer(election_timeout); } else { cl_log(LOG_ERR, "unexpected action %s", fsa_action2string(action)); } if(action & A_ELECTION_TIMEOUT) { CRM_DEBUG("The election timer went off, we win!"); FNRET(I_ELECTION_DC); } FNRET(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; FNIN(); 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); } FNRET(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) { FNIN(); CRM_DEBUG("################## Taking over the DC ##################"); set_bit_inplace(&fsa_input_register, R_THE_DC); CRM_DEBUG2("Am I the DC? %s", AM_I_DC?"yes":"no"); 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); FNRET(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; FNIN(); CRM_DEBUG("################## Releasing the DC ##################"); stopTimer(dc_heartbeat); 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 { cl_log(LOG_ERR, "Warning, do_dc_release invoked for action %s", fsa_action2string(action)); } CRM_DEBUG2("Am I still the DC? %s", AM_I_DC?"yes":"no"); FNRET(result); } /* A_JOIN_WELCOME, A_JOIN_WELCOME_ALL */ enum crmd_fsa_input do_send_welcome(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { int lpc = 0, size = 0, num_sent = 0; oc_node_t *members; gboolean was_sent = TRUE; FNIN(); if(action & A_JOIN_WELCOME && data == NULL) { cl_log(LOG_ERR, "Attempt to send welcome message " "without a message to reply to!"); FNRET(I_NULL); } else if(action & A_JOIN_WELCOME) { xmlNodePtr welcome = (xmlNodePtr)data; const char *join_to = xmlGetProp(welcome, XML_ATTR_HOSTFROM); if(join_to != NULL) { send_request(NULL, NULL, CRM_OPERATION_WELCOME, join_to, CRM_SYSTEM_CRMD); } FNRET(I_NULL); } // welcome everyone... /* Give everyone a chance to join before invoking the PolicyEngine */ stopTimer(integration_timer); startTimer(integration_timer); members = fsa_membership_copy->members; size = fsa_membership_copy->members_size; if(joined_nodes != NULL) { g_hash_table_destroy(joined_nodes); joined_nodes = g_hash_table_new(&g_str_hash, &g_str_equal); } for(; members != NULL && lpc < size; lpc++) { const char *new_node = members[lpc].node_uname; if(strcmp(fsa_our_uname, new_node) == 0) { // dont send one to ourselves continue; } CRM_DEBUG3("Sending welcome message to %s (%d)", new_node, was_sent); num_sent++; was_sent = was_sent && send_request(NULL, NULL, CRM_OPERATION_WELCOME, new_node, CRM_SYSTEM_CRMD); CRM_DEBUG3("Sent welcome message to %s (%d)", new_node, was_sent); } if(was_sent == FALSE) FNRET(I_FAIL); /* No point hanging around in S_INTEGRATION if we're the only ones here! */ if(num_sent == 0) { // that was the last outstanding join ack) cl_log(LOG_INFO,"That was the last outstanding join ack"); FNRET(I_SUCCESS); } else { cl_log(LOG_DEBUG, "Still waiting on %d outstanding join acks", num_sent); //dont waste time by invoking the pe yet; } FNRET(I_NULL); } /* 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 current_input, void *data) { xmlNodePtr welcome = (xmlNodePtr)data; FNIN(); #if 0 if(we are sick) { log error ; FNRET(I_NULL); } #endif xmlNodePtr cib_copy = get_cib_copy(); xmlNodePtr tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy); - xmlNodePtr tmp2 = create_cib_fragment(tmp1, XML_CIB_TAG_STATUS); + xmlNodePtr tmp2 = create_cib_fragment(tmp1, NULL); send_ha_reply(fsa_cluster_conn, welcome, tmp2); free_xml(tmp2); free_xml(cib_copy); FNRET(I_NULL); } /* 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) { FNIN(); /* Once we hear from the DC, we can stop the timer * * This timer was started either on startup or when a node * left the CCM list */ /* dont announce if we're in one of these states */ switch(cur_state) { case S_RECOVERY: case S_RECOVERY_DC: case S_RELEASE_DC: case S_TERMINATE: FNRET(I_NULL); // log warning break; default: break; } if(AM_I_OPERATIONAL) { send_request(NULL, NULL, CRM_OPERATION_ANNOUNCE, NULL, CRM_SYSTEM_DC); } else { /* Delay announce until we have finished local startup */ FNRET(I_NULL); } FNRET(I_NULL); } /* 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 current_input, void *data) { int lpc = 0, size = 0; oc_node_t *members; gboolean is_a_member = FALSE; xmlNodePtr join_ack = (xmlNodePtr)data; const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM); FNIN(); FNIN(); members = fsa_membership_copy->members; size = fsa_membership_copy->members_size; for(; lpc < size; lpc++) { const char *new_node = members[lpc].node_uname; if(strcmp(join_from, new_node) == 0) { is_a_member = TRUE; } } xmlNodePtr cib_fragment = find_xml_node(join_ack, XML_TAG_FRAGMENT); if(is_a_member == FALSE) { cl_log(LOG_ERR, "Node %s is not known to us", join_from); /* make sure any information from this node is discarded, * it is invalid */ free_xml(cib_fragment); FNRET(I_FAIL); } + + cl_log(LOG_DEBUG, "Welcoming node %s after ACK", join_from); // add them to our list of "active" nodes g_hash_table_insert(joined_nodes, strdup(join_from),strdup(join_from)); - + if(cib_fragment == NULL) { + cl_log(LOG_ERR, + "No status information was part of the" + " Welcome ACK from %s", + join_from); + FNRET(I_NULL); + } + /* TODO: check the fragment is only for the status section const char *section = get_xml_attr(cib_fragment, NULL, XML_ATTR_FILTER_TYPE, TRUE); */ /* Make changes so that state=active for this node when the update * is processed by A_CIB_INVOKE */ xmlNodePtr tmp1 = find_xml_node(cib_fragment, XML_TAG_CIB); tmp1 = get_object_root(XML_CIB_TAG_STATUS, tmp1); tmp1 = find_entity(tmp1, XML_CIB_TAG_STATE, join_from, FALSE); set_xml_property_copy(tmp1, "state", "active"); if(g_hash_table_size(joined_nodes) == fsa_membership_copy->members_size) { // that was the last outstanding join ack) cl_log(LOG_INFO,"That was the last outstanding join ack"); FNRET(I_SUCCESS); } else { cl_log(LOG_DEBUG, "Still waiting on %d outstanding join acks", size); //dont waste time by invoking the pe yet; } - FNRET(I_NULL); + FNRET(I_CIB_OP); } diff --git a/crm/crmd/fsa.c b/crm/crmd/fsa.c index 7c46f6038c..db7e18198d 100644 --- a/crm/crmd/fsa.c +++ b/crm/crmd/fsa.c @@ -1,1062 +1,1055 @@ /* * 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 long long do_state_transition(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, enum crmd_fsa_input current_input, void *data); #ifdef DOT_FSA_ACTIONS # ifdef FSA_TRACE # define ELSEIF_FSA_ACTION(x,y) \ else if(is_set(actions,x)) { \ CRM_DEBUG3("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data==NULL?"no":"yes", \ fsa_input2string(next_input)); \ fflush(dot_strm); \ CRM_DEBUG3("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else # define ELSEIF_FSA_ACTION(x,y) \ else if(is_set(actions,x)) { \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %s)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data==NULL?"no":"yes", \ fsa_input2string(next_input)); \ fflush(dot_strm); \ } # endif #else # ifdef FSA_TRACE # define ELSEIF_FSA_ACTION(x,y) \ else if(is_set(actions,x)) { \ CRM_DEBUG3("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ CRM_DEBUG3("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else # define ELSEIF_FSA_ACTION(x,y) \ else if(is_set(actions,x)) { \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ } # endif #endif 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; const char *fsa_our_uname; fsa_timer_t *election_trigger = NULL; /* */ fsa_timer_t *election_timeout = NULL; /* */ fsa_timer_t *shutdown_escalation_timmer = NULL; /* */ fsa_timer_t *integration_timer = NULL; fsa_timer_t *dc_heartbeat = NULL; long long toggle_bit(long long action_list, long long action) { // CRM_DEBUG2("Toggling bit %.16llx", action); action_list ^= action; // CRM_DEBUG2("Result %.16llx", action_list & action); return action_list; } long long clear_bit(long long action_list, long long action) { // CRM_DEBUG2("Clearing bit\t%.16llx", action); // ensure its set action_list |= action; // then toggle action_list = action_list ^ action; return action_list; } long long set_bit(long long action_list, long long action) { // CRM_DEBUG2("Adding bit\t%.16llx", action); action_list |= action; return action_list; } void toggle_bit_inplace(long long *action_list, long long action) { *action_list = toggle_bit(*action_list, action); } void clear_bit_inplace(long long *action_list, long long action) { *action_list = clear_bit(*action_list, action); } void set_bit_inplace(long long *action_list, long long action) { *action_list = set_bit(*action_list, action); } gboolean is_set(long long action_list, long long action) { // CRM_DEBUG2("Checking bit\t%.16llx", action); return ((action_list & action) == action); } gboolean startTimer(fsa_timer_t *timer) { if(((int)timer->source_id) < 0) { timer->source_id = Gmain_timeout_add(timer->period_ms, timer->callback, (void*)timer); /* CRM_DEBUG3("#!!#!!# Started %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); */ } else { cl_log(LOG_INFO, "#!!#!!# Timer %s already running (%d)", fsa_input2string(timer->fsa_input), timer->source_id); return FALSE; } return TRUE; } gboolean stopTimer(fsa_timer_t *timer) { if(((int)timer->source_id) > 0) { /* CRM_DEBUG3("#!!#!!# Stopping %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); */ g_source_remove(timer->source_id); timer->source_id = -2; } else { cl_log(LOG_INFO, "#!!#!!# Timer %s already stopped (%d)", fsa_input2string(timer->fsa_input), timer->source_id); return FALSE; } return TRUE; } enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause, enum crmd_fsa_input initial_input, void *data) { long long actions = A_NOTHING, new_actions = A_NOTHING; enum crmd_fsa_input last_input = initial_input; enum crmd_fsa_input cur_input; enum crmd_fsa_input next_input; enum crmd_fsa_state last_state, cur_state, next_state, starting_state; FNIN(); starting_state = fsa_state; cur_input = initial_input; next_input = initial_input; last_state = starting_state; cur_state = starting_state; next_state = starting_state; #ifdef FSA_TRACE CRM_DEBUG4("FSA invoked with Cause: %s\n\tState: %s, Input: %s", fsa_cause2string(cause), fsa_state2string(cur_state), fsa_input2string(cur_input)); #endif if(dot_strm == NULL) { dot_strm = fopen("/tmp/live.dot", "w"); fprintf(dot_strm, "%s", dot_intro); } /* * Process actions in order of priority but do only one * action at a time to avoid complicating the ordering. * * Actions may result in a new I_ event, these are added to * (not replace) existing actions before the next iteration. * */ while(next_input != I_NULL || actions != A_NOTHING) { if(next_input == I_WAIT_FOR_EVENT) { /* we may be waiting for an a-sync task to "happen" * and until it does, we cant do anything else */ cl_log(LOG_INFO, "Wait until something else happens"); break; } cur_input = next_input; #ifdef FSA_TRACE CRM_DEBUG3("FSA while loop:\tState: %s, Input: %s", fsa_state2string(cur_state), fsa_input2string(cur_input)); #endif new_actions = crmd_fsa_actions[cur_input][cur_state]; next_state = crmd_fsa_state[cur_input][cur_state]; last_state = cur_state; cur_state = next_state; fsa_state = next_state; if(new_actions != A_NOTHING) { #ifdef FSA_TRACE CRM_DEBUG2("Adding actions %.16llx", new_actions); #endif actions |= new_actions; } switch(cur_input) { case I_NULL: break; #if 0 case I_SOME_EVENT: case I_SOME_OTHER_EVENT: cc_transitioner(cur_input, data); /* flow through... */ #endif default: last_input = cur_input; break; } /* * Hook for change of state. * Allows actions to be added or removed when entering a state */ if(last_state != cur_state){ actions = do_state_transition(actions, cause, last_state, cur_state, last_input, data); } /* this is always run, some inputs/states may make various * actions irrelevant/invalid */ actions = clear_flags(actions, cause, cur_state, cur_input); /* regular action processing in order of action priority * * Make sure all actions that connect to required systems * are performed first */ if(actions == A_NOTHING) { cl_log(LOG_INFO, "Nothing to do"); next_input = I_NULL; /* // check registers, see if anything is pending if(is_set(fsa_input_register, R_SHUTDOWN)) { CRM_DEBUG("(Re-)invoking shutdown"); next_input = I_SHUTDOWN; } else if(is_set(fsa_input_register, R_INVOKE_PE)) { CRM_DEBUG("Invoke the PE somehow"); } */ } /* logging */ ELSEIF_FSA_ACTION(A_ERROR, do_log) ELSEIF_FSA_ACTION(A_WARN, do_log) ELSEIF_FSA_ACTION(A_LOG, do_log) /* get out of here NOW! before anything worse happens */ ELSEIF_FSA_ACTION(A_EXIT_1, do_exit) ELSEIF_FSA_ACTION(A_STARTUP, do_startup) ELSEIF_FSA_ACTION(A_CIB_START, do_cib_control) ELSEIF_FSA_ACTION(A_HA_CONNECT, do_ha_control) ELSEIF_FSA_ACTION(A_LRM_CONNECT,do_lrm_control) ELSEIF_FSA_ACTION(A_CCM_CONNECT,do_ccm_control) ELSEIF_FSA_ACTION(A_ANNOUNCE, do_announce) /* sub-system start */ ELSEIF_FSA_ACTION(A_PE_START, do_pe_control) ELSEIF_FSA_ACTION(A_TE_START, do_te_control) /* sub-system restart */ ELSEIF_FSA_ACTION(O_CIB_RESTART,do_cib_control) ELSEIF_FSA_ACTION(O_PE_RESTART, do_pe_control) ELSEIF_FSA_ACTION(O_TE_RESTART, do_te_control) ELSEIF_FSA_ACTION(A_STARTED, do_started) /* DC Timer */ ELSEIF_FSA_ACTION(O_DC_TIMER_RESTART, do_dc_timer_control) ELSEIF_FSA_ACTION(A_DC_TIMER_STOP, do_dc_timer_control) ELSEIF_FSA_ACTION(A_DC_TIMER_START, do_dc_timer_control) /* * Highest priority actions */ ELSEIF_FSA_ACTION(A_SHUTDOWN_REQ, do_shutdown_req) ELSEIF_FSA_ACTION(A_MSG_ROUTE, do_msg_route) ELSEIF_FSA_ACTION(A_RECOVER, do_recover) ELSEIF_FSA_ACTION(A_ELECTION_VOTE, do_election_vote) ELSEIF_FSA_ACTION(A_ELECT_TIMER_START, do_election_timer_ctrl) ELSEIF_FSA_ACTION(A_ELECT_TIMER_STOP, do_election_timer_ctrl) ELSEIF_FSA_ACTION(A_ELECTION_COUNT, do_election_count_vote) ELSEIF_FSA_ACTION(A_ELECTION_TIMEOUT, do_election_timer_ctrl) /* * "Get this over with" actions */ ELSEIF_FSA_ACTION(A_MSG_STORE, do_msg_store) ELSEIF_FSA_ACTION(A_NODE_BLOCK, do_node_block) /* * High priority actions * Update the cache first */ ELSEIF_FSA_ACTION(A_CCM_UPDATE_CACHE, do_ccm_update_cache) ELSEIF_FSA_ACTION(A_CCM_EVENT, do_ccm_event) /* * Medium priority actions */ ELSEIF_FSA_ACTION(A_DC_TAKEOVER, do_dc_takeover) ELSEIF_FSA_ACTION(A_DC_RELEASE, do_dc_release) ELSEIF_FSA_ACTION(A_JOIN_WELCOME_ALL, do_send_welcome) ELSEIF_FSA_ACTION(A_JOIN_WELCOME, do_send_welcome) ELSEIF_FSA_ACTION(A_JOIN_ACK, do_ack_welcome) ELSEIF_FSA_ACTION(A_JOIN_PROCESS_ACK, do_process_welcome_ack) /* * Low(er) priority actions * Make sure the CIB is always updated before invoking the * PE, and the PE before the TE */ - ELSEIF_FSA_ACTION(A_UPDATE_NODESTATUS, do_cib_invoke) + ELSEIF_FSA_ACTION(A_UPDATE_NODESTATUS, do_lrm_invoke) ELSEIF_FSA_ACTION(A_CIB_INVOKE_LOCAL, do_cib_invoke) ELSEIF_FSA_ACTION(A_CIB_INVOKE, do_cib_invoke) ELSEIF_FSA_ACTION(A_CIB_BUMPGEN, do_cib_invoke) ELSEIF_FSA_ACTION(A_LRM_INVOKE, do_lrm_invoke) ELSEIF_FSA_ACTION(A_LRM_EVENT, do_lrm_event) ELSEIF_FSA_ACTION(A_PE_INVOKE, do_pe_invoke) ELSEIF_FSA_ACTION(A_TE_INVOKE, do_te_invoke) /* sub-system stop */ ELSEIF_FSA_ACTION(A_PE_STOP, do_pe_control) ELSEIF_FSA_ACTION(A_TE_STOP, do_te_control) ELSEIF_FSA_ACTION(A_DC_RELEASED, do_dc_release) ELSEIF_FSA_ACTION(A_HA_DISCONNECT, do_ha_control) ELSEIF_FSA_ACTION(A_CCM_DISCONNECT, do_ccm_control) ELSEIF_FSA_ACTION(A_LRM_DISCONNECT, do_lrm_control) ELSEIF_FSA_ACTION(A_CIB_STOP, do_cib_control) /* time to go now... */ /* Some of these can probably be consolidated */ ELSEIF_FSA_ACTION(A_SHUTDOWN, do_shutdown) ELSEIF_FSA_ACTION(A_STOP, do_stop) /* exit gracefully */ ELSEIF_FSA_ACTION(A_EXIT_0, do_exit) // ELSEIF_FSA_ACTION(A_, do_) - else if(actions & A_MSG_PROCESS) { + else if(is_message()) { xmlNodePtr stored_msg = NULL; - /* any more queued messages? */ - if(is_message() == FALSE) { - CRM_DEBUG("No more messages"); - actions = clear_bit(actions, A_MSG_PROCESS); + fsa_message_queue_t msg = get_message(); + + if(msg == NULL || msg->message == NULL) { + cl_log(LOG_ERR, + "Invalid stored message"); continue; - } else { - fsa_message_queue_t msg = get_message(); - - if(msg == NULL || msg->message == NULL) { - cl_log(LOG_ERR, - "Invalid stored message"); - continue; - } - - data = msg->message; } + + data = msg->message; #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t// %s:\t%s\t(data? %s)", fsa_input2string(cur_input), fsa_action2string(A_MSG_PROCESS), stored_msg==NULL?"no":"yes"); fflush(dot_strm); #endif #ifdef FSA_TRACE CRM_DEBUG3("Invoking action %s (%.16llx)", fsa_action2string(A_MSG_PROCESS), A_MSG_PROCESS); #endif stored_msg = (xmlNodePtr)data; #ifdef FSA_TRACE xml_message_debug(stored_msg,"FSA processing message"); #endif next_input = handle_message(stored_msg); #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t(result=%s)\n", fsa_input2string(next_input)); #endif CRM_DEBUG3("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)) { cl_log(LOG_WARNING, "No action specified for input,state (%s,%s)", fsa_input2string(cur_input), fsa_state2string(cur_state)); next_input = I_NULL; } else if(cur_input == I_NULL && is_set(actions, A_NOTHING)) { #ifdef FSA_TRACE cl_log(LOG_INFO, "Nothing left to do"); #endif } else { cl_log(LOG_ERR, "Action %s (0x%llx) not supported ", fsa_action2string(actions), actions); next_input = I_ERROR; } } #ifdef FSA_TRACE CRM_DEBUG2("################# Exiting the FSA (%s) ##################", fsa_state2string(fsa_state)); #endif // cleanup inputs? FNRET(fsa_state); } /* A_NODE_BLOCK */ enum crmd_fsa_input do_node_block(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr xml_message = (xmlNodePtr)data; const char *host_from = xmlGetProp(xml_message, XML_ATTR_HOSTFROM); FNIN(); (void)host_from; FNRET(I_NULL); } const char * fsa_input2string(int input) { const char *inputAsText = NULL; switch(input){ case I_NULL: inputAsText = "I_NULL"; break; case I_CCM_EVENT: inputAsText = "I_CCM_EVENT"; break; case I_CIB_OP: inputAsText = "I_CIB_OP"; break; case I_CIB_UPDATE: inputAsText = "I_CIB_UPDATE"; break; case I_DC_TIMEOUT: inputAsText = "I_DC_TIMEOUT"; break; case I_ELECTION: inputAsText = "I_ELECTION"; break; case I_RELEASE_DC: inputAsText = "I_RELEASE_DC"; break; case I_ELECTION_DC: inputAsText = "I_ELECTION_DC"; break; case I_ERROR: inputAsText = "I_ERROR"; break; case I_FAIL: inputAsText = "I_FAIL"; break; case I_INTEGRATION_TIMEOUT: inputAsText = "I_INTEGRATION_TIMEOUT"; break; case I_NODE_JOIN: inputAsText = "I_NODE_JOIN"; break; case I_NODE_LEFT: inputAsText = "I_NODE_LEFT"; break; case I_NODE_LEAVING: inputAsText = "I_NODE_LEAVING"; break; case I_NOT_DC: inputAsText = "I_NOT_DC"; break; case I_RECOVERED: inputAsText = "I_RECOVERED"; break; case I_RELEASE_FAIL: inputAsText = "I_RELEASE_FAIL"; break; case I_RELEASE_SUCCESS: inputAsText = "I_RELEASE_SUCCESS"; break; case I_RESTART: inputAsText = "I_RESTART"; break; case I_REQUEST: inputAsText = "I_REQUEST"; break; case I_ROUTER: inputAsText = "I_ROUTER"; break; case I_SHUTDOWN: inputAsText = "I_SHUTDOWN"; break; /* case I_SHUTDOWN_REQ: */ /* inputAsText = "I_SHUTDOWN_REQ"; */ /* break; */ case I_STARTUP: inputAsText = "I_STARTUP"; break; case I_SUCCESS: inputAsText = "I_SUCCESS"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; break; case I_WELCOME: inputAsText = "I_WELCOME"; break; case I_WELCOME_ACK: inputAsText = "I_WELCOME_ACK"; break; case I_DC_HEARTBEAT: inputAsText = "I_DC_HEARTBEAT"; break; case I_ILLEGAL: inputAsText = "I_ILLEGAL"; break; } if(inputAsText == NULL) { cl_log(LOG_ERR, "Input %d is unknown", input); inputAsText = ""; } return inputAsText; } const char * fsa_state2string(int state) { const char *stateAsText = NULL; switch(state){ case S_IDLE: stateAsText = "S_IDLE"; break; case S_ELECTION: stateAsText = "S_ELECTION"; break; case S_INTEGRATION: stateAsText = "S_INTEGRATION"; break; case S_NOT_DC: stateAsText = "S_NOT_DC"; break; case S_POLICY_ENGINE: stateAsText = "S_POLICY_ENGINE"; break; case S_RECOVERY: stateAsText = "S_RECOVERY"; break; case S_RECOVERY_DC: stateAsText = "S_RECOVERY_DC"; break; case S_RELEASE_DC: stateAsText = "S_RELEASE_DC"; break; case S_PENDING: stateAsText = "S_PENDING"; break; case S_STOPPING: stateAsText = "S_STOPPING"; break; case S_TERMINATE: stateAsText = "S_TERMINATE"; break; case S_TRANSITION_ENGINE: stateAsText = "S_TRANSITION_ENGINE"; break; case S_ILLEGAL: stateAsText = "S_ILLEGAL"; break; } if(stateAsText == NULL) { cl_log(LOG_ERR, "State %d is unknown", state); stateAsText = ""; } return stateAsText; } const char * fsa_cause2string(int cause) { const char *causeAsText = NULL; switch(cause){ case C_UNKNOWN: causeAsText = "C_UNKNOWN"; break; case C_STARTUP: causeAsText = "C_STARTUP"; break; case C_IPC_MESSAGE: causeAsText = "C_IPC_MESSAGE"; break; case C_HA_MESSAGE: causeAsText = "C_HA_MESSAGE"; break; case C_CCM_CALLBACK: causeAsText = "C_CCM_CALLBACK"; break; case C_TIMER_POPPED: causeAsText = "C_TIMER_POPPED"; break; case C_SHUTDOWN: causeAsText = "C_SHUTDOWN"; break; case C_HEARTBEAT_FAILED: causeAsText = "C_HEARTBEAT_FAILED"; break; case C_ILLEGAL: causeAsText = "C_ILLEGAL"; break; } if(causeAsText == NULL) { cl_log(LOG_ERR, "Cause %d is unknown", cause); causeAsText = ""; } return causeAsText; } const char * fsa_action2string(long long action) { const char *actionAsText = NULL; switch(action){ case A_NOTHING: actionAsText = "A_NOTHING"; break; case O_SHUTDOWN: actionAsText = "O_SHUTDOWN"; break; case O_RELEASE: actionAsText = "O_RELEASE"; break; case A_STARTUP: actionAsText = "A_STARTUP"; break; case A_STARTED: actionAsText = "A_STARTED"; break; case A_HA_CONNECT: actionAsText = "A_HA_CONNECT"; break; case A_HA_DISCONNECT: actionAsText = "A_HA_DISCONNECT"; break; case A_LRM_CONNECT: actionAsText = "A_LRM_CONNECT"; break; case A_LRM_DISCONNECT: actionAsText = "A_LRM_DISCONNECT"; break; case O_DC_TIMER_RESTART: actionAsText = "O_DC_TIMER_RESTART"; break; case A_DC_TIMER_STOP: actionAsText = "A_DC_TIMER_STOP"; break; case A_DC_TIMER_START: actionAsText = "A_DC_TIMER_START"; break; case A_ELECTION_COUNT: actionAsText = "A_ELECTION_COUNT"; break; case A_ELECTION_TIMEOUT: actionAsText = "A_ELECTION_TIMEOUT"; break; case A_ELECT_TIMER_START: actionAsText = "A_ELECT_TIMER_START"; break; case A_ELECT_TIMER_STOP: actionAsText = "A_ELECT_TIMER_STOP"; break; case A_ELECTION_VOTE: actionAsText = "A_ELECTION_VOTE"; break; case A_ANNOUNCE: actionAsText = "A_ANNOUNCE"; break; case A_JOIN_ACK: actionAsText = "A_JOIN_ACK"; break; case A_JOIN_WELCOME: actionAsText = "A_JOIN_WELCOME"; break; case A_JOIN_WELCOME_ALL: actionAsText = "A_JOIN_WELCOME_ALL"; break; case A_JOIN_PROCESS_ACK: actionAsText = "A_JOIN_PROCESS_ACK"; break; case A_MSG_PROCESS: actionAsText = "A_MSG_PROCESS"; break; case A_MSG_ROUTE: actionAsText = "A_MSG_ROUTE"; break; case A_MSG_STORE: actionAsText = "A_MSG_STORE"; break; case A_RECOVER: actionAsText = "A_RECOVER"; break; case A_DC_RELEASE: actionAsText = "A_DC_RELEASE"; break; case A_DC_RELEASED: actionAsText = "A_DC_RELEASED"; break; case A_DC_TAKEOVER: actionAsText = "A_DC_TAKEOVER"; break; case A_SHUTDOWN: actionAsText = "A_SHUTDOWN"; break; case A_SHUTDOWN_REQ: actionAsText = "A_SHUTDOWN_REQ"; break; case A_STOP: actionAsText = "A_STOP "; break; case A_EXIT_0: actionAsText = "A_EXIT_0"; break; case A_EXIT_1: actionAsText = "A_EXIT_1"; break; case A_CCM_CONNECT: actionAsText = "A_CCM_CONNECT"; break; case A_CCM_DISCONNECT: actionAsText = "A_CCM_DISCONNECT"; break; case A_CCM_EVENT: actionAsText = "A_CCM_EVENT"; break; case A_CCM_UPDATE_CACHE: actionAsText = "A_CCM_UPDATE_CACHE"; break; case A_CIB_BUMPGEN: actionAsText = "A_CIB_BUMPGEN"; break; case A_CIB_INVOKE: actionAsText = "A_CIB_INVOKE"; break; case O_CIB_RESTART: actionAsText = "O_CIB_RESTART"; break; case A_CIB_START: actionAsText = "A_CIB_START"; break; case A_CIB_STOP: actionAsText = "A_CIB_STOP"; break; case A_TE_INVOKE: actionAsText = "A_TE_INVOKE"; break; case O_TE_RESTART: actionAsText = "O_TE_RESTART"; break; case A_TE_START: actionAsText = "A_TE_START"; break; case A_TE_STOP: actionAsText = "A_TE_STOP"; break; case A_PE_INVOKE: actionAsText = "A_PE_INVOKE"; break; case O_PE_RESTART: actionAsText = "O_PE_RESTART"; break; case A_PE_START: actionAsText = "A_PE_START"; break; case A_PE_STOP: actionAsText = "A_PE_STOP"; break; case A_NODE_BLOCK: actionAsText = "A_NODE_BLOCK"; break; case A_UPDATE_NODESTATUS: actionAsText = "A_UPDATE_NODESTATUS"; break; case A_LOG: actionAsText = "A_LOG "; break; case A_ERROR: actionAsText = "A_ERROR "; break; case A_WARN: actionAsText = "A_WARN "; break; } if(actionAsText == NULL) { cl_log(LOG_ERR, "Action %.16llx is unknown", action); actionAsText = ""; } return actionAsText; } long long do_state_transition(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, enum crmd_fsa_input current_input, void *data) { long long tmp = A_NOTHING; if(current_input != I_NULL && (current_input != I_DC_HEARTBEAT || cur_state != S_NOT_DC)){ const char *state_from = fsa_state2string(cur_state); const char *state_to = fsa_state2string(next_state); const char *input = fsa_input2string(current_input); time_t now = time(NULL); fprintf(dot_strm, "\t\"%s\" -> \"%s\" [ label =\"%s\" ] // %s", state_from, state_to, input, asctime(localtime(&now))); fflush(dot_strm); } switch(next_state) { case S_PENDING: case S_NOT_DC: if(is_set(fsa_input_register, R_SHUTDOWN)){ tmp = set_bit(actions, A_SHUTDOWN_REQ); } tmp = clear_bit(actions, A_RECOVER); break; case S_RECOVERY_DC: case S_RECOVERY: tmp = set_bit(actions, A_RECOVER); break; default: tmp = clear_bit(actions, A_RECOVER); break; } if(tmp != actions) { cl_log(LOG_INFO, "Action b4 %.16llx ", actions); cl_log(LOG_INFO, "Action after %.16llx ", tmp); actions = tmp; } return actions; } long long clear_flags(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input) { if(is_set(fsa_input_register, R_SHUTDOWN)){ clear_bit_inplace(&actions, A_DC_TIMER_START); } switch(cur_state) { case S_IDLE: break; case S_ELECTION: break; case S_INTEGRATION: break; case S_NOT_DC: break; case S_POLICY_ENGINE: break; case S_RECOVERY: break; case S_RECOVERY_DC: break; case S_RELEASE_DC: break; case S_PENDING: break; case S_STOPPING: break; case S_TERMINATE: break; case S_TRANSITION_ENGINE: break; case S_ILLEGAL: break; } return actions; } diff --git a/crm/crmd/fsa_matrix.h b/crm/crmd/fsa_matrix.h index da41a18dfc..bf15da0482 100644 --- a/crm/crmd/fsa_matrix.h +++ b/crm/crmd/fsa_matrix.h @@ -1,1000 +1,1000 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef XML_FSA_MATRIX__H #define XML_FSA_MATRIX__H /* * The state transition table. The rows are inputs, and * the columns are states. */ const enum crmd_fsa_state crmd_fsa_state [MAXINPUT][MAXSTATE] = { /* Got an I_NULL */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_CCM_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_CIB_OP */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_CIB_UPDATE */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_RECOVERY, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_ELECTION, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RECOVERY, /* S_PENDING ==> */ S_ELECTION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_ELECTION */ { /* S_IDLE ==> */ S_ELECTION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_ELECTION, /* S_NOT_DC ==> */ S_ELECTION, /* S_POLICY_ENGINE ==> */ S_ELECTION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_ELECTION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_ELECTION, }, /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_ELECTION_DC */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_INTEGRATION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_INTEGRATION, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY_DC, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_INTEGRATION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, }, /* Got an I_ERROR */ { /* S_IDLE ==> */ S_RECOVERY_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_RECOVERY_DC, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RELEASE_DC, /* S_RELEASE_DC ==> */ S_STOPPING, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_TERMINATE, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY_DC, }, /* Got an I_FAIL */ { /* S_IDLE ==> */ S_RECOVERY_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_INTEGRATION_TIMEOUT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_POLICY_ENGINE, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_NODE_JOIN */ { /* S_IDLE ==> */ S_INTEGRATION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_INTEGRATION, }, /* Got an I_NODE_LEFT */ { /* S_IDLE ==> */ S_POLICY_ENGINE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_NODE_LEAVING */ { /* S_IDLE ==> */ S_POLICY_ENGINE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_NOT_DC */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_PENDING, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_RECOVERED */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_PENDING, /* S_RECOVERY_DC ==> */ S_INTEGRATION, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_RELEASE_FAIL */ { /* S_IDLE ==> */ S_STOPPING, /* S_ELECTION ==> */ S_STOPPING, /* S_INTEGRATION ==> */ S_STOPPING, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_STOPPING, /* S_RECOVERY ==> */ S_STOPPING, /* S_RECOVERY_DC ==> */ S_STOPPING, /* S_RELEASE_DC ==> */ S_STOPPING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_STOPPING, }, /* Got an I_RELEASE_SUCCESS */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_PENDING, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_RESTART */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_REQUEST */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_ROUTER */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_SHUTDOWN */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RELEASE_DC, /* S_RECOVERY ==> */ S_PENDING, /* S_RECOVERY_DC ==> */ S_PENDING, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_TERMINATE */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, /* S_NOT_DC ==> */ S_STOPPING, /* S_POLICY_ENGINE ==> */ S_RELEASE_DC, /* S_RECOVERY ==> */ S_STOPPING, /* S_RECOVERY_DC ==> */ S_STOPPING, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_STOPPING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_STARTUP */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_SUCCESS */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_POLICY_ENGINE, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_TRANSITION_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_TERMINATE, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_IDLE, }, /* Got an I_WELCOME */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_RELEASE_DC, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RELEASE_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_NOT_DC, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, /* Got an I_WELCOME_ACK */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_WAIT_FOR_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, /* Got an I_DC_HEARTBEAT */ { /* S_IDLE ==> */ S_ELECTION, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_ELECTION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_ELECTION, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_ELECTION, }, /* Got an I_LRM_EVENT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_NOT_DC, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_TRANSITION_ENGINE, }, }; /* * The action table. Each entry is a set of actions to take or-ed * together. Like the state table, the rows are inputs, and * the columns are states. */ const long long crmd_fsa_actions [MAXINPUT][MAXSTATE] = { /* Got an I_NULL */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_NOTHING, /* S_INTEGRATION ==> */ A_NOTHING, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_RECOVER, /* S_RECOVERY_DC ==> */ A_RECOVER, /* S_RELEASE_DC ==> */ A_NOTHING, /* S_PENDING ==> */ A_NOTHING, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_NOTHING, }, /* Got an I_CCM_EVENT */ { /* S_IDLE ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_ELECTION ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_INTEGRATION ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_NOT_DC ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_POLICY_ENGINE ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_RECOVERY ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_RECOVERY_DC ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_RELEASE_DC ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_PENDING ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_CCM_EVENT|A_CCM_UPDATE_CACHE, }, /* Got an I_CIB_OP */ { /* S_IDLE ==> */ A_CIB_INVOKE, /* S_ELECTION ==> */ A_CIB_INVOKE, /* S_INTEGRATION ==> */ A_CIB_INVOKE, /* S_NOT_DC ==> */ A_CIB_INVOKE, /* S_POLICY_ENGINE ==> */ A_CIB_INVOKE, /* S_RECOVERY ==> */ A_CIB_INVOKE, /* S_RECOVERY_DC ==> */ A_CIB_INVOKE, /* S_RELEASE_DC ==> */ A_CIB_INVOKE, /* S_PENDING ==> */ A_CIB_INVOKE, /* S_STOPPING ==> */ A_CIB_INVOKE, /* S_TERMINATE ==> */ A_CIB_INVOKE, /* S_TRANSITION_ENGINE ==> */ A_CIB_INVOKE, }, /* Got an I_CIB_UPDATE */ { /* S_IDLE ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_CIB_BUMPGEN|A_PE_INVOKE, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_ELECTION ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_INTEGRATION ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_NOT_DC ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_POLICY_ENGINE ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_RECOVERY ==> */ A_NOTHING, /* S_RECOVERY_DC ==> */ A_NOTHING, /* S_RELEASE_DC ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_PENDING ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, }, /* Got an I_ELECTION */ { /* S_IDLE ==> */ A_ELECTION_COUNT, /* S_ELECTION ==> */ A_ELECTION_COUNT, /* S_INTEGRATION ==> */ A_ELECTION_COUNT, /* S_NOT_DC ==> */ A_ELECTION_COUNT, /* S_POLICY_ENGINE ==> */ A_ELECTION_COUNT, /* S_RECOVERY ==> */ A_LOG, /* S_RECOVERY_DC ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_ELECTION_COUNT, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_ELECTION_COUNT, }, /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ O_RELEASE|A_ERROR, /* S_ELECTION ==> */ O_RELEASE, /* S_INTEGRATION ==> */ O_RELEASE|A_ERROR, /* S_NOT_DC ==> */ A_ERROR, /* S_POLICY_ENGINE ==> */ O_RELEASE|A_ERROR, /* S_RECOVERY ==> */ O_RELEASE, /* S_RECOVERY_DC ==> */ O_RELEASE|A_ERROR, /* S_RELEASE_DC ==> */ O_RELEASE|A_ERROR, /* S_PENDING ==> */ A_ERROR, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_ERROR, }, /* Got an I_ELECTION_DC */ { /* S_IDLE ==> */ A_WARN|A_ELECTION_VOTE, /* S_ELECTION ==> */ A_LOG|A_DC_TAKEOVER|A_PE_START|A_TE_START|A_JOIN_WELCOME_ALL|A_DC_TIMER_STOP|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, /* S_INTEGRATION ==> */ A_WARN|A_ELECTION_VOTE, /* S_NOT_DC ==> */ A_LOG|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, /* S_POLICY_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, /* S_RECOVERY ==> */ A_WARN|A_ELECTION_VOTE, /* S_RECOVERY_DC ==> */ A_LOG|A_ELECTION_VOTE, /* S_RELEASE_DC ==> */ A_WARN|A_ELECTION_VOTE, /* S_PENDING ==> */ A_LOG|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, }, /* Got an I_ERROR */ { /* S_IDLE ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_ELECTION ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_INTEGRATION ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|A_RECOVER, /* S_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|O_PE_RESTART|A_RECOVER, /* S_RECOVERY ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_RECOVERY_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_PENDING ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_STOPPING ==> */ A_DC_TIMER_STOP|A_EXIT_1, /* S_TERMINATE ==> */ A_DC_TIMER_STOP|A_EXIT_1, /* S_TRANSITION_ENGINE ==> */ A_DC_TIMER_STOP|O_TE_RESTART|A_RECOVER, }, /* Got an I_FAIL */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_DC_TIMER_STOP|A_WARN, /* S_INTEGRATION ==> */ A_WARN|A_JOIN_WELCOME_ALL, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN|A_JOIN_WELCOME_ALL|A_PE_INVOKE, /* S_RECOVERY ==> */ A_WARN|O_SHUTDOWN, /* S_RECOVERY_DC ==> */ A_WARN|O_SHUTDOWN|O_RELEASE, /* S_RELEASE_DC ==> */ A_WARN|O_SHUTDOWN, /* S_PENDING ==> */ A_DC_TIMER_STOP|A_WARN|O_SHUTDOWN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN|A_EXIT_1, /* S_TRANSITION_ENGINE ==> */ A_WARN|O_TE_RESTART|A_RECOVER, }, /* Got an I_INTEGRATION_TIMEOUT */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_PE_INVOKE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_NOTHING, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_NOTHING, }, /* Got an I_NODE_JOIN */ { /* S_IDLE ==> */ A_JOIN_WELCOME|A_PE_INVOKE, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_JOIN_WELCOME|A_PE_INVOKE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_JOIN_WELCOME|A_PE_INVOKE, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_JOIN_WELCOME|A_PE_INVOKE, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_JOIN_WELCOME|A_PE_INVOKE, }, /* Got an I_NODE_LEFT */ { /* S_IDLE ==> */ A_PE_INVOKE, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_PE_INVOKE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_PE_INVOKE, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_PE_INVOKE, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_PE_INVOKE, }, /* Got an I_NODE_LEAVING */ { /* S_IDLE ==> */ A_NODE_BLOCK|A_PE_INVOKE, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_NODE_BLOCK|A_PE_INVOKE, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_NODE_BLOCK|A_PE_INVOKE, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_NODE_BLOCK|A_PE_INVOKE, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_NODE_BLOCK|A_PE_INVOKE, }, /* Got an I_NOT_DC */ { /* S_IDLE ==> */ O_RELEASE|A_DC_TIMER_START, /* S_ELECTION ==> */ A_LOG|A_DC_TIMER_START, /* S_INTEGRATION ==> */ O_RELEASE|A_DC_TIMER_START, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ O_RELEASE|A_DC_TIMER_START, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ O_RELEASE|A_DC_TIMER_START, /* S_RELEASE_DC ==> */ O_RELEASE|A_DC_TIMER_START, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_DC_TIMER_START, }, /* Got an I_RECOVERED */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_DC_TIMER_START, /* S_RECOVERY_DC ==> */ A_JOIN_WELCOME_ALL|A_PE_INVOKE, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, }, /* Got an I_RELEASE_FAIL */ { /* S_IDLE ==> */ A_WARN|O_SHUTDOWN, /* S_ELECTION ==> */ A_WARN|O_SHUTDOWN, /* S_INTEGRATION ==> */ A_WARN|O_SHUTDOWN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ O_SHUTDOWN, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN|O_SHUTDOWN, /* S_RELEASE_DC ==> */ O_SHUTDOWN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN|O_SHUTDOWN, /* S_TERMINATE ==> */ A_WARN|O_SHUTDOWN, /* S_TRANSITION_ENGINE ==> */ A_WARN|O_SHUTDOWN, }, /* Got an I_RELEASE_SUCCESS */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, }, /* Got an I_RESTART */ { /* S_IDLE ==> */ A_NOTHING, /* S_ELECTION ==> */ A_LOG|A_ELECTION_TIMEOUT|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_LOG|A_JOIN_WELCOME_ALL|A_PE_INVOKE, /* S_NOT_DC ==> */ A_LOG|A_NOTHING, /* S_POLICY_ENGINE ==> */ A_LOG|A_PE_INVOKE, /* S_RECOVERY ==> */ A_LOG|A_RECOVER, /* S_RECOVERY_DC ==> */ A_LOG|A_RECOVER, /* S_RELEASE_DC ==> */ A_LOG|O_RELEASE, /* S_PENDING ==> */ A_LOG|A_STARTUP, /* S_STOPPING ==> */ A_LOG|O_SHUTDOWN, /* S_TERMINATE ==> */ A_LOG|O_SHUTDOWN, /* S_TRANSITION_ENGINE ==> */ A_LOG|A_TE_INVOKE, }, /* Got an I_REQUEST */ { /* S_IDLE ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_ELECTION ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_INTEGRATION ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_NOT_DC ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_POLICY_ENGINE ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_RECOVERY ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_RECOVERY_DC ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_RELEASE_DC ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_PENDING ==> */ A_MSG_STORE|A_MSG_PROCESS, /* S_STOPPING ==> */ A_LOG|A_MSG_STORE|A_MSG_PROCESS, /* S_TERMINATE ==> */ A_LOG|A_MSG_STORE|A_MSG_PROCESS, /* S_TRANSITION_ENGINE ==> */ A_MSG_STORE|A_MSG_PROCESS, }, /* Got an I_ROUTER */ { /* S_IDLE ==> */ A_MSG_ROUTE, /* S_ELECTION ==> */ A_MSG_ROUTE, /* S_INTEGRATION ==> */ A_MSG_ROUTE, /* S_NOT_DC ==> */ A_MSG_ROUTE, /* S_POLICY_ENGINE ==> */ A_MSG_ROUTE, /* S_RECOVERY ==> */ A_MSG_ROUTE, /* S_RECOVERY_DC ==> */ A_MSG_ROUTE, /* S_RELEASE_DC ==> */ A_MSG_ROUTE, /* S_PENDING ==> */ A_MSG_ROUTE, /* S_STOPPING ==> */ A_MSG_ROUTE, /* S_TERMINATE ==> */ A_MSG_ROUTE, /* S_TRANSITION_ENGINE ==> */ A_MSG_ROUTE, }, /* Got an I_SHUTDOWN */ { /* S_IDLE ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_ELECTION ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_INTEGRATION ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_RECOVERY ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_RECOVERY_DC ==> */ A_DC_TIMER_STOP|O_RELEASE, /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_PENDING ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_STOPPING ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_TERMINATE ==> */ A_DC_TIMER_STOP|A_SHUTDOWN_REQ, /* S_TRANSITION_ENGINE ==> */ A_DC_TIMER_STOP|O_RELEASE, }, /* Got an I_TERMINATE */ { /* S_IDLE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_ELECTION ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_INTEGRATION ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_NOT_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_RECOVERY ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_RECOVERY_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_PENDING ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_STOPPING ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_TERMINATE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, /* S_TRANSITION_ENGINE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, }, /* Got an I_STARTUP */ { /* S_IDLE ==> */ A_WARN, /* S_ELECTION ==> */ A_WARN, /* S_INTEGRATION ==> */ A_WARN, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_WARN, /* S_RECOVERY ==> */ A_WARN, /* S_RECOVERY_DC ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_LOG|A_STARTUP|A_CIB_START|A_LRM_CONNECT|A_CCM_CONNECT|A_HA_CONNECT|A_DC_TIMER_START, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_WARN, }, /* Got an I_SUCCESS */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_LOG|A_PE_INVOKE, + /* S_INTEGRATION ==> */ A_LOG|A_PE_INVOKE|A_CIB_INVOKE, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_LOG|A_TE_INVOKE, /* S_RECOVERY ==> */ A_RECOVER|A_LOG, /* S_RECOVERY_DC ==> */ A_RECOVER|A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_LOG, }, /* Got an I_WELCOME */ { /* S_IDLE ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_ELECTION ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_INTEGRATION ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_NOT_DC ==> */ O_DC_TICKLE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_POLICY_ENGINE ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_RECOVERY ==> */ A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_RECOVERY_DC ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_RELEASE_DC ==> */ A_UPDATE_NODESTATUS|A_JOIN_ACK, /* S_PENDING ==> */ O_DC_TICKLE|A_UPDATE_NODESTATUS|A_JOIN_ACK|A_STARTED|A_UPDATE_NODESTATUS, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, }, /* Got an I_WELCOME_ACK */ { - /* S_IDLE ==> */ A_JOIN_PROCESS_ACK|A_CIB_INVOKE|A_CIB_BUMPGEN, + /* S_IDLE ==> */ A_JOIN_PROCESS_ACK, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_JOIN_PROCESS_ACK|A_CIB_INVOKE|A_CIB_BUMPGEN, + /* S_INTEGRATION ==> */ A_JOIN_PROCESS_ACK, /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_JOIN_PROCESS_ACK|A_CIB_INVOKE|A_CIB_BUMPGEN, + /* S_POLICY_ENGINE ==> */ A_JOIN_PROCESS_ACK, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_JOIN_PROCESS_ACK|A_CIB_INVOKE|A_CIB_BUMPGEN, + /* S_RECOVERY_DC ==> */ A_JOIN_PROCESS_ACK, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_JOIN_PROCESS_ACK|A_CIB_INVOKE|A_CIB_BUMPGEN, + /* S_TRANSITION_ENGINE ==> */ A_JOIN_PROCESS_ACK, }, /* Got an I_WAIT_FOR_EVENT */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_LOG, /* S_NOT_DC ==> */ A_LOG, /* S_POLICY_ENGINE ==> */ A_LOG, /* S_RECOVERY ==> */ A_LOG, /* S_RECOVERY_DC ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_LOG, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_LOG, }, /* Got an I_DC_HEARTBEAT */ { /* S_IDLE ==> */ A_WARN|A_ELECTION_VOTE, /* S_ELECTION ==> */ A_WARN|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_WARN|A_ELECTION_VOTE, /* S_NOT_DC ==> */ O_DC_TICKLE, /* S_POLICY_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, /* S_RECOVERY ==> */ A_NOTHING|O_DC_TICKLE, /* S_RECOVERY_DC ==> */ A_WARN|O_RELEASE|A_DC_TIMER_START, /* S_RELEASE_DC ==> */ A_LOG|A_DC_TIMER_START, /* S_PENDING ==> */ A_LOG|O_DC_TICKLE|A_ANNOUNCE, /* S_STOPPING ==> */ A_NOTHING, /* S_TERMINATE ==> */ A_NOTHING, /* S_TRANSITION_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, }, /* Got an I_LRM_EVENT */ { /* S_IDLE ==> */ A_LRM_EVENT, /* S_ELECTION ==> */ A_LRM_EVENT, /* S_INTEGRATION ==> */ A_LRM_EVENT, /* S_NOT_DC ==> */ A_LRM_EVENT, /* S_POLICY_ENGINE ==> */ A_LRM_EVENT, /* S_RECOVERY ==> */ A_LRM_EVENT, /* S_RECOVERY_DC ==> */ A_LRM_EVENT, /* S_RELEASE_DC ==> */ A_LRM_EVENT, /* S_PENDING ==> */ A_LRM_EVENT, /* S_STOPPING ==> */ A_LRM_EVENT, /* S_TERMINATE ==> */ A_LRM_EVENT, /* S_TRANSITION_ENGINE ==> */ A_LRM_EVENT, }, }; #endif diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c index e65b488bac..9f9c7ff52f 100644 --- a/crm/crmd/messages.c +++ b/crm/crmd/messages.c @@ -1,812 +1,841 @@ /* * 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 FILE *msg_in_strm = NULL; FILE *router_strm = NULL; fsa_message_queue_t fsa_message_queue = NULL; gboolean relay_message(xmlNodePtr xml_relay_message, gboolean originated_locally); #ifdef MSG_LOG # define ROUTER_RESULT(x) char *msg_text = dump_xml(xml_relay_message);\ if(router_strm == NULL) { \ router_strm = fopen("/tmp/router.log", "w"); \ } \ fprintf(router_strm, "[%d RESULT (%s)]\t%s\t%s\n", \ AM_I_DC, \ xmlGetProp(xml_relay_message, XML_ATTR_REFERENCE),\ x, msg_text); \ fflush(router_strm); \ cl_free(msg_text); #else # define ROUTER_RESULT(x) CRM_DEBUG(x); #endif /* returns the current head of the FIFO queue */ fsa_message_queue_t put_message(xmlNodePtr new_message) { fsa_message_queue_t next_message = (fsa_message_queue_t) cl_malloc(sizeof(struct fsa_message_queue_s)); CRM_DEBUG("Adding msg to queue"); next_message->message = new_message; next_message->next = NULL; if(fsa_message_queue == NULL) { fsa_message_queue = next_message; } else { fsa_message_queue->next = next_message; } CRM_DEBUG("Added msg to queue"); return fsa_message_queue; } /* returns the next message */ fsa_message_queue_t get_message(void) { fsa_message_queue_t next_message = NULL; if(fsa_message_queue != NULL) { next_message = fsa_message_queue; fsa_message_queue = fsa_message_queue->next; next_message->next = NULL; } return next_message; } /* returns the current head of the FIFO queue */ gboolean is_message(void) { return (fsa_message_queue != NULL && fsa_message_queue->message != NULL); } /* A_MSG_STORE */ enum crmd_fsa_input do_msg_store(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { // xmlNodePtr new_message = (xmlNodePtr)data; FNIN(); // put_message(new_message); FNRET(I_NULL); } /* A_MSG_ROUTE */ enum crmd_fsa_input do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; xmlNodePtr xml_message = (xmlNodePtr)data; gboolean routed = FALSE, defer = TRUE, do_process = TRUE; FNIN(); #if 0 // if(cause == C_IPC_MESSAGE) { if (crmd_authorize_message(root_xml_node, msg, curr_client) == FALSE) { CRM_DEBUG("Message not authorized"); do_process = FALSE; } // } #endif if(do_process) { /* try passing the buck first */ routed = relay_message(xml_message, cause==C_IPC_MESSAGE); if(routed == FALSE) { defer = TRUE; /* calculate defer */ result = handle_message(xml_message); switch(result) { case I_NULL: defer = FALSE; break; case I_DC_HEARTBEAT: defer = FALSE; break; /* what else should go here? */ default: CRM_DEBUG("Defering local processing of message"); put_message(xml_message); result = I_REQUEST; break; } } } FNRET(result); } void crmd_ha_input_callback(const struct ha_msg* msg, void* private_data) { const char *from = ha_msg_value(msg, F_ORIG); const char *to = NULL; 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 xmlNodePtr 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; crmd_client_t *curr_client = (crmd_client_t*)user_data; FNIN(); CRM_DEBUG2("Processing IPC message from %s", curr_client->table_key); while(client->ops->is_message_pending(client)) { if (client->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if (client->ops->recv(client, &msg) != IPC_OK) { perror("Receive failure:"); FNRET(!hack_return_good); } if (msg == NULL) { CRM_DEBUG("No message this time"); continue; } lpc++; buffer = (char*)msg->msg_body; CRM_DEBUG3("Processing xml from %s [text=%s]", curr_client->table_key, buffer); xmlNodePtr root_xml_node = find_xml_in_ipcmessage(msg, FALSE); if (root_xml_node != NULL) { if (crmd_authorize_message(root_xml_node, msg, curr_client)) { CRM_DEBUG("Message authorized,about to relay"); s_crmd_fsa(C_IPC_MESSAGE, I_ROUTER, root_xml_node); } else { CRM_DEBUG("Message not authorized"); } } else { cl_log(LOG_INFO, "IPC Message was not valid... discarding."); } free_xml(root_xml_node); msg->msg_done(msg); msg = NULL; buffer = NULL; root_xml_node = NULL; } CRM_DEBUG2("Processed %d messages", lpc); if (client->ch_status == IPC_DISCONNECT) { cl_log(LOG_INFO, "received HUP from %s", curr_client->table_key); if (curr_client != NULL) { struct crm_subsystem_s *the_subsystem = NULL; if (curr_client->sub_sys == NULL) CRM_DEBUG("Client had not registered with us yet"); else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) the_subsystem = pe_subsystem; else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) the_subsystem = te_subsystem; else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0) the_subsystem = cib_subsystem; if(the_subsystem != NULL) { cleanup_subsystem(the_subsystem); } // else that was a transient client if (curr_client->table_key != NULL) { /* * Key is destroyed below: curr_client->table_key * Value is cleaned up by G_main_del_IPC_Channel */ g_hash_table_remove(ipc_clients, curr_client->table_key); } if(curr_client->client_source != NULL) { gboolean det = G_main_del_IPC_Channel(curr_client->client_source); CRM_DEBUG2("crm_client was %s detached", det?"successfully":"not"); } cl_free(curr_client->table_key); cl_free(curr_client->sub_sys); cl_free(curr_client->uuid); cl_free(curr_client); } CRM_DEBUG("this client has now left the building."); FNRET(!hack_return_good); } FNRET(hack_return_good); } /* * This method adds a copy of xml_response_data */ gboolean send_request(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation, const char *host_to, const char *sys_to) { gboolean was_sent = FALSE; xmlNodePtr request = NULL; FNIN(); msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS, XML_ATTR_OP, operation, TRUE); request = create_request(msg_options, msg_data, host_to, sys_to, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL, NULL); // xml_message_debug(request, "Final request..."); was_sent = relay_message(request, TRUE); + if(was_sent == FALSE) { + put_message(request); + } + free_xml(request); FNRET(was_sent); } +/* + * This method adds a copy of xml_response_data + */ +gboolean +store_request(xmlNodePtr msg_options, xmlNodePtr msg_data, + const char *operation, const char *host_to, const char *sys_to) +{ + xmlNodePtr request = NULL; + FNIN(); + + + msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS, + XML_ATTR_OP, operation, TRUE); + + request = create_request(msg_options, + msg_data, + host_to, + sys_to, + AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, + NULL, + NULL); + + put_message(request); + + FNRET(TRUE); +} gboolean relay_message(xmlNodePtr xml_relay_message, gboolean originated_locally) { int is_for_dc = 0; int is_for_dcib = 0; int is_for_crm = 0; int is_for_cib = 0; int is_local = 0; gboolean dont_cc= TRUE; gboolean processing_complete = FALSE; const char *host_to = xmlGetProp(xml_relay_message, XML_ATTR_HOSTTO); const char *sys_to = xmlGetProp(xml_relay_message, XML_ATTR_SYSTO); const char *sys_cc = get_xml_attr(xml_relay_message, XML_TAG_OPTIONS, XML_ATTR_SYSCC, FALSE); FNIN(); if(xml_relay_message == NULL) { cl_log(LOG_ERR, "Cannot route empty message"); FNRET(TRUE); } if(strcmp("hello", xml_relay_message->name) == 0) { /* quietly ignore */ FNRET(TRUE); } if(strcmp(XML_MSG_TAG, xml_relay_message->name) != 0) { xml_message_debug(xml_relay_message, "Bad message type, should be crm_message"); cl_log(LOG_ERR, "Ignoring message of type %s", xml_relay_message->name); FNRET(TRUE); } if(sys_to == NULL) { xml_message_debug(xml_relay_message, "Message did not have any value for sys_to"); cl_log(LOG_ERR, "Message did not have any value for %s", XML_ATTR_SYSTO); FNRET(TRUE); } is_for_dc = (strcmp(CRM_SYSTEM_DC, sys_to) == 0); is_for_dcib = (strcmp(CRM_SYSTEM_DCIB, sys_to) == 0); is_for_cib = (strcmp(CRM_SYSTEM_CIB, sys_to) == 0); is_for_crm = (strcmp(CRM_SYSTEM_CRMD, sys_to) == 0); is_local = 0; if(host_to == NULL || strlen(host_to) == 0) { if(is_for_dc) is_local = 0; else if(is_for_crm && originated_locally) is_local = 0; else is_local = 1; } else if(strcmp(fsa_our_uname, host_to) == 0) { is_local=1; } #if 0 CRM_DEBUG2("is_local %d", is_local); CRM_DEBUG2("is_for_dcib %d", is_for_dcib); CRM_DEBUG2("is_for_dc %d", is_for_dc); CRM_DEBUG2("is_for_crm %d", is_for_crm); CRM_DEBUG2("AM_I_DC %d", AM_I_DC); CRM_DEBUG2("sys_to %s", sys_to); CRM_DEBUG2("host_to %s", host_to); #endif /* if(AM_I_DC && sys_cc != NULL && strcmp(sys_cc, CRM_SYSTEM_DC) == 0) { dont_cc = FALSE; } */ (void)sys_cc; if(is_for_dc || is_for_dcib) { if(AM_I_DC) { ROUTER_RESULT("Message result: DC/CRMd process"); processing_complete = FALSE; // more to be done by caller } else if(originated_locally) { ROUTER_RESULT("Message result: External relay to DC"); send_msg_via_ha(xml_relay_message, NULL); processing_complete = TRUE; } else { ROUTER_RESULT("Message result: Discard, not DC"); processing_complete = TRUE; // discard } } else if(is_local && (is_for_crm || is_for_cib)) { ROUTER_RESULT("Message result: CRMd process"); } else if(is_local) { if(dont_cc) { ROUTER_RESULT("Message result: Local relay"); } else { /* The DC should also get this message */ ROUTER_RESULT("Message result: Local relay with CC"); } send_msg_via_ipc(xml_relay_message, sys_to); processing_complete = TRUE & dont_cc; } else { if(dont_cc) { ROUTER_RESULT("Message result: External relay"); } else { /* The DC should also get this message */ ROUTER_RESULT("Message result: External relay with CC"); } send_msg_via_ha(xml_relay_message, host_to); processing_complete = TRUE & dont_cc; } FNRET(processing_complete); } void send_msg_via_ha(xmlNodePtr action, const char *dest_node) { FNIN(); if (action == NULL) FNOUT(); if (validate_crm_message(action, NULL, NULL, NULL) == NULL) { cl_log(LOG_ERR, "Relay message to (%s) via HA was invalid, ignoring", dest_node); FNOUT(); } // CRM_DEBUG2("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) { FNIN(); // cl_log(LOG_DEBUG, "relaying msg to sub_sys=%s via IPC", sys); IPC_Channel *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; gpointer table_key = NULL; FNIN(); if (sys_from != NULL) { gboolean can_reply = FALSE; // no-one has registered with this id const char *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_DEBUG3("Message reply can%s be routed from %s.", can_reply?"":" not", sys_from); FNRET(can_reply); } // otherwise, check if it was a hello message cl_log(LOG_INFO, "received client join msg: %s", (char*)client_msg->msg_body); gboolean result = process_hello_message(client_msg, &uuid, &client_name, &major_version, &minor_version); if (result == TRUE) { // check version int mav = atoi(major_version); int miv = atoi(minor_version); if (mav < 0 || miv < 0) { cl_log(LOG_ERR, "Client version (%d:%d) is not acceptable", mav, miv); result = FALSE; } cl_free(major_version); cl_free(minor_version); } if (result == TRUE) { /* if we already have one of those clients * only applies to te, pe etc. not admin clients */ struct crm_subsystem_s *the_subsystem = NULL; if (client_name == NULL) CRM_DEBUG("Client had not registered with us yet"); else if (strcmp(CRM_SYSTEM_PENGINE, client_name) == 0) the_subsystem = pe_subsystem; else if (strcmp(CRM_SYSTEM_TENGINE, client_name) == 0) the_subsystem = te_subsystem; else if (strcmp(CRM_SYSTEM_CIB, client_name) == 0) the_subsystem = cib_subsystem; if (the_subsystem != NULL) { // do we already have one? result = (fsa_input_register & the_subsystem->flag) == 0; set_bit_inplace(&fsa_input_register, the_subsystem->flag); 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) table_key = (gpointer)cl_strdup(client_name); if (result == TRUE) { cl_log(LOG_INFO, "Accepted client %s", (char*)table_key); curr_client->table_key = table_key; curr_client->sub_sys = cl_strdup(client_name); curr_client->uuid = cl_strdup(uuid); g_hash_table_insert (ipc_clients, table_key, curr_client->client_channel); send_hello_message(curr_client->client_channel, "n/a", CRM_SYSTEM_CRMD, "0", "1"); } else { cl_log(LOG_ERR, "Rejected client logon request"); curr_client->client_channel->ch_status = IPC_DISC_PENDING; } if(uuid != NULL) cl_free(uuid); if(client_name != NULL) cl_free(client_name); /* hello messages should never be processed further */ FNRET(FALSE); } enum crmd_fsa_input handle_message(xmlNodePtr stored_msg) { enum crmd_fsa_input next_input = I_NULL; const char *sys_to = get_xml_attr(stored_msg, NULL, XML_ATTR_SYSTO, TRUE); // const char *sys_from = get_xml_attr(stored_msg, NULL, // XML_ATTR_SYSFROM, TRUE); const char *type = get_xml_attr(stored_msg, NULL, XML_ATTR_MSGTYPE, TRUE); const char *op = get_xml_attr(stored_msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); // xml_message_debug(stored_msg, "Processing message"); if(type == NULL || op == NULL) { cl_log(LOG_ERR, "Ignoring message (type=%s), (op=%s)", type, op); xml_message_debug(stored_msg, "Bad message"); } else if(strcmp(type, XML_ATTR_REQUEST) == 0){ if(strcmp(op, CRM_OPERATION_VOTE) == 0) { next_input = I_ELECTION; } else if(strcmp(op, CRM_OPERATION_HBEAT) == 0) { next_input = I_DC_HEARTBEAT; } else if(strcmp(op, CRM_OPERATION_WELCOME) == 0) { next_input = I_WELCOME; } else if(strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0) { next_input = I_CIB_OP; } else if(strcmp(op, CRM_OPERATION_SHUTDOWN) == 0) { next_input = I_TERMINATE; } else if(strcmp(op, CRM_OPERATION_ANNOUNCE) == 0) { next_input = I_NODE_JOIN; } else if(strcmp(op, CRM_OPERATION_REPLACE) == 0 || strcmp(op, CRM_OPERATION_ERASE) == 0) { next_input = I_CIB_OP; fprintf(router_strm, "Message result: CIB Op\n"); } else if(AM_I_DC && (strcmp(op, CRM_OPERATION_CREATE) == 0 || strcmp(op, CRM_OPERATION_UPDATE) == 0 || strcmp(op, CRM_OPERATION_DELETE) == 0)) { /* updates should only be performed on the DC */ next_input = I_CIB_OP; } else if(strcmp(op, CRM_OPERATION_PING) == 0) { /* eventually do some stuff to figure out * if we /are/ ok */ xmlNodePtr ping = createPingAnswerFragment(sys_to, "ok"); xmlNodePtr wrapper = create_reply(stored_msg, ping); relay_message(wrapper, TRUE); free_xml(wrapper); } else { cl_log(LOG_ERR, "Unexpected request (op=%s) sent to the %s", op, AM_I_DC?"DC":"CRMd"); } } else if(strcmp(type, XML_ATTR_RESPONSE) == 0) { if(strcmp(op, CRM_OPERATION_WELCOME) == 0) { next_input = I_WELCOME_ACK; } else if(strcmp(op, CRM_OPERATION_VOTE) == 0 || strcmp(op, CRM_OPERATION_HBEAT) == 0 || strcmp(op, CRM_OPERATION_WELCOME) == 0 || strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OPERATION_SHUTDOWN) == 0 || strcmp(op, CRM_OPERATION_ANNOUNCE) == 0) { next_input = I_NULL; - } else if(AM_I_DC - && (strcmp(op, CRM_OPERATION_CREATE) == 0 - || strcmp(op, CRM_OPERATION_UPDATE) == 0 - || strcmp(op, CRM_OPERATION_DELETE) == 0 - || strcmp(op, CRM_OPERATION_REPLACE) == 0 - || strcmp(op, CRM_OPERATION_ERASE) == 0)) { +/* } else if(AM_I_DC */ +/* && (strcmp(op, CRM_OPERATION_CREATE) == 0 */ +/* || strcmp(op, CRM_OPERATION_UPDATE) == 0 */ +/* || strcmp(op, CRM_OPERATION_DELETE) == 0 */ +/* || strcmp(op, CRM_OPERATION_REPLACE) == 0 */ +/* || strcmp(op, CRM_OPERATION_ERASE) == 0)) { */ - // perhaps we should do somethign with these replies - fprintf(router_strm, "Message result: CIB Reply\n"); +/* // perhaps we should do somethign with these replies */ +/* fprintf(router_strm, "Message result: CIB Reply\n"); */ - next_input = I_CIB_UPDATE; - } 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_DEBUG3("%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 9496846c6b..c42e39d1af 100644 --- a/crm/crmd/subsystems.c +++ b/crm/crmd/subsystems.c @@ -1,1084 +1,1050 @@ /* * 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 // for access #include #include #include // for calls to open #include // for calls to open #include // for calls to open #include // for getpwuid #include // for initgroups #include // for getrlimit #include // for getrlimit #include #include #include #include #include #include #include #include #include #include #include #define CLIENT_EXIT_WAIT 10 static gboolean stop_subsystem (struct crm_subsystem_s *centry); static gboolean start_subsystem(struct crm_subsystem_s *centry); static gboolean run_command (struct crm_subsystem_s *centry, const char *options, gboolean update_pid); xmlNodePtr do_lrm_query(void); + GHashTable *xml2list(xmlNodePtr parent, const char **attr_path, int depth); + gboolean lrm_dispatch(int fd, gpointer user_data); -void send_cib_status_update(xmlNodePtr update); -void send_cib_lrm_update(xmlNodePtr update, gboolean lrm_replace); -void do_update_resource(lrm_rsc_t *rsc, int status, int rc, const char *op_type); +void do_update_resource(lrm_rsc_t *rsc, int status, int rc, const char *op_type); struct crm_subsystem_s *cib_subsystem = NULL; struct crm_subsystem_s *te_subsystem = NULL; struct crm_subsystem_s *pe_subsystem = NULL; void cleanup_subsystem(struct crm_subsystem_s *the_subsystem) { int pid_status = -1; the_subsystem->ipc = NULL; clear_bit_inplace(&fsa_input_register, the_subsystem->flag); /* Forcing client to die */ kill(the_subsystem->pid, -9); // cleanup the ps entry waitpid(the_subsystem->pid, &pid_status, WNOHANG); the_subsystem->pid = -1; } /* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = cib_subsystem; long long stop_actions = A_CIB_STOP; long long start_actions = A_CIB_START; FNIN(); if(action & stop_actions) { // dont do anything, its embedded now } if(action & start_actions) { if(cur_state != S_STOPPING) { if(startCib(CIB_FILENAME) == FALSE) result = I_FAIL; } else { cl_log(LOG_INFO, "Ignoring request to start %s after shutdown", this_subsys->command); } } FNRET(result); } /* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr cib_msg = NULL; FNIN(); if(data != NULL) cib_msg = (xmlNodePtr)data; if(action & A_CIB_INVOKE) { const char *op = xmlGetProp(cib_msg, XML_ATTR_OP); if(safe_str_eq(op, CRM_OPERATION_SHUTDOWN_REQ)){ // create update section xmlNodePtr tmp1 = NULL; xmlNodePtr tmp2 = create_xml_node(NULL, XML_CIB_TAG_STATE); const char *req_from = xmlGetProp(cib_msg, XML_ATTR_HOSTFROM); set_xml_property_copy(tmp1, "id", req_from); set_xml_property_copy(tmp1, "exp_state", "shutdown"); // create fragment - tmp1 = create_cib_fragment(tmp2, XML_CIB_TAG_STATUS); + tmp1 = create_cib_fragment(tmp2, NULL); // add to cib_msg add_node_copy(cib_msg, tmp1); free_xml(tmp2); free_xml(tmp1); } set_xml_property_copy(cib_msg, XML_ATTR_SYSTO, "cib"); xmlNodePtr answer = process_cib_message(cib_msg, TRUE); if(relay_message(answer, TRUE) == FALSE) { cl_log(LOG_ERR, "Confused what to do with cib result"); xml_message_debug(answer, "Couldnt route: "); } + + if(AM_I_DC && (strcmp(op, CRM_OPERATION_CREATE) == 0 + || strcmp(op, CRM_OPERATION_UPDATE) == 0 + || strcmp(op, CRM_OPERATION_DELETE) == 0 + || strcmp(op, CRM_OPERATION_REPLACE) == 0 + || strcmp(op, CRM_OPERATION_WELCOME) == 0 + || strcmp(op, CRM_OPERATION_SHUTDOWN_REQ) == 0 + || strcmp(op, CRM_OPERATION_ERASE) == 0)) { + FNRET(I_CIB_UPDATE); + } + + // 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) { xmlNodePtr 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 const char *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 */ - xmlNodePtr new_options = - set_xml_attr(NULL, XML_TAG_OPTIONS, - XML_ATTR_FILTER_TYPE, section, TRUE); + xmlNodePtr new_options = NULL; + + if(section != NULL) { + new_options = set_xml_attr(NULL, XML_TAG_OPTIONS, + XML_ATTR_FILTER_TYPE, + section, TRUE); + } xmlNodePtr answer = process_cib_request(CRM_OPERATION_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_OPERATION_REPLACE, NULL, CRM_SYSTEM_CRMD); free_xml(answer); - } else if(action & A_UPDATE_NODESTATUS) { - - xmlNodePtr data = do_lrm_query(); - - send_cib_lrm_update(data, TRUE); - - free_xml(data); - } else { cl_log(LOG_ERR, "Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } FNRET(I_NULL); } /* A_PE_START, A_PE_STOP, A_TE_RESTART */ enum crmd_fsa_input do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = pe_subsystem; long long stop_actions = A_PE_STOP; long long start_actions = A_PE_START; FNIN(); if(action & stop_actions) { if(stop_subsystem(this_subsys) == FALSE) result = I_FAIL; else if(this_subsys->pid > 0){ int lpc = CLIENT_EXIT_WAIT; int pid_status = -1; while(lpc-- > 0 && this_subsys->pid > 0 && CL_PID_EXISTS(this_subsys->pid)) { sleep(1); waitpid(this_subsys->pid, &pid_status, WNOHANG); } if(CL_PID_EXISTS(this_subsys->pid)) { cl_log(LOG_ERR, "Process %s is still active with pid=%d", this_subsys->command, this_subsys->pid); result = I_FAIL; } } cleanup_subsystem(this_subsys); } if(action & start_actions) { if(cur_state != S_STOPPING) { if(start_subsystem(this_subsys) == FALSE) { result = I_FAIL; cleanup_subsystem(this_subsys); } } else { cl_log(LOG_INFO, "Ignoring request to start %s while shutting down", this_subsys->command); } } FNRET(result); } /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { FNIN(); stopTimer(integration_timer); cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); FNRET(I_NULL); } /* A_TE_START, A_TE_STOP, A_TE_RESTART */ enum crmd_fsa_input do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = te_subsystem; long long stop_actions = A_TE_STOP; long long start_actions = A_TE_START; FNIN(); /* if(action & stop_actions && cur_state != S_STOPPING */ /* && is_set(fsa_input_register, R_TE_PEND)) { */ /* result = I_WAIT_FOR_EVENT; */ /* FNRET(result); */ /* } */ if(action & stop_actions) { if(stop_subsystem(this_subsys) == FALSE) result = I_FAIL; else if(this_subsys->pid > 0){ int lpc = CLIENT_EXIT_WAIT; int pid_status = -1; while(lpc-- > 0 && this_subsys->pid > 0 && CL_PID_EXISTS(this_subsys->pid)) { sleep(1); waitpid(this_subsys->pid, &pid_status, WNOHANG); } if(CL_PID_EXISTS(this_subsys->pid)) { cl_log(LOG_ERR, "Process %s is still active with pid=%d", this_subsys->command, this_subsys->pid); result = I_FAIL; } } cleanup_subsystem(this_subsys); } if(action & start_actions) { if(cur_state != S_STOPPING) { if(start_subsystem(this_subsys) == FALSE) { result = I_FAIL; cleanup_subsystem(this_subsys); } } else { cl_log(LOG_INFO, "Ignoring request to start %s while shutting down", this_subsys->command); } } FNRET(result); } /* A_TE_INVOKE */ 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) { FNIN(); cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); FNRET(I_NULL); } gboolean crmd_client_connect(IPC_Channel *client_channel, gpointer user_data) { FNIN(); CRM_DEBUG("A client tried to connect... and there was much rejoicing."); if (client_channel == NULL) { cl_log(LOG_ERR, "Channel was NULL"); } else if (client_channel->ch_status == IPC_DISCONNECT) { cl_log(LOG_ERR, "Channel was disconnected"); } else { crmd_client_t *blank_client = (crmd_client_t *)cl_malloc(sizeof(crmd_client_t)); if (blank_client == NULL) { cl_log(LOG_ERR, "Could not allocate memory for a blank crmd_client_t"); FNRET(FALSE); } client_channel->ops->set_recv_qlen(client_channel, 100); client_channel->ops->set_send_qlen(client_channel, 100); blank_client->client_channel = client_channel; blank_client->sub_sys = NULL; blank_client->uuid = NULL; blank_client->table_key = NULL; CRM_DEBUG("Adding IPC Channel to main thread."); blank_client->client_source = G_main_add_IPC_Channel(G_PRIORITY_LOW, client_channel, FALSE, crmd_ipc_input_callback, blank_client, default_ipc_input_destroy); } FNRET(TRUE); } static gboolean stop_subsystem(struct crm_subsystem_s* centry) { cl_log(LOG_INFO, "Stopping sub-system \"%s\"", centry->name); if (centry->pid <= 0) { cl_log(LOG_ERR, "OOPS! client %s not running yet", centry->command); } else { cl_log(LOG_INFO, "Sending quit message to %s.", centry->name); send_request(NULL, NULL, "quit", NULL, centry->name); } return TRUE; } static gboolean start_subsystem(struct crm_subsystem_s* centry) { cl_log(LOG_INFO, "Starting sub-system \"%s\"", centry->command); if (centry->pid != 0) { cl_log(LOG_ERR, "OOPS! client %s already running as pid %d" , centry->command, (int) centry->pid); } return run_command(centry, "-r", TRUE); } static gboolean run_command(struct crm_subsystem_s *centry, const char *options, gboolean update_pid) { pid_t pid; /* * 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; } struct stat buf; int s_res = stat(centry->command, &buf); if(s_res != 0) { cl_perror("Cannot (stat) exec %s", centry->command); return FALSE; } /* We need to fork so we can make child procs not real time */ switch(pid=fork()) { case -1: cl_log(LOG_ERR , "start_a_child_client: Cannot fork."); return FALSE; default: /* Parent */ #if 0 NewTrackedProc(pid, 1, PT_LOGVERBOSE , centry, &ManagedChildTrackOps); #else if(update_pid) centry->pid = pid; #endif return TRUE; case 0: /* Child */ break; } /* Child process: start the managed child */ cl_make_normaltime(); setpgid(0,0); /* Limit peak resource usage, maximize success chances */ if (centry->shortrcount > 0) { alarm(0); sleep(1); } char *cmd_with_options = NULL; int size = strlen(options); size += strlen(centry->command); size += 2; // ' ' + \0 cmd_with_options = cl_malloc((1+size)*sizeof(char)); sprintf(cmd_with_options, "%s %s", centry->command, options); cmd_with_options[size] = 0; cl_log(LOG_INFO, "Executing \"%s\" (pid %d)", cmd_with_options, (int) getpid()); if(CL_SIGINTERRUPT(SIGALRM, 0) < 0) { cl_perror("Cannot set interrupt for child process %s", cmd_with_options); }else{ const char * devnull = "/dev/null"; unsigned int j; struct rlimit oflimits; CL_SIGNAL(SIGCHLD, SIG_DFL); alarm(0); CL_IGNORE_SIG(SIGALRM); /* A precautionary measure */ getrlimit(RLIMIT_NOFILE, &oflimits); for (j=0; j < oflimits.rlim_cur; ++j) { close(j); } (void)devnull; (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ (void)execl("/bin/sh", "sh", "-c", cmd_with_options, (const char *)NULL); /* Should not happen */ cl_perror("Cannot exec %s", cmd_with_options); } /* Suppress respawning */ exit(100); // never reached return TRUE; } /* A_LRM_CONNECT */ enum crmd_fsa_input do_lrm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input failed = I_NULL;//I_FAIL; int ret = HA_OK; FNIN(); if(action & A_LRM_DISCONNECT) { fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); } if(action & A_LRM_CONNECT) { CRM_DEBUG("LRM: connect..."); fsa_lrm_conn = ll_lrm_new("lrm"); if(NULL == fsa_lrm_conn) { return failed; } CRM_DEBUG("LRM: sigon..."); ret = fsa_lrm_conn->lrm_ops->signon(fsa_lrm_conn, "crmd"); if(ret != HA_OK) { cl_log(LOG_ERR, "Failed to sign on to the LRM"); return failed; } CRM_DEBUG("LRM: set_lrm_callback..."); ret = fsa_lrm_conn->lrm_ops->set_lrm_callback(fsa_lrm_conn, lrm_op_callback, lrm_monitor_callback); if(ret != HA_OK) { cl_log(LOG_ERR, "Failed to set LRM callbacks"); return failed; } /* TODO: create a destroy handler that causes * some recovery to happen */ G_main_add_fd(G_PRIORITY_LOW, fsa_lrm_conn->lrm_ops->inputfd(fsa_lrm_conn), FALSE, lrm_dispatch, fsa_lrm_conn, default_ipc_input_destroy); } if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) { cl_log(LOG_ERR, "Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } FNRET(I_NULL); } gboolean lrm_dispatch(int fd, gpointer user_data) { ll_lrm_t *lrm = (ll_lrm_t*)user_data; lrm->lrm_ops->rcvmsg(lrm, FALSE); return TRUE; } xmlNodePtr do_lrm_query(void) { GList* lrm_list = NULL; xmlNodePtr data = create_xml_node(NULL, "lrm"); xmlNodePtr agent_list = create_xml_node(data, "lrm_agents"); 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) { char *rsc_type = (char*)element->data; xmlNodePtr agent = create_xml_node(agent_list, "lrm_agent"); set_xml_property_copy(agent, "class", rsc_type); /* we dont have these yet */ set_xml_property_copy(agent, "type", NULL); set_xml_property_copy(agent, "version", NULL); element = g_list_next(element); } } g_list_free(lrm_list); lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); xmlNodePtr rsc_list = create_xml_node(data, "lrm_resources"); GList* element = NULL; if (NULL != lrm_list) { element = g_list_first(lrm_list); } while (NULL != element) { lrm_rsc_t *the_rsc = (lrm_rsc_t*)element->data; /* const char* ra_type; */ /* GHashTable* params; */ xmlNodePtr xml_rsc = create_xml_node(rsc_list, "rsc_state"); set_xml_property_copy(xml_rsc, "id", the_rsc->id); set_xml_property_copy(xml_rsc, "rsc_id", the_rsc->name); set_xml_property_copy(xml_rsc, "node_id",fsa_our_uname); state_flag_t cur_state = 0; CRM_DEBUG("get_cur_state..."); GList* op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); CRM_DEBUG2("\tcurrent state:%s\n", cur_state==LRM_RSC_IDLE?"Idel":"Busy"); const char *this_op = NULL; GList* 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; FNIN(); + + if(action & A_UPDATE_NODESTATUS) { + + xmlNodePtr data = do_lrm_query(); + set_xml_property_copy(data, "replace_lrm", "true"); + + xmlNodePtr fragment, tmp1; + + tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); + set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname); + fragment = create_cib_fragment(tmp1, NULL); + + set_xml_property_copy(data, "replace_lrm", "true"); + add_node_copy(tmp1, data); + + send_request(NULL, fragment, CRM_OPERATION_UPDATE, + NULL, CRM_SYSTEM_DC); + + free_xml(fragment); + free_xml(tmp1); + free_xml(data); + + FNRET(next_input); + } + + + cl_log(LOG_ERR, "Action %s (%.16llx) not supported\n", fsa_action2string(action), action); xmlNodePtr msg = (xmlNodePtr)data; const char *rsc_path[] = { "msg_data", "rsc_op", "resource", "instance_attributes", "parameters" }; const char *operation = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -3, "operation", TRUE); rsc_id_t rid; const char *id_from_cib = get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, "id", TRUE); // only the first 16 chars are used by the LRM strncpy(rid, id_from_cib, 16); const char *crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, "operation", TRUE); lrm_rsc_t *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); } lrm_mon_t* mon = g_new(lrm_mon_t, 1); mon->op_type = "status"; mon->params = NULL; mon->timeout = 0; mon->user_data = rsc; mon->mode = LRM_MONITOR_SET; mon->interval = 2; mon->target = 1; rsc->ops->set_monitor(rsc,mon); mon = g_new(lrm_mon_t, 1); } else if(operation != NULL) { if(rsc == NULL) { // add it to the list CRM_DEBUG("add_rsc..."); fsa_lrm_conn->lrm_ops->add_rsc( fsa_lrm_conn, rid, get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, "class", TRUE), get_xml_attr_nested(msg, rsc_path, DIMOF(rsc_path) -2, "type", TRUE), NULL); rsc = fsa_lrm_conn->lrm_ops->get_rsc( fsa_lrm_conn, rid); } if(rsc == NULL) { cl_log(LOG_ERR, "Could not add resource to LRM"); FNRET(I_FAIL); } // now do the op CRM_DEBUG2("performing op %s...", operation); lrm_op_t* 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); } -/* while (TRUE) { */ -/* lrm->lrm_ops->rcvmsg(lrm,TRUE); */ -/* } */ - - FNRET(I_NULL); + FNRET(next_input); } GHashTable * xml2list(xmlNodePtr parent, const char**attr_path, int depth) { xmlNodePtr node_iter = NULL; GHashTable *nvpair_hash = g_hash_table_new(&g_str_hash, &g_str_equal); xmlNodePtr nvpair_list = find_xml_node_nested(parent, attr_path, depth); if(nvpair_list != NULL){ node_iter = nvpair_list->children; while(node_iter != NULL) { const char *key = xmlGetProp(node_iter, "name"); const char *value = xmlGetProp(node_iter, "value"); CRM_DEBUG3("Added %s=%s", key, value); g_hash_table_insert (nvpair_hash, cl_strdup(key), cl_strdup(value)); node_iter = node_iter->next; } } return nvpair_hash; } void do_update_resource(lrm_rsc_t *rsc, int status, int rc, const char *op_type) { /* */ xmlNodePtr update, iter; update = create_xml_node(NULL, "node_state"); set_xml_property_copy(update, XML_ATTR_ID, fsa_our_uname); iter = create_xml_node(update, "lrm"); iter = create_xml_node(iter, "lrm_resources"); iter = create_xml_node(iter, "lrm_resource"); set_xml_property_copy(iter, XML_ATTR_ID, rsc->id); set_xml_property_copy(iter, "last_op", op_type); char *tmp = crm_itoa(status); set_xml_property_copy(iter, "op_status", tmp); cl_free(tmp); tmp = crm_itoa(rc); set_xml_property_copy(iter, "op_code", tmp); cl_free(tmp); - send_cib_lrm_update(update, FALSE); - free_xml(update); + + xmlNodePtr fragment, tmp1; + + tmp1 = create_xml_node(NULL, XML_CIB_TAG_STATE); + set_xml_property_copy(tmp1, XML_ATTR_ID, fsa_our_uname); + add_node_copy(tmp1, update); -} + fragment = create_cib_fragment(tmp1, NULL); + + send_request(NULL, fragment, CRM_OPERATION_UPDATE, + NULL, CRM_SYSTEM_DCIB); + free_xml(fragment); + free_xml(update); + free_xml(tmp1); +} enum crmd_fsa_input do_lrm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data) { FNIN(); if(cause == C_LRM_MONITOR_CALLBACK) { lrm_mon_t* monitor = (lrm_mon_t*)data; lrm_rsc_t* rsc = monitor->rsc; switch(monitor->status) { case LRM_OP_DONE: CRM_DEBUG("An LRM monitor operation passed"); FNRET(I_NULL); break; case LRM_OP_CANCELLED: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: case LRM_OP_ERROR: cl_log(LOG_ERR, "An LRM monitor operation failed" " or was aborted"); do_update_resource(rsc, monitor->status, monitor->rc, monitor->op_type); break; } } else if(cause == C_LRM_OP_CALLBACK) { lrm_op_t* op = (lrm_op_t*)data; lrm_rsc_t* rsc = op->rsc; switch(op->status) { case LRM_OP_CANCELLED: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: case LRM_OP_ERROR: cl_log(LOG_ERR, "An LRM operation failed" " or was aborted"); // keep going case LRM_OP_DONE: do_update_resource(rsc, op->status, op->rc, op->op_type); break; } } else { FNRET(I_FAIL); } FNRET(I_NULL); } -/* - * If lrm_replace is TRUE, then we keep the update local - * (Ie. we dont send it to the DC) because that will be handled by - * another part of the JoinProtocol at the correct point. - */ -void send_cib_lrm_update(xmlNodePtr update, gboolean lrm_replace) -{ - xmlNodePtr fragment, tmp1, tmp2; - - 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); - - if(lrm_replace) { - tmp2 = create_xml_node(tmp1, "lrm"); - process_cib_request(CRM_OPERATION_DELETE, NULL, fragment); - - free_xml(tmp2); - - add_node_copy(tmp1, update); - - process_cib_request(CRM_OPERATION_UPDATE, NULL, fragment); - - } else { - add_node_copy(tmp1, update); - - send_cib_status_update(tmp1); - } - - free_xml(fragment); - free_xml(tmp1); -} - - -void send_cib_status_update(xmlNodePtr update) -{ - xmlNodePtr answer; - xmlNodePtr fragment = create_cib_fragment(update, NULL); - xmlNodePtr options = create_xml_node(NULL, XML_TAG_OPTIONS); - set_xml_property_copy(options, XML_ATTR_VERBOSE, "true"); - - // set verbose - answer = process_cib_request(CRM_OPERATION_UPDATE, options, fragment); - - // distribute the answer - if(AM_I_DC) { - - xmlNodePtr new_options = - set_xml_attr(NULL, XML_TAG_OPTIONS, - XML_ATTR_FILTER_TYPE, XML_CIB_TAG_STATUS, - TRUE); - - free_xml(answer); - answer = process_cib_request(CRM_OPERATION_BUMP, - new_options, - NULL); - - free_xml(new_options); - - if(answer == NULL) { - cl_log(LOG_ERR, "Result of BUMP in %s was NULL", - __FUNCTION__); - } else { - send_request(NULL, answer, CRM_OPERATION_REPLACE, - NULL, CRM_SYSTEM_CRMD); - } - - } else { - send_request(NULL, answer, - CRM_OPERATION_UPDATE, - NULL, CRM_SYSTEM_DCIB); - - } - - free_xml(fragment); - free_xml(answer); -}