diff --git a/crm/cib/primatives.c b/crm/cib/primatives.c index 5eeb3ad7de..bc2e3b8f09 100644 --- a/crm/cib/primatives.c +++ b/crm/cib/primatives.c @@ -1,601 +1,571 @@ -/* $Id: primatives.c,v 1.1 2004/09/15 09:16:55 andrew Exp $ */ +/* $Id: primatives.c,v 1.2 2004/09/21 19:40:18 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 /* * 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_verbose("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; root = get_object_root(XML_CIB_TAG_RESOURCES, cib); ret = find_entity(root, XML_CIB_TAG_RESOURCE, id, FALSE); return 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_verbose("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_verbose("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_verbose("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; root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib); ret = find_entity(root, XML_CIB_TAG_CONSTRAINT, id, FALSE); return 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_verbose("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_verbose("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_verbose("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; root = get_object_root(XML_CIB_TAG_NODES, cib); ret = find_entity(root, XML_CIB_TAG_NODE, id, FALSE); return 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_verbose("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_verbose("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_verbose("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); return 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_verbose("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_verbose("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; 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); 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(delete_spec->children == NULL) { /* only leaves are deleted */ unlink_xml_node(equiv_node); free_xml(equiv_node); } else { xml_child_iter( delete_spec, child, NULL, int tmp_result = delete_cib_object(equiv_node, child); /* only the first error is likely to be interesting */ if(tmp_result != CIBRES_OK && result == CIBRES_OK) { result = tmp_result; } ); } 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; 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); 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 *replace = NULL; const char *object_name = NULL; const char *object_id = NULL; xmlNodePtr equiv_node = 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); crm_debug("Processing update to <%s id=%s>", object_name, object_id); 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) { crm_debug("No node to update, creating %s instead", new_obj->name); if(parent == NULL) { crm_warn("Failed to add <%s id=%s> (NULL parent)", object_name, object_id); return CIBRES_FAILED_NODECOPY; } else if(add_node_copy(parent, new_obj) == NULL) { crm_warn("Failed to add <%s id=%s>", object_name, object_id); return CIBRES_FAILED_NODECOPY; } else { crm_debug("Added <%s id=%s>", object_name, object_id); 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); } } } else { crm_verbose("Found node <%s id=%s> to update", object_name, object_id); replace = xmlGetProp(new_obj, "replace"); - 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) { - crm_err( - "Ignoring old update to <%s id=\"%s\">" - "(%s vs. %s)", - object_name, object_id, - ts_new, ts_existing); - return CIBRES_FAILED_STALE; - } - } - if(replace != NULL) { xmlNodePtr remove = find_xml_node(equiv_node, replace); if(remove != NULL) { crm_debug("Replacing node <%s> in <%s>", replace, equiv_node->name); xmlUnlinkNode(remove); remove->doc = NULL; free_xml(remove); } xmlUnsetProp(new_obj, "replace"); xmlUnsetProp(equiv_node, "replace"); } 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); } crm_debug("Processing children of <%s id=%s>", object_name, object_id); xml_child_iter( new_obj, a_child, NULL, int tmp_result = 0; crm_debug("Updating child <%s id=%s>", a_child->name, xmlGetProp(a_child, XML_ATTR_ID)); tmp_result = update_cib_object(equiv_node, a_child, force); /* only the first error is likely to be interesting */ if(tmp_result != CIBRES_OK) { crm_err("Error updating child <%s id=%s>", a_child->name, xmlGetProp(a_child, XML_ATTR_ID)); if(result == CIBRES_OK) { result = tmp_result; } } ); } crm_debug("Finished with <%s id=%s>", object_name, object_id); return result; } void update_node_state(xmlNodePtr target, xmlNodePtr update) { const char *source = NULL; xmlAttrPtr prop_iter = NULL; gboolean any_updates = FALSE; gboolean clear_stonith = FALSE; gboolean clear_shutdown = FALSE; 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, XML_ATTR_ID) == 0) { } else if(strcmp(local_prop_name, XML_ATTR_TSTAMP) == 0) { } else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_SHUTDOWN) == 0) { clear_shutdown = TRUE; } else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_STONITH) == 0) { clear_stonith = TRUE; clear_shutdown = TRUE; } else if(strcmp(local_prop_name, "source") == 0) { source = local_prop_value; } else { any_updates = TRUE; set_xml_property_copy(target, local_prop_name, local_prop_value); } prop_iter = prop_iter->next; } if(clear_shutdown) { /* unset XML_CIB_ATTR_SHUTDOWN */ crm_verbose("Clearing %s", XML_CIB_ATTR_SHUTDOWN); xmlUnsetProp(target, XML_CIB_ATTR_SHUTDOWN); any_updates = TRUE; } if(clear_stonith) { /* unset XML_CIB_ATTR_STONITH */ crm_verbose("Clearing %s", XML_CIB_ATTR_STONITH); xmlUnsetProp(target, XML_CIB_ATTR_STONITH); any_updates = TRUE; } if(any_updates) { set_node_tstamp(target); set_xml_property_copy(target, "source", source); } } diff --git a/crm/crmd/Makefile.am b/crm/crmd/Makefile.am index 05af9ea6af..9e34441c74 100644 --- a/crm/crmd/Makefile.am +++ b/crm/crmd/Makefile.am @@ -1,94 +1,95 @@ # # 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 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl \ -I$(top_builddir)/linux-ha -I$(top_srcdir)/linux-ha \ -I$(top_builddir) -I$(top_srcdir) hadir = $(sysconfdir)/ha.d halibdir = $(libdir)/@HB_PKG@ commmoddir = $(halibdir)/modules/comm havarlibdir = $(localstatedir)/lib/@HB_PKG@ PIDFILE = $(localstatedir)/run/crmd.pid XML_FLAGS = `xml2-config --cflags` XML_LIBS = `xml2-config --libs` # sockets with path crmdir = $(havarlibdir)/crm apigid = @HA_APIGID@ crmuid = @HA_CCMUID@ COMMONLIBS = $(CRM_DEBUG_LIBS) \ $(top_builddir)/lib/clplumbing/libplumb.la \ $(top_builddir)/$(CRM_DIR)/common/libcrmcommon.la \ $(top_builddir)/$(CRM_DIR)/cib/libcib.la \ $(top_builddir)/lib/apphb/libapphb.la \ $(top_builddir)/lib/hbclient/libhbclient.la \ $(GLIBLIB) \ $(LIBRT) LIBRT = @LIBRT@ AM_CFLAGS = @CFLAGS@ \ -DPIDFILE='"$(PIDFILE)"' \ $(CRM_DEBUG_FLAGS) ## libraries lib_LTLIBRARIES = ## binary progs halib_PROGRAMS = crmd ## SOURCES noinst_HEADERS = crmd.h crmd_fsa.h crmd_messages.h fsa_defines.h \ fsa_matrix.h fsa_proto.h crmd_utils.h crmd_callbacks.h crmd_SOURCES = main.c crmd.c \ fsa.c control.c messages.c ccm.c callbacks.c \ - election.c subsystems.c lrm.c join.c utils.c misc.c + election.c subsystems.c lrm.c join_client.c join_dc.c \ + utils.c misc.c crmd_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crmd_LDFLAGS = $(XML_LIBS) crmd_LDADD = $(COMMONLIBS) \ $(top_builddir)/$(CRM_DIR)/cib/libcib.la \ $(top_builddir)/lib/lrm/liblrm.la \ $(top_builddir)/membership/ccm/libccmclient.la # Simple HA client app #clnt_SOURCES = clnt.c #clnt_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' #clnt_LDFLAGS = $(XML_LIBS) #clnt_LDADD = $(COMMONLIBS) clean-generic: rm -f *.log *.debug *.xml *~ install-exec-local: uninstall-local: graphs: fsa_inputs.png fsa_inputs_by_action.png fsa_actions_by_state.png %.png: %.dot dot -Tpng $< > $@ %.dot : fsa_matrix.h perl make_dot.pl diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c index cd52e8191e..c46157c923 100644 --- a/crm/crmd/ccm.c +++ b/crm/crmd/ccm.c @@ -1,580 +1,581 @@ -/* $Id: ccm.c,v 1.34 2004/09/17 13:03:09 andrew Exp $ */ +/* $Id: ccm.c,v 1.35 2004/09/21 19:40:18 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 */ /* put these first so that uuid_t is defined without conflicts */ #include #include #include #include #include #include #include #include #include #include #include #include #include void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); int register_with_ccm(ll_cluster_t *hb_cluster); void msg_ccm_join(const struct ha_msg *msg, void *foo); void crmd_ccm_input_callback(oc_ed_t event, void *cookie, size_t size, const void *data); void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event); gboolean ccm_dispatch(int fd, gpointer user_data); gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data); void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data); #define CCM_EVENT_DETAIL 1 oc_ev_t *fsa_ev_token; /* A_CCM_CONNECT */ enum crmd_fsa_input do_ccm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { int ret; int fsa_ev_fd; if(action & A_CCM_DISCONNECT){ oc_ev_unregister(fsa_ev_token); } if(action & A_CCM_CONNECT) { crm_info("Registering with CCM"); oc_ev_register(&fsa_ev_token); crm_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*/); crm_info("Activating CCM token"); ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd); if (ret){ crm_info("CCM Activation failed... unregistering"); oc_ev_unregister(fsa_ev_token); return(I_FAIL); } crm_info("CCM Activation passed... all set to go!"); /* GFDSource* */ G_main_add_fd(G_PRIORITY_LOW, fsa_ev_fd, FALSE, ccm_dispatch, fsa_ev_token, default_ipc_input_destroy); } if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return 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; crm_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; + if(oc->m_n_out != 0) { + /* delay this until the CIB update to be interpreted by the TE */ + return_input = I_NULL; } 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 { crm_warn("So why are we here? What CCM event happened?"); } } return return_input; } /* A_CCM_UPDATE_CACHE */ /* * Take the opportunity to update the node status in the CIB as well * (but only if we are the DC) */ enum crmd_fsa_input do_ccm_update_cache(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input next_input = I_NULL; int lpc, offset; GHashTable *members = NULL; oc_ed_t event = *((struct ccm_data *)data)->event; const oc_ev_membership_t *oc = ((struct ccm_data *)data)->oc; oc_node_list_t *tmp = NULL, *membership_copy = NULL; crm_malloc(membership_copy, sizeof(oc_node_list_t)); crm_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"); if(membership_copy == NULL) { crm_crit("Couldnt create membership copy - out of memory"); return I_ERROR; } /*--*-- All Member Nodes --*--*/ offset = oc->m_memb_idx; membership_copy->members_size = oc->m_n_member; if(membership_copy->members_size > 0) { membership_copy->members = g_hash_table_new(g_str_hash, g_str_equal); members = membership_copy->members; for(lpc=0; lpc < membership_copy->members_size; lpc++) { oc_node_t *member = NULL; crm_malloc(member, sizeof(oc_node_t)); if(member == NULL) { continue; } member->node_id = oc->m_array[offset+lpc].node_id; member->node_born_on = oc->m_array[offset+lpc].node_born_on; member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); g_hash_table_insert(members, member->node_uname, member); } } else { membership_copy->members = NULL; } /*--*-- New Member Nodes --*--*/ offset = oc->m_in_idx; membership_copy->new_members_size = oc->m_n_in; if(membership_copy->new_members_size > 0) { membership_copy->new_members = g_hash_table_new(g_str_hash, g_str_equal); members = membership_copy->new_members; for(lpc=0; lpc < membership_copy->new_members_size; lpc++) { oc_node_t *member = NULL; crm_malloc(member, sizeof(oc_node_t)); if(member == NULL) { continue; } member->node_id = oc->m_array[offset+lpc].node_id; member->node_born_on = oc->m_array[offset+lpc].node_born_on; member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); g_hash_table_insert(members, member->node_uname, member); } } else { membership_copy->new_members = NULL; } /*--*-- Recently Dead Member Nodes --*--*/ offset = oc->m_out_idx; membership_copy->dead_members_size = oc->m_n_out; if(membership_copy->dead_members_size > 0) { membership_copy->dead_members = g_hash_table_new(g_str_hash, g_str_equal); members = membership_copy->dead_members; for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) { oc_node_t *member = NULL; crm_malloc(member, sizeof(oc_node_t)); if(member == NULL) { continue; } member->node_id = oc->m_array[offset+lpc].node_id; member->node_born_on = oc->m_array[offset+lpc].node_born_on; member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); g_hash_table_insert(members, member->node_uname, member); } } else { membership_copy->dead_members = NULL; } tmp = fsa_membership_copy; fsa_membership_copy = membership_copy; if(AM_I_DC) { /* should be sufficient for only the DC to do this */ free_xml(do_update_cib_nodes(NULL, FALSE)); } /* Free the old copy */ if(tmp != NULL) { if(tmp->members != NULL) g_hash_table_foreach_remove( tmp->members, ghash_node_clfree, NULL); if(tmp->new_members != NULL) g_hash_table_foreach_remove( tmp->new_members, ghash_node_clfree, NULL); if(tmp->dead_members != NULL) g_hash_table_foreach_remove( tmp->dead_members, ghash_node_clfree, NULL); crm_free(tmp); } return next_input; } void ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event) { int member_id = -1; gboolean member = FALSE; int lpc; int node_list_size; crm_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); crm_info("NODES IN THE PRIMARY MEMBERSHIP"); node_list_size = oc->m_n_member; for(lpc=0; lpcm_array[oc->m_memb_idx+lpc].node_uname, oc->m_array[oc->m_memb_idx+lpc].node_id, oc->m_array[oc->m_memb_idx+lpc].node_born_on); crm_verbose("%s ? %s", fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname); if(safe_str_eq(fsa_our_uname, oc->m_array[oc->m_memb_idx+lpc].node_uname)) { member = TRUE; member_id = oc->m_array[oc->m_memb_idx+lpc].node_id; } } if (member == FALSE) { crm_warn("MY NODE IS NOT IN CCM THE MEMBERSHIP LIST"); } else { crm_info("MY NODE ID IS %d", member_id); } crm_info("NEW MEMBERS"); if (oc->m_n_in==0) crm_info("\tNONE"); for(lpc=0; lpcm_n_in; lpc++) { crm_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); } crm_info("MEMBERS LOST"); if (oc->m_n_out==0) crm_info("\tNONE"); for(lpc=0; lpcm_n_out; lpc++) { crm_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)) { crm_err("We're not part of the cluster anymore"); } } crm_info("-----------------------"); } int register_with_ccm(ll_cluster_t *hb_cluster) { return 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; if(data != NULL) { crm_malloc(event_data, sizeof(struct ccm_data)); if(event_data != NULL) { event_data->event = &event; event_data->oc = (const oc_ev_membership_t *)data; s_crmd_fsa(C_CCM_CALLBACK, I_CCM_EVENT, (void*)event_data); event_data->event = NULL; event_data->oc = NULL; crm_free(event_data); } } else { crm_info("CCM Callback with NULL data... " "I dont /think/ this is bad"); } oc_ev_callback_done(cookie); return; } void msg_ccm_join(const struct ha_msg *msg, void *foo) { crm_verbose("\n###### Recieved ccm_join message..."); if (msg != NULL) { crm_verbose("[type=%s]", ha_msg_value(msg, F_TYPE)); crm_verbose("[orig=%s]", ha_msg_value(msg, F_ORIG)); crm_verbose("[to=%s]", ha_msg_value(msg, F_TO)); crm_verbose("[status=%s]", ha_msg_value(msg, F_STATUS)); crm_verbose("[info=%s]", ha_msg_value(msg, F_COMMENT)); crm_verbose("[rsc_hold=%s]", ha_msg_value(msg, F_RESOURCES)); crm_verbose("[stable=%s]", ha_msg_value(msg, F_ISSTABLE)); crm_verbose("[rtype=%s]", ha_msg_value(msg, F_RTYPE)); crm_verbose("[ts=%s]", ha_msg_value(msg, F_TIME)); crm_verbose("[seq=%s]", ha_msg_value(msg, F_SEQ)); crm_verbose("[generation=%s]", ha_msg_value(msg, F_HBGENERATION)); /* crm_verbose("[=%s]", ha_msg_value(msg, F_)); */ } return; } struct update_data_s { xmlNodePtr updates; const char *state; const char *join; }; xmlNodePtr do_update_cib_nodes(xmlNodePtr updates, gboolean overwrite) { struct update_data_s update_data; update_data.updates = updates; update_data.state = XML_BOOLEAN_NO; update_data.join = CRMD_JOINSTATE_DOWN; if(fsa_membership_copy->dead_members != NULL) { g_hash_table_foreach(fsa_membership_copy->dead_members, ghash_update_cib_node, &update_data); } update_data.state = XML_BOOLEAN_YES; update_data.join = NULL; if(overwrite) { update_data.join = CRMD_JOINSTATE_PENDING; } if(fsa_membership_copy->members != NULL) { g_hash_table_foreach(fsa_membership_copy->members, ghash_update_cib_node, &update_data); } /* this is most likely overkill... * * make *sure* that the join status of nodes entering the ccm list * is reset * update_data.join = CRMD_JOINSTATE_PENDING; if(fsa_membership_copy->new_members != NULL) { g_hash_table_foreach(fsa_membership_copy->new_members, ghash_update_cib_node, &update_data); } */ if(update_data.updates != NULL) { xmlNodePtr fragment = create_cib_fragment(update_data.updates, NULL); invoke_local_cib(NULL, fragment, CRM_OP_UPDATE); free_xml(fragment); } /* so it can be freed */ return update_data.updates; } void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data) { xmlNodePtr tmp1 = NULL; const char *node_uname = (const char*)key; struct update_data_s* data = (struct update_data_s*)user_data; const char *state = data->join; crm_verbose("%s processing %s (%s)", __FUNCTION__, node_uname, data->state); if(state != NULL && safe_str_eq(fsa_our_uname, node_uname)) { /* the DC is always a member */ state = CRMD_JOINSTATE_MEMBER; } tmp1 = create_node_state(node_uname, node_uname, data->state, NULL, state); if(data->updates == NULL) { crm_verbose("Creating first update"); data->updates = tmp1; } else { xmlAddNextSibling(data->updates, tmp1); } } gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data) { /* value->node_uname is free'd as "key" */ if(key != NULL) { crm_free(key); } if(value != NULL) { crm_free(value); } return TRUE; } diff --git a/crm/crmd/election.c b/crm/crmd/election.c index 35890840a6..333af7e196 100644 --- a/crm/crmd/election.c +++ b/crm/crmd/election.c @@ -1,411 +1,371 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include void ghash_count_vote(gpointer key, gpointer value, gpointer user_data); /* A_ELECTION_VOTE */ enum crmd_fsa_input do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { gboolean not_voting = FALSE; xmlNodePtr msg_options = NULL; enum crmd_fsa_input election_result = I_NULL; /* dont vote if we're in one of these states or wanting to shut down */ switch(cur_state) { case S_RECOVERY: - case S_RECOVERY_DC: case S_STOPPING: case S_RELEASE_DC: case S_TERMINATE: crm_warn("Not voting in election, we're in state %s", fsa_state2string(cur_state)); not_voting = TRUE; break; default: if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_warn("Not voting in election," " we're shutting down"); not_voting = TRUE; } break; } if(not_voting) { stopTimer(election_timeout); if(AM_I_DC) { return I_RELEASE_DC; } else { return I_NOT_DC; } } msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); set_xml_property_copy(msg_options, XML_ATTR_VERSION, CRM_VERSION); send_request(msg_options, NULL, CRM_OP_VOTE, NULL, CRM_SYSTEM_CRMD, NULL); return election_result; } gboolean do_dc_heartbeat(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; gboolean was_sent = send_request(NULL, NULL, CRM_OP_HBEAT, NULL, CRM_SYSTEM_CRMD, NULL); /* crm_debug("#!!#!!# Heartbeat timer just popped!"); */ if(was_sent == FALSE) { /* this is bad */ stopTimer(timer); /* dont make it go off again */ s_crmd_fsa(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL); } return TRUE; } struct election_data_s { const char *winning_uname; unsigned int winning_bornon; }; /* A_ELECTION_COUNT */ enum crmd_fsa_input do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { gboolean we_loose = FALSE; xmlNodePtr vote = (xmlNodePtr)data; enum crmd_fsa_input election_result = I_NULL; const char *vote_from = xmlGetProp(vote, XML_ATTR_HOSTFROM); const char *your_version = get_xml_attr( vote, XML_TAG_OPTIONS, XML_ATTR_VERSION, TRUE); oc_node_t *our_node = NULL, * your_node = NULL; struct election_data_s election_data; if(vote_from == NULL || strcmp(vote_from, fsa_our_uname) == 0) { /* dont count our own vote */ return election_result; } if(fsa_membership_copy->members_size < 1) { /* if even we are not in the cluster then we should not vote */ return I_FAIL; } our_node = (oc_node_t*) g_hash_table_lookup(fsa_membership_copy->members, fsa_our_uname); your_node = (oc_node_t*) g_hash_table_lookup(fsa_membership_copy->members, vote_from); #if 0 crm_debug("%s (bornon=%d), our bornon (%d)", vote_from, our_node->born, my_born); crm_debug("%s %s %s", fsa_our_uname, strcmp(fsa_our_uname, vote_from) < 0?"<":">=", vote_from); #endif if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_debug("Election fail: we are shutting down"); we_loose = TRUE; } else if(our_node == NULL) { crm_debug("Election fail: we dont exist in the CCM list"); we_loose = TRUE; } else if(your_node == NULL) { crm_err("The other side doesnt exist in the CCM list"); } else if(compare_version(your_version, CRM_VERSION) > 0) { crm_debug("Election fail: version"); we_loose = TRUE; } else if(your_node->node_born_on < our_node->node_born_on) { crm_debug("Election fail: born_on"); we_loose = TRUE; } else if(your_node->node_born_on == our_node->node_born_on && strcmp(fsa_our_uname, vote_from) > 0) { crm_debug("Election fail: uname"); we_loose = TRUE; } else { election_data.winning_uname = NULL; election_data.winning_bornon = -1; /* maximum integer */ crm_trace("We might win... we should vote (possibly again)"); - election_result = I_DC_TIMEOUT; /* new "default" */ - -#if 0 - /* we dont try to predict the winner anymore */ - g_hash_table_foreach(fsa_membership_copy->members, - ghash_count_vote, &election_data); - - crm_debug("Election winner should be %s (born_on=%d)", - election_data.winning_uname, election_data.winning_bornon); - - - if(safe_str_eq(election_data.winning_uname, fsa_our_uname)){ - crm_debug("Election win: lowest born_on and uname"); - election_result = I_ELECTION_DC; - } -#endif + election_result = I_VOTE; /* new "default" */ } if(we_loose) { if(fsa_input_register & R_THE_DC) { crm_debug("Give up the DC"); election_result = I_RELEASE_DC; } else { crm_debug("We werent the DC anyway"); election_result = I_NOT_DC; } } if(we_loose || election_result == I_ELECTION_DC) { /* cancel timer, its been decided */ stopTimer(election_timeout); } return election_result; } /* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */ /* we won */ enum crmd_fsa_input do_election_timer_ctrl(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { if(action & A_ELECT_TIMER_START) { startTimer(election_timeout); } else if(action & A_ELECT_TIMER_STOP || action & A_ELECTION_TIMEOUT) { stopTimer(election_timeout); } else { crm_err("unexpected action %s", fsa_action2string(action)); } if(action & A_ELECTION_TIMEOUT) { crm_trace("The election timer went off, we win!"); return I_ELECTION_DC; } return I_NULL; } /* A_DC_TIMER_STOP, A_DC_TIMER_START */ enum crmd_fsa_input do_dc_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { gboolean timer_op_ok = TRUE; if(action & A_DC_TIMER_STOP) { timer_op_ok = stopTimer(election_trigger); } /* dont start a timer that wasnt already running */ if(action & A_DC_TIMER_START && timer_op_ok) { startTimer(election_trigger); } return I_NULL; } /* A_DC_TAKEOVER */ enum crmd_fsa_input do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { - xmlNodePtr update = NULL, fragment = NULL; - - crm_trace("################## Taking over the DC ##################"); set_bit_inplace(&fsa_input_register, R_THE_DC); crm_verbose("Am I the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO); fsa_our_dc = NULL; set_bit_inplace(&fsa_input_register, R_JOIN_OK); set_bit_inplace(&fsa_input_register, R_INVOKE_PE); clear_bit_inplace(&fsa_input_register, R_CIB_DONE); clear_bit_inplace(&fsa_input_register, R_HAVE_CIB); startTimer(dc_heartbeat); - if (fsa_cluster_conn->llc_ops->set_cstatus_callback( - fsa_cluster_conn, crmd_client_status_callback, NULL)!=HA_OK){ + if (HA_OK != fsa_cluster_conn->llc_ops->set_cstatus_callback( + fsa_cluster_conn, crmd_client_status_callback, NULL)) { crm_err("Cannot set client status callback\n"); crm_err("REASON: %s\n", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); } - /* just in case */ - create_node_entry(fsa_our_uname, fsa_our_uname, "member"); - - /* store our state in the CIB (since some fields will not be - * filled in because the DC doesnt go through the join process - * with itself - * - * bypass the TE for now, it will be informed in good time - */ - update = create_node_state( - fsa_our_uname, fsa_our_uname, - NULL, ONLINESTATUS, CRMD_JOINSTATE_MEMBER); - set_xml_property_copy( - update,XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE); - - fragment = create_cib_fragment(update, NULL); - invoke_local_cib(NULL, fragment, CRM_OP_UPDATE); - - free_xml(update); - free_xml(fragment); - /* Async get client status information in the cluster */ fsa_cluster_conn->llc_ops->client_status( fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1); return I_NULL; } /* A_DC_RELEASE */ enum crmd_fsa_input do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; crm_trace("################## Releasing the DC ##################"); stopTimer(dc_heartbeat); if (fsa_cluster_conn->llc_ops->set_cstatus_callback( fsa_cluster_conn, NULL, NULL)!=HA_OK){ crm_err("Cannot unset client status callback\n"); crm_err("REASON: %s\n", fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn)); result = I_ERROR; } if(action & A_DC_RELEASE) { clear_bit_inplace(&fsa_input_register, R_THE_DC); /* get a new CIB from the new DC */ clear_bit_inplace(&fsa_input_register, R_HAVE_CIB); } else if (action & A_DC_RELEASED) { if(cur_state == S_STOPPING) { result = I_SHUTDOWN; /* necessary? */ result = I_RELEASE_SUCCESS; } #if 0 else if( are there errors ) { /* we cant stay up if not healthy */ /* or perhaps I_ERROR and go to S_RECOVER? */ result = I_SHUTDOWN; } #endif else result = I_RELEASE_SUCCESS; } else { crm_err("Warning, do_dc_release invoked for action %s", fsa_action2string(action)); } crm_verbose("Am I still the DC? %s", AM_I_DC?XML_BOOLEAN_YES:XML_BOOLEAN_NO); return result; } void ghash_count_vote(gpointer key, gpointer value, gpointer user_data) { struct election_data_s *election_data = (struct election_data_s *)user_data; oc_node_t *cur_node = (oc_node_t*)value; const char *node_uname = (const char*)key; if(election_data->winning_bornon > cur_node->node_born_on) { election_data->winning_uname = node_uname; election_data->winning_bornon = cur_node->node_born_on; } else if(election_data->winning_bornon == cur_node->node_born_on && (election_data->winning_uname == NULL || strcmp(election_data->winning_uname, node_uname) > 0)) { election_data->winning_uname = node_uname; election_data->winning_bornon = cur_node->node_born_on; } } diff --git a/crm/crmd/fsa.c b/crm/crmd/fsa.c index 8c5b449dd8..b4efbb9aee 100644 --- a/crm/crmd/fsa.c +++ b/crm/crmd/fsa.c @@ -1,690 +1,685 @@ /* * 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 -extern GHashTable *joined_nodes; +extern int num_join_invites; 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 clear_flags(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input); void dump_rsc_info(void); #ifdef DOT_FSA_ACTIONS # ifdef FSA_TRACE # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ crm_verbose("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %p)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data, \ fsa_input2string(next_input)); \ fflush(dot_strm); \ crm_verbose("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, \ "\t// %s:\t%s\t(data? %p)\t(result=%s)\n", \ fsa_input2string(cur_input), \ fsa_action2string(x), \ data, \ fsa_input2string(next_input)); \ fflush(dot_strm); \ } # endif #else # ifdef FSA_TRACE # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ crm_verbose("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ crm_verbose("Result of action %s was %s", \ fsa_action2string(x), fsa_input2string(next_input)); \ } # else # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ last_action = x; \ actions = clear_bit(actions, x); \ next_input = y(x, cause, cur_state, last_input, data); \ } # endif #endif /* #define ELSEIF_FSA_ACTION(x,y) else IF_FSA_ACTION(x,y) */ const char *dot_intro = "digraph \"g\" {\n" " size = \"30,30\"\n" " graph [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " bb = \"0,0,398.922306,478.927856\"\n" " color = \"black\"\n" " ]\n" " node [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " shape = \"ellipse\"\n" " color = \"black\"\n" " ]\n" " edge [\n" " fontsize = \"12\"\n" " fontname = \"Times-Roman\"\n" " fontcolor = \"black\"\n" " color = \"black\"\n" " ]\n" "// special nodes\n" " \"S_PENDING\" \n" " [\n" " color = \"blue\"\n" " fontcolor = \"blue\"\n" " ]\n" " \"S_TERMINATE\" \n" " [\n" " color = \"red\"\n" " fontcolor = \"red\"\n" " ]\n" "\n" "// DC only nodes\n" " \"S_RECOVERY_DC\" [ fontcolor = \"green\" ]\n" " \"S_INTEGRATION\" [ fontcolor = \"green\" ]\n" " \"S_POLICY_ENGINE\" [ fontcolor = \"green\" ]\n" " \"S_TRANSITION_ENGINE\" [ fontcolor = \"green\" ]\n" " \"S_RELEASE_DC\" [ fontcolor = \"green\" ]\n" " \"S_IDLE\" [ fontcolor = \"green\" ]\n"; static FILE *dot_strm = NULL; enum crmd_fsa_state fsa_state; oc_node_list_t *fsa_membership_copy; ll_cluster_t *fsa_cluster_conn; ll_lrm_t *fsa_lrm_conn; long long fsa_input_register; long long fsa_actions = A_NOTHING; const char *fsa_our_uname; const char *fsa_our_dc; fsa_timer_t *election_trigger = NULL; /* */ fsa_timer_t *election_timeout = NULL; /* */ fsa_timer_t *shutdown_escalation_timmer = NULL; /* */ fsa_timer_t *integration_timer = NULL; fsa_timer_t *dc_heartbeat = NULL; enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause, enum crmd_fsa_input initial_input, void *data) { long long actions = fsa_actions; long long new_actions = A_NOTHING; long long last_action = A_NOTHING; enum crmd_fsa_input last_input = initial_input; enum crmd_fsa_input cur_input; enum crmd_fsa_input next_input; enum crmd_fsa_state last_state, cur_state, next_state, starting_state; - - starting_state = fsa_state; cur_input = initial_input; next_input = initial_input; last_state = starting_state; cur_state = starting_state; next_state = starting_state; #ifdef FSA_TRACE crm_verbose("FSA invoked with Cause: %s\tState: %s, Input: %s", fsa_cause2string(cause), fsa_state2string(cur_state), fsa_input2string(cur_input)); #endif #ifdef DOT_FSA_ACTIONS if(dot_strm == NULL) { dot_strm = fopen(DEVEL_DIR"/live.dot", "w"); fprintf(dot_strm, "%s", dot_intro); } fprintf(dot_strm, "\t// FSA invoked: Cause=%s\tState=%s\tInput=%s\n", fsa_cause2string(cause), fsa_state2string(cur_state), fsa_input2string(cur_input)); fflush(dot_strm); #endif /* * Process actions in order of priority but do only one * action at a time to avoid complicating the ordering. * * Actions may result in a new I_ event, these are added to * (not replace) existing actions before the next iteration. * */ while(next_input != I_NULL || actions != A_NOTHING || is_message()) { if(next_input == I_WAIT_FOR_EVENT) { /* we may be waiting for an a-sync task to "happen" * and until it does, we cant do anything else * * Re-add the last action */ actions |= last_action; crm_info("Wait until something else happens"); break; } #ifdef FSA_TRACE crm_verbose("FSA while loop:\tState: %s, Input: %s", fsa_state2string(cur_state), fsa_input2string(cur_input)); #endif /* update input variables */ cur_input = next_input; if(cur_input != I_NULL) { + /* record the most recent non I_NULL input */ last_input = cur_input; } /* get the next batch of actions */ new_actions = crmd_fsa_actions[cur_input][cur_state]; if(new_actions != A_NOTHING) { #ifdef FSA_TRACE crm_verbose("Adding actions %.16llx", new_actions); #endif actions |= new_actions; } + /* logging : *before* the state is changed */ IF_FSA_ACTION(A_ERROR, do_log) else IF_FSA_ACTION(A_WARN, do_log) else IF_FSA_ACTION(A_LOG, do_log) /* update state variables */ next_state = crmd_fsa_state[cur_input][cur_state]; last_state = cur_state; cur_state = next_state; fsa_state = next_state; /* start doing things... */ - /* * Hook for change of state. * Allows actions to be added or removed when entering a state */ if(last_state != cur_state){ actions = do_state_transition(actions, cause, last_state, cur_state, last_input, data); } /* this is always run, some inputs/states may make various * actions irrelevant/invalid */ actions = clear_flags(actions, cause, cur_state, cur_input); /* regular action processing in order of action priority * * Make sure all actions that connect to required systems * are performed first */ if(actions == A_NOTHING) { - - crm_info("Nothing to do"); + crm_debug("Nothing to do"); next_input = I_NULL; - -/* // check registers, see if anything is pending - if(is_set(fsa_input_register, R_SHUTDOWN)) { - crm_verbose("(Re-)invoking shutdown"); - next_input = I_SHUTDOWN; - } else if(is_set(fsa_input_register, R_INVOKE_PE)) { - crm_verbose("Invoke the PE somehow"); - } -*/ } - /* get out of here NOW! before anything worse happens */ - else IF_FSA_ACTION(A_EXIT_1, do_exit) - - else IF_FSA_ACTION(A_STARTUP, do_startup) - - else IF_FSA_ACTION(A_CIB_START, do_cib_control) + else IF_FSA_ACTION(A_EXIT_1, do_exit) + else IF_FSA_ACTION(A_STARTUP, do_startup) + + else IF_FSA_ACTION(A_CIB_START, do_cib_control) else IF_FSA_ACTION(A_READCONFIG, do_read_config) - else IF_FSA_ACTION(A_HA_CONNECT, do_ha_control) - else IF_FSA_ACTION(A_LRM_CONNECT,do_lrm_control) - else IF_FSA_ACTION(A_CCM_CONNECT,do_ccm_control) + else IF_FSA_ACTION(A_HA_CONNECT, do_ha_control) + else IF_FSA_ACTION(A_LRM_CONNECT, do_lrm_control) + else IF_FSA_ACTION(A_CCM_CONNECT, do_ccm_control) /* sub-system start */ - else IF_FSA_ACTION(A_TE_START, do_te_control) - else IF_FSA_ACTION(A_PE_START, do_pe_control) + else IF_FSA_ACTION(A_TE_START, do_te_control) + else IF_FSA_ACTION(A_PE_START, do_pe_control) /* sub-system restart */ - else IF_FSA_ACTION(O_CIB_RESTART,do_cib_control) - else IF_FSA_ACTION(O_PE_RESTART, do_pe_control) - else IF_FSA_ACTION(O_TE_RESTART, do_te_control) - - else IF_FSA_ACTION(A_STARTED, do_started) + else IF_FSA_ACTION(O_CIB_RESTART, do_cib_control) + else IF_FSA_ACTION(O_PE_RESTART, do_pe_control) + else IF_FSA_ACTION(O_TE_RESTART, do_te_control) + else IF_FSA_ACTION(A_STARTED, do_started) /* DC Timer */ else IF_FSA_ACTION(O_DC_TIMER_RESTART, do_dc_timer_control) else IF_FSA_ACTION(A_DC_TIMER_STOP, do_dc_timer_control) else IF_FSA_ACTION(A_DC_TIMER_START, do_dc_timer_control) /* * Highest priority actions */ /* the order of these is finiky... * the status section seems to dissappear after the BUMPGEN!!! * Yet BUMPGEN is non-destructive */ else IF_FSA_ACTION(A_TE_COPYTO, do_te_copyto) else IF_FSA_ACTION(A_CIB_BUMPGEN, do_cib_invoke) else IF_FSA_ACTION(A_MSG_ROUTE, do_msg_route) else IF_FSA_ACTION(A_RECOVER, do_recover) - else IF_FSA_ACTION(A_UPDATE_NODESTATUS, do_update_node_status) - else IF_FSA_ACTION(A_JOIN_ACK, do_ack_welcome) + else IF_FSA_ACTION(A_CL_JOIN_REQUEST, do_cl_join_request) + else IF_FSA_ACTION(A_CL_JOIN_RESULT, do_cl_join_result) else IF_FSA_ACTION(A_SHUTDOWN_REQ, do_shutdown_req) else IF_FSA_ACTION(A_ELECTION_VOTE, do_election_vote) else IF_FSA_ACTION(A_ELECT_TIMER_STOP, do_election_timer_ctrl) else IF_FSA_ACTION(A_ELECT_TIMER_START, do_election_timer_ctrl) else IF_FSA_ACTION(A_ELECTION_COUNT, do_election_count_vote) else IF_FSA_ACTION(A_ELECTION_TIMEOUT, do_election_timer_ctrl) /* * "Get this over with" actions */ else IF_FSA_ACTION(A_MSG_STORE, do_msg_store) /* * High priority actions * Update the cache first */ else IF_FSA_ACTION(A_CCM_UPDATE_CACHE, do_ccm_update_cache) else IF_FSA_ACTION(A_CCM_EVENT, do_ccm_event) /* * Medium priority actions */ - else IF_FSA_ACTION(A_DC_TAKEOVER, do_dc_takeover) - else IF_FSA_ACTION(A_DC_RELEASE, do_dc_release) - else IF_FSA_ACTION(A_JOIN_WELCOME_ALL, do_send_welcome_all) - else IF_FSA_ACTION(A_JOIN_WELCOME, do_send_welcome) - else IF_FSA_ACTION(A_JOIN_PROCESS_ACK, do_process_welcome_ack) + else IF_FSA_ACTION(A_DC_TAKEOVER, do_dc_takeover) + else IF_FSA_ACTION(A_DC_RELEASE, do_dc_release) + else IF_FSA_ACTION(A_DC_JOIN_OFFER_ALL, do_dc_join_offer_all) + else IF_FSA_ACTION(A_DC_JOIN_OFFER_ONE, do_dc_join_offer_one) + else IF_FSA_ACTION(A_DC_JOIN_PROCESS_REQ,do_dc_join_req) + else IF_FSA_ACTION(A_DC_JOIN_PROCESS_ACK,do_dc_join_ack) + else IF_FSA_ACTION(A_DC_JOIN_FINALIZE, do_dc_join_finalize) /* * Low(er) priority actions * Make sure the CIB is always updated before invoking the * PE, and the PE before the TE */ else IF_FSA_ACTION(A_CIB_INVOKE_LOCAL, do_cib_invoke) - else IF_FSA_ACTION(A_CIB_INVOKE, do_cib_invoke) - else IF_FSA_ACTION(A_LRM_INVOKE, do_lrm_invoke) + else IF_FSA_ACTION(A_CIB_INVOKE, do_cib_invoke) + else IF_FSA_ACTION(A_LRM_INVOKE, do_lrm_invoke) else IF_FSA_ACTION(A_LRM_EVENT, do_lrm_event) else IF_FSA_ACTION(A_TE_CANCEL, do_te_invoke) else IF_FSA_ACTION(A_PE_INVOKE, do_pe_invoke) else IF_FSA_ACTION(A_TE_INVOKE, do_te_invoke) - else IF_FSA_ACTION(A_ANNOUNCE, do_announce) + else IF_FSA_ACTION(A_CL_JOIN_ANNOUNCE, do_cl_join_announce) /* sub-system stop */ else IF_FSA_ACTION(A_PE_STOP, do_pe_control) else IF_FSA_ACTION(A_TE_STOP, do_te_control) else IF_FSA_ACTION(A_DC_RELEASED, do_dc_release) else IF_FSA_ACTION(A_HA_DISCONNECT, do_ha_control) else IF_FSA_ACTION(A_CCM_DISCONNECT, do_ccm_control) else IF_FSA_ACTION(A_LRM_DISCONNECT, do_lrm_control) - else IF_FSA_ACTION(A_CIB_STOP, do_cib_control) + else IF_FSA_ACTION(A_CIB_STOP, do_cib_control) + /* time to go now... */ /* Some of these can probably be consolidated */ - else IF_FSA_ACTION(A_SHUTDOWN, do_shutdown) + else IF_FSA_ACTION(A_SHUTDOWN, do_shutdown) else IF_FSA_ACTION(A_STOP, do_stop) /* exit gracefully */ else IF_FSA_ACTION(A_EXIT_0, do_exit) /* else IF_FSA_ACTION(A_, do_) */ else if((actions & A_MSG_PROCESS) != 0 || is_message()) { xmlNodePtr stored_msg = NULL; crm_verbose("Checking messages... %d", g_list_length(fsa_message_queue)); stored_msg = get_message(); if(is_message() == FALSE) { actions = clear_bit(actions, A_MSG_PROCESS); } if(stored_msg == NULL) { crm_err("Invalid stored message"); continue; } /* * This is where we should clean up old messages * The problem is that we dont always know the * type of the data (and therefore the correct way * to free it). A wrapper is probably required. */ data = stored_msg; #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t// %s:\t%s\t(data? %s)", fsa_input2string(cur_input), fsa_action2string(A_MSG_PROCESS), stored_msg==NULL?XML_BOOLEAN_NO:XML_BOOLEAN_YES); fflush(dot_strm); #endif #ifdef FSA_TRACE crm_verbose("Invoking action %s (%.16llx)", fsa_action2string(A_MSG_PROCESS), A_MSG_PROCESS); #endif /*#ifdef FSA_TRACE*/ crm_xml_devel(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 #ifdef FSA_TRACE crm_verbose("Result of action %s was %s", fsa_action2string(A_MSG_PROCESS), fsa_input2string(next_input)); #endif /* Error checking and reporting */ } else if(cur_input != I_NULL && is_set(actions, A_NOTHING)) { crm_warn( "No action specified for input,state (%s,%s)", fsa_input2string(cur_input), fsa_state2string(cur_state)); next_input = I_NULL; } else if(cur_input == I_NULL && is_set(actions, A_NOTHING)) { #ifdef FSA_TRACE crm_info("Nothing left to do"); #endif } else { crm_err("Action %s (0x%llx) not supported ", fsa_action2string(actions), actions); next_input = I_ERROR; } if(is_message()) { actions |= A_MSG_PROCESS; } } #ifdef FSA_TRACE crm_verbose("################# Exiting the FSA (%s) ##################", fsa_state2string(fsa_state)); #endif #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t// ### Exiting the FSA (%s)\n", fsa_state2string(fsa_state)); fflush(dot_strm); #endif /* cleanup inputs? */ fsa_actions = actions; return fsa_state; } long long do_state_transition(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_state next_state, enum crmd_fsa_input current_input, void *data) { gboolean clear_recovery_bit = TRUE; long long tmp = actions; const char *state_from = fsa_state2string(cur_state); const char *state_to = fsa_state2string(next_state); const char *input = fsa_input2string(current_input); time_t now = time(NULL); if(cur_state == next_state) { crm_err("%s called in state %s with no transtion", __FUNCTION__, state_from); return A_NOTHING; } -/* if(current_input != I_NULL */ -/* && (current_input != I_DC_HEARTBEAT || cur_state != S_NOT_DC)){ */ - - fprintf(dot_strm, - "\t\"%s\" -> \"%s\" [ label =\"%s\" ] // %s", - state_from, state_to, input, - asctime(localtime(&now))); - fflush(dot_strm); - /*}*/ + if(current_input != I_DC_HEARTBEAT && cur_state != S_NOT_DC){ + fprintf(dot_strm, + "\t\"%s\" -> \"%s\" [ label =\"%s\" ] // %s", + state_from, state_to, input, + asctime(localtime(&now))); + fflush(dot_strm); + } crm_info("State transition \"%s\" -> \"%s\" [ cause =\"%s\" %s ]", state_from, state_to, input, asctime(localtime(&now))); switch(next_state) { + case S_ELECTION: + fsa_our_dc = NULL; + break; + case S_INTEGRATION: + fsa_our_dc = fsa_our_uname; + break; case S_PENDING: break; case S_NOT_DC: if(is_set(fsa_input_register, R_SHUTDOWN)){ crm_info("(Re)Issuing shutdown request now" " that we have a new DC"); tmp = set_bit(tmp, A_SHUTDOWN_REQ); } + if(fsa_our_dc == NULL) { + crm_err("Reached S_NOT_DC without a DC" + " being recorded"); + } break; - case S_RECOVERY_DC: case S_RECOVERY: clear_recovery_bit = FALSE; break; case S_POLICY_ENGINE: - if(g_hash_table_size(joined_nodes) - != fsa_membership_copy->members_size) { + if(num_join_invites != fsa_membership_copy->members_size) { crm_warn("Only %d (of %d) cluster nodes are" " eligable to run resources.", - 1+g_hash_table_size(joined_nodes), + num_join_invites, fsa_membership_copy->members_size); } else { crm_info("All %d clusters nodes are" " eligable to run resources.", fsa_membership_copy->members_size); } break; case S_IDLE: dump_rsc_info(); /* keep going */ default: break; } if(clear_recovery_bit && next_state != S_PENDING) { tmp = clear_bit(tmp, A_RECOVER); } else if(clear_recovery_bit == FALSE) { tmp = set_bit(tmp, A_RECOVER); } if(tmp != actions) { crm_info("Action b4 %.16llx ", actions); crm_info("Action after %.16llx ", tmp); actions = tmp; } return actions; } long long clear_flags(long long actions, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input) { if(is_set(fsa_input_register, R_SHUTDOWN)){ clear_bit_inplace(&actions, A_DC_TIMER_START); } switch(cur_state) { case S_IDLE: break; case S_ELECTION: break; case S_INTEGRATION: break; + case S_FINALIZE_JOIN: + 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; } void dump_rsc_info(void) { xmlNodePtr local_cib = get_cib_copy(); xmlNodePtr root = get_object_root(XML_CIB_TAG_STATUS, local_cib); xmlNodePtr resources = NULL; const char *rsc_id = NULL; const char *node_id = NULL; const char *rsc_state = NULL; const char *op_status = NULL; const char *last_rc = NULL; const char *last_op = NULL; const char *path[] = { XML_CIB_TAG_LRM, XML_LRM_TAG_RESOURCES }; xml_child_iter( root, node, XML_CIB_TAG_STATE, resources = find_xml_node_nested(node, path, DIMOF(path)); xml_child_iter( resources, rsc, XML_LRM_TAG_RESOURCE, rsc_id = xmlGetProp(rsc, XML_ATTR_ID); node_id = xmlGetProp(rsc, XML_LRM_ATTR_TARGET); rsc_state = xmlGetProp(rsc, XML_LRM_ATTR_RSCSTATE); op_status = xmlGetProp(rsc, XML_LRM_ATTR_OPSTATUS); last_rc = xmlGetProp(rsc, XML_LRM_ATTR_RC); last_op = xmlGetProp(rsc, XML_LRM_ATTR_LASTOP); /* if(safe_str_eq(rsc_state, "stopped")) { */ /* continue; */ /* } */ crm_info("Resource state: %s %s " "[%s (rc=%s) after %s] on %s", rsc_id, rsc_state, op_status, last_rc, last_op, node_id); ); ); } diff --git a/crm/crmd/fsa_defines.h b/crm/crmd/fsa_defines.h index 5b488e7c36..a47ca9eb01 100644 --- a/crm/crmd/fsa_defines.h +++ b/crm/crmd/fsa_defines.h @@ -1,449 +1,461 @@ -/* $Id: fsa_defines.h,v 1.19 2004/08/30 03:17:38 msoffen Exp $ */ +/* $Id: fsa_defines.h,v 1.20 2004/09/21 19:40:18 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 FSA_DEFINES__H #define FSA_DEFINES__H /*====================================== * States the DC/CRMd can be in *======================================*/ enum crmd_fsa_state { S_IDLE = 0, /* Nothing happening */ S_ELECTION, /* Take part in the election algorithm as * described below */ S_INTEGRATION, /* integrate that status of new nodes (which is * all of them if we have just been elected DC) * to form a complete and up-to-date picture of * the CIB */ + S_FINALIZE_JOIN,/* integrate that status of new nodes (which is + * all of them if we have just been elected DC) + * to form a complete and up-to-date picture of + * the CIB + */ S_NOT_DC, /* we are in crmd/slave mode */ S_POLICY_ENGINE,/* Determin the next stable state of the cluster */ S_RECOVERY, /* Something bad happened, check everything is ok * before continuing and attempt to recover if * required */ - S_RECOVERY_DC, /* Something bad happened to the DC, check - * everything is ok before continuing and attempt - * to recover if required - */ S_RELEASE_DC, /* we were the DC, but now we arent anymore, * possibly by our own request, and we should * release all unnecessary sub-systems, finish * any pending actions, do general cleanup and * unset anything that makes us think we are * special :) */ S_PENDING, /* we are just starting out */ S_STOPPING, /* We are in the final stages of shutting down */ S_TERMINATE, /* We are going to shutdown, this is the equiv of * "Sending TERM signal to all processes" in Linux * and in worst case scenarios could be considered * a self STONITH */ S_TRANSITION_ENGINE,/* Attempt to make the calculated next stable * state of the cluster a reality */ /* ----------- Last input found in table is above ---------- */ S_ILLEGAL, /* This is an illegal FSA state */ /* (must be last) */ }; #define MAXSTATE S_ILLEGAL /* A state diagram can be constructed from the dc_fsa.dot with the following command: dot -Tpng crmd_fsa.dot > crmd_fsa.png Description: Once we start and do some basic sanity checks, we go into the S_NOT_DC state and await instructions from the DC or input from the CCM which indicates the election algorithm needs to run. If the election algorithm is triggered we enter the S_ELECTION state from where we can either go back to the S_NOT_DC state or progress to the S_INTEGRATION state (or S_RELEASE_DC if we used to be the DC but arent anymore). The election algorithm has been adapted from http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR521 Loosly known as the Bully Algorithm, its major points are: - Election is initiated by any node (N) notices that the coordinator is no longer responding - Concurrent multiple elections are possible - Algorithm + N sends ELECTION messages to all nodes that occur earlier in the CCM's membership list. + If no one responds, N wins and becomes coordinator + N sends out COORDINATOR messages to all other nodes in the partition + If one of higher-ups answers, it takes over. N is done. Once the election is complete, if we are the DC, we enter the S_INTEGRATION state which is a DC-in-waiting style state. We are the DC, but we shouldnt do anything yet because we may not have an up-to-date picture of the cluster. There may of course be times when this fails, so we should go back to the S_RECOVERY stage and check everything is ok. We may also end up here if a new node came online, since each node is authorative on itself and we would want to incorporate its information into the CIB. Once we have the latest CIB, we then enter the S_POLICY_ENGINE state where invoke the Policy Engine. It is possible that between invoking the Policy Engine and recieving an answer, that we recieve more input. In this case we would discard the orginal result and invoke it again. Once we are satisfied with the output from the Policy Engine we enter S_TRANSITION_ENGINE and feed the Policy Engine's output to the Transition Engine who attempts to make the Policy Engine's calculation a reality. If the transition completes successfully, we enter S_IDLE, otherwise we go back to S_POLICY_ENGINE with the current unstable state and try again. Of course we may be asked to shutdown at any time, however we must progress to S_NOT_DC before doing so. Once we have handed over DC duties to another node, we can then shut down like everyone else, that is by asking the DC for permission and waiting it to take all our resources away. The case where we are the DC and the only node in the cluster is a special case and handled as an escalation which takes us to S_SHUTDOWN. Similarly if any other point in the shutdown fails or stalls, this is escalated and we end up in S_TERMINATE. At any point, the CRMd/DC can relay messages for its sub-systems, but outbound messages (from sub-systems) should probably be blocked until S_INTEGRATION (for the DC case) or the join protocol has completed (for the CRMd case) */ /*====================================== * * Inputs/Events/Stimuli to be given to the finite state machine * * Some of these a true events, and others a synthesised based on * the "register" (see below) and the contents or source of messages. * * At this point, my plan is to have a loop of some sort that keeps * going until recieving I_NULL * *======================================*/ enum crmd_fsa_input { /* 0 */ I_NULL, /* Nothing happened */ /* 1 */ I_CCM_EVENT, I_CIB_OP, /* An update to the CIB occurred */ I_CIB_UPDATE, /* An update to the CIB occurred */ I_DC_TIMEOUT, /* We have lost communication with the DC */ I_ELECTION, /* Someone started an election */ I_PE_CALC, /* The Policy Engine needs to be invoked */ I_RELEASE_DC, /* The election completed and we were not * elected, but we were the DC beforehand */ I_ELECTION_DC, /* The election completed and we were (re-)elected * DC */ I_ERROR, /* Something bad happened (more serious than * I_FAIL) and may not have been due to the action * being performed. For example, we may have lost * our connection to the CIB. */ /* 10 */ I_FAIL, /* The action failed to complete successfully */ I_INTEGRATION_TIMEOUT, - I_NODE_JOIN, /* A node has entered the CCM membership list*/ - I_NODE_LEFT, /* A node shutdown (possibly unexpectedly) */ + I_NODE_JOIN, /* A node has entered the cluster */ I_NOT_DC, /* We are not and were not the DC before or after * the current operation or state */ I_RECOVERED, /* The recovery process completed successfully */ I_RELEASE_FAIL, /* We could not give up DC status for some reason */ I_RELEASE_SUCCESS, /* We are no longer the DC */ I_RESTART, /* The current set of actions needs to be * restarted */ I_REQUEST, /* Some non-resource, non-ccm action is required * of us, eg. ping */ /* 20 */ I_ROUTER, /* Do our job as router and forward this to the * right place */ I_SHUTDOWN, /* We are asking to shutdown */ I_TERMINATE, /* We have been told to shutdown */ I_STARTUP, I_SUCCESS, /* The action completed successfully */ - I_WELCOME, /* Welcome a newly joined node */ - I_WELCOME_ACK, /* The newly joined node has acknowledged us as - overlord - */ + I_JOIN_OFFER, /* The DC is offering membership */ + I_JOIN_REQUEST, /* The client is requesting membership */ + I_JOIN_RESULT, /* If not the DC: The result of a join request + * Else: A client is responding with its local state info + */ I_WAIT_FOR_EVENT, /* we may be waiting for an async task to "happen" * and until it does, we cant do anything else */ I_DC_HEARTBEAT, /* The DC is telling us that it is alive and well */ I_LRM_EVENT, + +/* 30 */ + I_VOTE, /* ------------ Last input found in table is above ----------- */ I_ILLEGAL, /* This is an illegal value for an FSA input */ /* (must be last) */ }; #define MAXINPUT I_ILLEGAL #define I_MESSAGE I_ROUTER /*====================================== * * actions * * Some of the actions below will always occur together for now, but I can * forsee that this may not always be the case. So I've spilt them up so * that if they ever do need to be called independantly in the future, it * wont be a problem. * * For example, separating A_LRM_CONNECT from A_STARTUP might be useful * if we ever try to recover from a faulty or disconnected LRM. * *======================================*/ /* Dont do anything */ #define A_NOTHING 0x0000000000000000ULL /* -- Startup actions -- */ /* Hook to perform any actions (other than starting the CIB, * connecting to HA or the CCM) that might be needed as part * of the startup. */ #define A_STARTUP 0x0000000000000001ULL /* Hook to perform any actions that might be needed as part * after startup is successful. */ #define A_STARTED 0x0000000000000002ULL /* Connect to Heartbeat */ #define A_HA_CONNECT 0x0000000000000004ULL #define A_HA_DISCONNECT 0x0000000000000008ULL /* -- Election actions -- */ #define A_DC_TIMER_START 0x0000000000000010ULL #define A_DC_TIMER_STOP 0x0000000000000020ULL #define A_ELECT_TIMER_START 0x0000000000000040ULL #define A_ELECT_TIMER_STOP 0x0000000000000080ULL #define A_ELECTION_COUNT 0x0000000000000100ULL #define A_ELECTION_TIMEOUT 0x0000000000000200ULL #define A_ELECTION_VOTE 0x0000000000000400ULL - -/* -- Join protocol actions -- */ -#define A_ANNOUNCE 0x0000000000000800ULL - /* Acknowledge the DC as our overlord*/ -#define A_JOIN_ACK 0x0000000000001000ULL - /* Send a welcome message to new node(s) */ -#define A_JOIN_WELCOME 0x0000000000002000ULL - /* Send a welcome message to all nodes */ -#define A_JOIN_WELCOME_ALL 0x0000000000004000ULL - /* Process the remote node's ack of our join message */ -#define A_JOIN_PROCESS_ACK 0x0000000000008000ULL - /* -- Message processing -- */ /* Process the queue of requests */ -#define A_MSG_PROCESS 0x0000000000010000ULL +#define A_MSG_PROCESS 0x0000000000001000ULL /* Send the message to the correct recipient */ -#define A_MSG_ROUTE 0x0000000000020000ULL +#define A_MSG_ROUTE 0x0000000000002000ULL /* Put the request into a queue for processing. We do this every * time so that the processing is consistent. The intent is to * allow the DC to keep doing important work while still not * loosing requests. * Messages are not considered recieved until processed. */ -#define A_MSG_STORE 0x0000000000040000ULL +#define A_MSG_STORE 0x0000000000004000ULL + + +/* -- Client Join protocol actions -- */ +#define A_CL_JOIN_ANNOUNCE 0x0000000000010000ULL + /* Request membership to the DC list */ +#define A_CL_JOIN_REQUEST 0x0000000000020000ULL + /* Did the DC accept or reject the request */ +#define A_CL_JOIN_RESULT 0x0000000000040000ULL + +/* -- Server Join protocol actions -- */ + /* Send a welcome message to new node(s) */ +#define A_DC_JOIN_OFFER_ONE 0x0000000000080000ULL + /* Send a welcome message to all nodes */ +#define A_DC_JOIN_OFFER_ALL 0x0000000000100000ULL + /* Process the remote node's ack of our join message */ +#define A_DC_JOIN_PROCESS_REQ 0x0000000000200000ULL + /* Send out the reults of the Join phase */ +#define A_DC_JOIN_FINALIZE 0x0000000000400000ULL + /* Send out the reults of the Join phase */ +#define A_DC_JOIN_PROCESS_ACK 0x0000000000800000ULL /* -- Recovery, DC start/stop -- */ /* Something bad happened, try to recover */ #define A_RECOVER 0x0000000001000000ULL /* Hook to perform any actions (apart from starting, the TE, PE * and gathering the latest CIB) that might be necessary before * giving up the responsibilities of being the DC. */ #define A_DC_RELEASE 0x0000000002000000ULL /* */ #define A_DC_RELEASED 0x0000000004000000ULL /* Hook to perform any actions (apart from starting, the TE, PE * and gathering the latest CIB) that might be necessary before * taking over the responsibilities of being the DC. */ #define A_DC_TAKEOVER 0x0000000008000000ULL /* -- Shutdown actions -- */ #define A_SHUTDOWN 0x0000000010000000ULL #define A_STOP 0x0000000020000000ULL #define A_EXIT_0 0x0000000040000000ULL #define A_EXIT_1 0x0000000080000000ULL #define A_SHUTDOWN_REQ 0x0000000100000000ULL /* -- CCM actions -- */ #define A_CCM_CONNECT 0x0000001000000000ULL #define A_CCM_DISCONNECT 0x0000002000000000ULL /* Process whatever it is the CCM is trying to tell us. * This will generate inputs such as I_NODE_JOIN, * I_NODE_LEAVE, I_SHUTDOWN, I_DC_RELEASE, I_DC_TAKEOVER */ #define A_CCM_EVENT 0x0000004000000000ULL #define A_CCM_UPDATE_CACHE 0x0000008000000000ULL /* -- CBI actions -- */ #define A_CIB_INVOKE 0x0000010000000000ULL #define A_CIB_START 0x0000020000000000ULL #define A_CIB_STOP 0x0000040000000000ULL #define A_CIB_INVOKE_LOCAL 0x0000080000000000ULL /* -- Transition Engine actions -- */ /* Attempt to reach the newly calculated cluster state. This is * only called once per transition (except if it is asked to * stop the transition or start a new one). * Once given a cluster state to reach, the TE will determin * tasks that can be performed in parallel, execute them, wait * for replies and then determin the next set until the new * state is reached or no further tasks can be taken. */ #define A_TE_INVOKE 0x0000100000000000ULL #define A_TE_START 0x0000200000000000ULL #define A_TE_STOP 0x0000400000000000ULL #define A_TE_CANCEL 0x0000800000000000ULL #define A_TE_COPYTO 0x0001000000000000ULL /* -- Policy Engine actions -- */ /* Calculate the next state for the cluster. This is only * invoked once per needed calculation. */ #define A_PE_INVOKE 0x0002000000000000ULL #define A_PE_START 0x0004000000000000ULL #define A_PE_STOP 0x0008000000000000ULL /* -- Misc actions -- */ /* Add a system generate "block" so that resources arent moved * to or are activly moved away from the affected node. This * way we can return quickly even if busy with other things. */ #define A_NODE_BLOCK 0x0010000000000000ULL /* Update our information in the local CIB */ #define A_UPDATE_NODESTATUS 0x0020000000000000ULL #define A_CIB_BUMPGEN 0x0040000000000000ULL #define A_READCONFIG 0x0080000000000000ULL /* -- LRM Actions -- */ /* Connect to the Local Resource Manager */ #define A_LRM_CONNECT 0x0100000000000000ULL /* Disconnect from the Local Resource Manager */ #define A_LRM_DISCONNECT 0x0200000000000000ULL #define A_LRM_INVOKE 0x0400000000000000ULL #define A_LRM_EVENT 0x0800000000000000ULL /* -- Logging actions -- */ #define A_LOG 0x1000000000000000ULL #define A_ERROR 0x2000000000000000ULL #define A_WARN 0x4000000000000000ULL #define O_SHUTDOWN (A_CCM_DISCONNECT|A_LRM_DISCONNECT|A_HA_DISCONNECT|A_SHUTDOWN|A_STOP|A_EXIT_0|A_CIB_STOP) #define O_RELEASE (A_DC_TIMER_STOP|A_DC_RELEASE|A_PE_STOP|A_TE_STOP|A_DC_RELEASED) #define O_DC_TIMER_RESTART (A_DC_TIMER_STOP|A_DC_TIMER_START) #define O_PE_RESTART (A_PE_START|A_PE_STOP) #define O_TE_RESTART (A_TE_START|A_TE_STOP) #define O_CIB_RESTART (A_CIB_START|A_CIB_STOP) #define O_DC_TICKLE O_DC_TIMER_RESTART /*====================================== * * "register" contents * * Things we may want to remember regardless of which state we are in. * * These also count as inputs for synthesizing I_* * *======================================*/ #define R_THE_DC 0x00000001 /* Are we the DC? */ #define R_STARTING 0x00000002 /* Are we starting up? */ #define R_SHUTDOWN 0x00000004 /* Are we trying to shut down? */ #define R_CIB_DONE 0x00000008 /* Have we calculated the CIB? */ #define R_JOIN_OK 0x00000010 /* Have we completed the join process */ #define R_HAVE_CIB 0x00000020 /* Do we have an up-to-date CIB */ #define R_HAVE_RES 0x00000040 /* Do we have any resources running locally */ #define R_INVOKE_PE 0x00000080 /* Does the PE needed to be invoked at the next appropriate point? */ #define R_CIB_CONNECTED 0x00000100 /* Is the CIB connected? */ #define R_PE_CONNECTED 0x00000200 /* Is the Policy Engine connected? */ #define R_TE_CONNECTED 0x00000400 /* Is the Transition Engine connected? */ #define R_LRM_CONNECTED 0x00000800 /* Is the Local Resource Manager connected? */ #define R_REQ_PEND 0x00001000 /* Are there Requests waiting for processing? */ #define R_PE_PEND 0x00002000 /* Has the PE been invoked and we're awaiting a reply? */ #define R_TE_PEND 0x00004000 /* Has the TE been invoked and we're awaiting completion? */ #define R_RESP_PEND 0x00008000 /* Do we have clients waiting on a response? if so perhaps we shouldnt stop yet */ enum crmd_fsa_cause { C_UNKNOWN = 0, C_STARTUP, C_IPC_MESSAGE, C_HA_MESSAGE, C_CCM_CALLBACK, C_CRMD_STATUS_CALLBACK, C_LRM_OP_CALLBACK, C_LRM_MONITOR_CALLBACK, C_TIMER_POPPED, C_SHUTDOWN, C_HEARTBEAT_FAILED, C_SUBSYSTEM_CONNECT, C_HA_DISCONNECT, C_ILLEGAL }; extern const char *fsa_input2string(enum crmd_fsa_input input); extern const char *fsa_state2string(enum crmd_fsa_state state); extern const char *fsa_cause2string(enum crmd_fsa_cause cause); extern const char *fsa_action2string(long long action); #endif diff --git a/crm/crmd/fsa_matrix.h b/crm/crmd/fsa_matrix.h index 84cc2d6be5..ec6855f053 100644 --- a/crm/crmd/fsa_matrix.h +++ b/crm/crmd/fsa_matrix.h @@ -1,999 +1,1034 @@ /* * 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_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_TRANSITION_ENGINE, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_RECOVERY, + /* S_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ S_ELECTION, /* S_NOT_DC ==> */ S_ELECTION, /* S_POLICY_ENGINE ==> */ S_ELECTION, /* S_RECOVERY ==> */ S_RECOVERY, - /* S_RECOVERY_DC ==> */ S_RECOVERY, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_ELECTION, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_ELECTION, }, /* Got an I_PE_CALC */ { /* S_IDLE ==> */ S_POLICY_ENGINE, /* S_ELECTION ==> */ S_ELECTION, - /* S_INTEGRATION ==> */ S_POLICY_ENGINE, + /* S_INTEGRATION ==> */ S_INTEGRATION, + /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* S_NOT_DC ==> */ S_RECOVERY, /* S_POLICY_ENGINE ==> */ S_POLICY_ENGINE, /* S_RECOVERY ==> */ S_RECOVERY, - /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, /* S_RELEASE_DC ==> */ S_RELEASE_DC, /* S_PENDING ==> */ S_RECOVERY, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_POLICY_ENGINE, }, /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RECOVERY, + /* S_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_INTEGRATION, /* S_POLICY_ENGINE ==> */ S_INTEGRATION, - /* S_RECOVERY ==> */ S_RECOVERY_DC, - /* S_RECOVERY_DC ==> */ S_RECOVERY_DC, + /* S_RECOVERY ==> */ S_RECOVERY, /* 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_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_INTEGRATION, + /* S_FINALIZE_JOIN ==> */ S_INTEGRATION, /* S_NOT_DC ==> */ S_RECOVERY, - /* S_POLICY_ENGINE ==> */ S_RECOVERY_DC, + /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* 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, + /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_FAIL */ { - /* S_IDLE ==> */ S_RECOVERY_DC, + /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_INTEGRATION, + /* S_FINALIZE_JOIN ==> */ 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_INTEGRATION ==> */ S_FINALIZE_JOIN, + /* S_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_NOT_DC */ { /* S_IDLE ==> */ S_RECOVERY, /* S_ELECTION ==> */ S_PENDING, /* S_INTEGRATION ==> */ S_RECOVERY, + /* S_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* 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_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* 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_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_IDLE ==> */ S_RECOVERY, + /* S_ELECTION ==> */ S_RECOVERY, + /* S_INTEGRATION ==> */ S_RECOVERY, + /* S_FINALIZE_JOIN ==> */ S_RECOVERY, + /* S_NOT_DC ==> */ S_RECOVERY, + /* S_POLICY_ENGINE ==> */ S_RECOVERY, /* 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, + /* S_TRANSITION_ENGINE ==> */ S_RECOVERY, }, /* Got an I_SUCCESS */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, - /* S_INTEGRATION ==> */ S_POLICY_ENGINE, + /* S_INTEGRATION ==> */ S_FINALIZE_JOIN, + /* S_FINALIZE_JOIN ==> */ 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_PENDING ==> */ S_NOT_DC, /* S_STOPPING ==> */ S_TERMINATE, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_IDLE, }, -/* Got an I_WELCOME */ +/* Got an I_JOIN_OFFER */ { /* S_IDLE ==> */ S_RELEASE_DC, /* S_ELECTION ==> */ S_RELEASE_DC, /* S_INTEGRATION ==> */ S_RELEASE_DC, + /* S_FINALIZE_JOIN ==> */ 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_PENDING ==> */ S_PENDING, /* S_STOPPING ==> */ S_STOPPING, /* S_TERMINATE ==> */ S_TERMINATE, /* S_TRANSITION_ENGINE ==> */ S_RELEASE_DC, }, -/* Got an I_WELCOME_ACK */ +/* Got an I_JOIN_REQUEST */ + { + /* S_IDLE ==> */ S_INTEGRATION, + /* S_ELECTION ==> */ S_ELECTION, + /* S_INTEGRATION ==> */ S_INTEGRATION, + /* S_FINALIZE_JOIN ==> */ S_INTEGRATION, + /* S_NOT_DC ==> */ S_NOT_DC, + /* S_POLICY_ENGINE ==> */ S_INTEGRATION, + /* S_RECOVERY ==> */ S_RECOVERY, + /* 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_JOIN_RESULT */ { /* S_IDLE ==> */ S_IDLE, /* S_ELECTION ==> */ S_ELECTION, /* S_INTEGRATION ==> */ S_INTEGRATION, + /* S_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* 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_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ S_FINALIZE_JOIN, /* 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_VOTE */ + { + /* S_IDLE ==> */ S_ELECTION, + /* S_ELECTION ==> */ S_ELECTION, + /* S_INTEGRATION ==> */ S_ELECTION, + /* S_FINALIZE_JOIN ==> */ S_ELECTION, + /* S_NOT_DC ==> */ S_ELECTION, + /* S_POLICY_ENGINE ==> */ S_ELECTION, + /* S_RECOVERY ==> */ 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, + }, }; /* * 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. */ + +/* NOTE: In the fsa, the actions are extracted then state is updated. */ + 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_FINALIZE_JOIN ==> */ A_NOTHING, /* S_NOT_DC ==> */ A_NOTHING, /* S_POLICY_ENGINE ==> */ A_NOTHING, - /* S_RECOVERY ==> */ A_RECOVER, - /* S_RECOVERY_DC ==> */ A_RECOVER, + /* S_RECOVERY ==> */ A_RECOVER|O_RELEASE, /* 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_TE_COPYTO, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, + /* S_FINALIZE_JOIN ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, /* S_NOT_DC ==> */ A_WARN, /* S_POLICY_ENGINE ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_CIB_BUMPGEN|A_TE_COPYTO, }, /* Got an I_DC_TIMEOUT */ { /* S_IDLE ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_ELECTION ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, /* S_INTEGRATION ==> */ A_ELECTION_VOTE|A_ELECT_TIMER_START, + /* S_FINALIZE_JOIN ==> */ 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_RELEASE_DC ==> */ A_WARN, /* 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, + /* S_TRANSITION_ENGINE ==> */ A_TE_CANCEL|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_FINALIZE_JOIN ==> */ A_ELECTION_COUNT, /* S_NOT_DC ==> */ A_ELECTION_COUNT, /* S_POLICY_ENGINE ==> */ A_ELECTION_COUNT, /* S_RECOVERY ==> */ A_LOG, - /* S_RECOVERY_DC ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_LOG, /* S_PENDING ==> */ A_ELECTION_COUNT, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, /* S_TRANSITION_ENGINE ==> */ A_ELECTION_COUNT, }, /* Got an I_PE_CALC */ { /* S_IDLE ==> */ A_PE_INVOKE, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_PE_INVOKE, + /* S_INTEGRATION ==> */ A_WARN, + /* S_FINALIZE_JOIN ==> */ A_WARN, /* S_NOT_DC ==> */ A_ERROR, /* S_POLICY_ENGINE ==> */ A_PE_INVOKE, - /* S_RECOVERY ==> */ A_ERROR, - /* S_RECOVERY_DC ==> */ A_PE_INVOKE, + /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_ERROR, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, /* S_TRANSITION_ENGINE ==> */ A_PE_INVOKE|A_TE_CANCEL, }, /* Got an I_RELEASE_DC */ { /* S_IDLE ==> */ O_RELEASE|A_ERROR, /* S_ELECTION ==> */ O_RELEASE, /* S_INTEGRATION ==> */ O_RELEASE|A_ERROR, + /* S_FINALIZE_JOIN ==> */ 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_ELECT_TIMER_STOP|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, + /* S_ELECTION ==> */ A_LOG|A_DC_TAKEOVER|A_PE_START|A_TE_START|A_DC_JOIN_OFFER_ALL|A_ELECT_TIMER_STOP|A_ELECTION_VOTE, /* S_INTEGRATION ==> */ A_WARN|A_ELECTION_VOTE, - /* S_NOT_DC ==> */ A_LOG|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, + /* S_FINALIZE_JOIN ==> */ A_WARN|A_ELECTION_VOTE, + /* S_NOT_DC ==> */ A_LOG|A_ELECTION_VOTE, /* S_POLICY_ENGINE ==> */ A_WARN|A_ELECTION_VOTE, - /* S_RECOVERY ==> */ A_WARN|A_ELECTION_VOTE, - /* S_RECOVERY_DC ==> */ A_LOG|A_ELECTION_VOTE, + /* S_RECOVERY ==> */ A_WARN, /* S_RELEASE_DC ==> */ A_WARN|A_ELECTION_VOTE, - /* S_PENDING ==> */ A_LOG|A_ELECTION_VOTE|A_UPDATE_NODESTATUS, + /* S_PENDING ==> */ A_LOG|A_ELECTION_VOTE, /* 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_IDLE ==> */ A_DC_TIMER_STOP|A_RECOVER|O_RELEASE, + /* S_ELECTION ==> */ A_DC_TIMER_STOP|A_RECOVER|O_RELEASE, + /* S_INTEGRATION ==> */ A_DC_TIMER_STOP|A_RECOVER|O_RELEASE, + /* S_FINALIZE_JOIN ==> */ A_DC_TIMER_STOP|A_RECOVER|O_RELEASE, /* 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_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|A_RECOVER|O_RELEASE, + /* S_RECOVERY ==> */ 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, + /* S_TRANSITION_ENGINE ==> */ A_DC_TIMER_STOP|A_RECOVER|O_RELEASE, }, /* 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_INTEGRATION ==> */ A_WARN|A_DC_JOIN_OFFER_ALL, + /* S_FINALIZE_JOIN ==> */ A_WARN|A_DC_JOIN_OFFER_ALL, /* S_NOT_DC ==> */ A_ELECT_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_POLICY_ENGINE ==> */ A_WARN|A_DC_JOIN_OFFER_ALL|A_PE_INVOKE, + /* S_RECOVERY ==> */ A_WARN|O_SHUTDOWN|O_RELEASE, /* S_RELEASE_DC ==> */ A_WARN|O_SHUTDOWN, /* S_PENDING ==> */ A_ELECT_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_INTEGRATION ==> */ A_DC_JOIN_FINALIZE, + /* S_FINALIZE_JOIN ==> */ A_WARN, /* 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_TE_CANCEL|A_JOIN_WELCOME, - /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_TE_CANCEL|A_JOIN_WELCOME, - /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_TE_CANCEL|A_JOIN_WELCOME, - /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_TE_CANCEL|A_JOIN_WELCOME, - /* S_RELEASE_DC ==> */ A_WARN, - /* S_PENDING ==> */ A_WARN, - /* S_STOPPING ==> */ A_WARN, - /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_TE_CANCEL|A_JOIN_WELCOME, - }, - -/* Got an I_NODE_LEFT */ - { - /* S_IDLE ==> */ A_LOG, + /* S_IDLE ==> */ A_TE_CANCEL|A_DC_JOIN_OFFER_ONE, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_LOG, + /* S_INTEGRATION ==> */ A_TE_CANCEL|A_DC_JOIN_OFFER_ONE, + /* S_FINALIZE_JOIN ==> */ A_TE_CANCEL|A_DC_JOIN_OFFER_ONE, /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_LOG, + /* S_POLICY_ENGINE ==> */ A_TE_CANCEL|A_DC_JOIN_OFFER_ONE, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_LOG, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_LOG, + /* S_TRANSITION_ENGINE ==> */ A_TE_CANCEL|A_DC_JOIN_OFFER_ONE, }, /* 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_FINALIZE_JOIN ==> */ 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_RECOVERY ==> */ A_WARN|O_RELEASE, /* 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_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_RECOVERY ==> */ A_WARN|A_SHUTDOWN_REQ, /* 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_FINALIZE_JOIN ==> */ 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_INTEGRATION ==> */ A_LOG|A_DC_JOIN_OFFER_ALL, + /* S_FINALIZE_JOIN ==> */ A_LOG|A_DC_JOIN_FINALIZE, /* 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_RECOVERY ==> */ A_LOG|A_RECOVER|O_RELEASE, /* 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_PROCESS, /* S_ELECTION ==> */ A_MSG_PROCESS, /* S_INTEGRATION ==> */ A_MSG_PROCESS, + /* S_FINALIZE_JOIN ==> */ A_MSG_PROCESS, /* S_NOT_DC ==> */ A_MSG_PROCESS, /* S_POLICY_ENGINE ==> */ A_MSG_PROCESS, /* S_RECOVERY ==> */ A_MSG_PROCESS, - /* S_RECOVERY_DC ==> */ A_MSG_PROCESS, /* S_RELEASE_DC ==> */ A_MSG_PROCESS, /* S_PENDING ==> */ A_MSG_PROCESS, - /* S_STOPPING ==> */ A_LOG|A_MSG_PROCESS, - /* S_TERMINATE ==> */ A_LOG|A_MSG_PROCESS, + /* S_STOPPING ==> */ A_WARN|A_MSG_PROCESS, + /* S_TERMINATE ==> */ A_WARN|A_MSG_PROCESS, /* S_TRANSITION_ENGINE ==> */ A_MSG_PROCESS, }, /* Got an I_ROUTER */ { /* S_IDLE ==> */ A_MSG_ROUTE, /* S_ELECTION ==> */ A_MSG_ROUTE, /* S_INTEGRATION ==> */ A_MSG_ROUTE, + /* S_FINALIZE_JOIN ==> */ 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 ==> */ O_RELEASE, /* S_ELECTION ==> */ O_RELEASE, /* S_INTEGRATION ==> */ O_RELEASE, + /* S_FINALIZE_JOIN ==> */ O_RELEASE, /* S_NOT_DC ==> */ A_ELECT_TIMER_STOP|A_SHUTDOWN_REQ, /* S_POLICY_ENGINE ==> */ O_RELEASE, - /* S_RECOVERY ==> */ A_ELECT_TIMER_STOP|A_SHUTDOWN_REQ, - /* S_RECOVERY_DC ==> */ O_RELEASE, + /* S_RECOVERY ==> */ A_ELECT_TIMER_STOP|A_SHUTDOWN_REQ|O_RELEASE, /* S_RELEASE_DC ==> */ A_SHUTDOWN_REQ, /* S_PENDING ==> */ A_ELECT_TIMER_STOP|A_SHUTDOWN_REQ, /* S_STOPPING ==> */ A_SHUTDOWN_REQ, /* S_TERMINATE ==> */ A_SHUTDOWN_REQ, /* S_TRANSITION_ENGINE ==> */ 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_FINALIZE_JOIN ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_NOT_DC ==> */ O_SHUTDOWN, /* S_POLICY_ENGINE ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, - /* S_RECOVERY ==> */ O_SHUTDOWN, - /* S_RECOVERY_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, - /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN, + /* S_RECOVERY ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, + /* S_RELEASE_DC ==> */ A_DC_TIMER_STOP|O_SHUTDOWN|O_RELEASE, /* S_PENDING ==> */ O_SHUTDOWN, /* S_STOPPING ==> */ O_SHUTDOWN, /* S_TERMINATE ==> */ 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_FINALIZE_JOIN ==> */ 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|A_READCONFIG, /* 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_CIB_INVOKE|A_PE_INVOKE, + /* S_INTEGRATION ==> */ A_LOG|A_DC_JOIN_FINALIZE, + /* S_FINALIZE_JOIN ==> */ A_LOG|A_CIB_INVOKE|A_PE_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 */ +/* Got an I_JOIN_OFFER */ { - /* 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_IDLE ==> */ O_RELEASE|A_CL_JOIN_REQUEST, + /* S_ELECTION ==> */ O_RELEASE|A_CL_JOIN_REQUEST, + /* S_INTEGRATION ==> */ O_RELEASE|A_CL_JOIN_REQUEST, + /* S_FINALIZE_JOIN ==> */ O_RELEASE|A_CL_JOIN_REQUEST, + /* S_NOT_DC ==> */ O_DC_TICKLE|A_CL_JOIN_REQUEST, + /* S_POLICY_ENGINE ==> */ O_RELEASE|A_CL_JOIN_REQUEST, + /* S_RECOVERY ==> */ O_RELEASE|A_CL_JOIN_REQUEST, + /* S_RELEASE_DC ==> */ A_CL_JOIN_REQUEST, + /* S_PENDING ==> */ O_DC_TICKLE|A_CL_JOIN_REQUEST|A_STARTED, /* S_STOPPING ==> */ A_LOG, /* S_TERMINATE ==> */ A_LOG, - /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_UPDATE_NODESTATUS|A_JOIN_ACK, + /* S_TRANSITION_ENGINE ==> */ O_RELEASE|A_CL_JOIN_REQUEST, }, -/* Got an I_WELCOME_ACK */ +/* Got an I_JOIN_REQUEST */ { - /* S_IDLE ==> */ A_JOIN_PROCESS_ACK, + /* S_IDLE ==> */ A_DC_JOIN_PROCESS_REQ, /* S_ELECTION ==> */ A_WARN, - /* S_INTEGRATION ==> */ A_JOIN_PROCESS_ACK, + /* S_INTEGRATION ==> */ A_DC_JOIN_PROCESS_REQ, + /* S_FINALIZE_JOIN ==> */ A_DC_JOIN_PROCESS_REQ, /* S_NOT_DC ==> */ A_WARN, - /* S_POLICY_ENGINE ==> */ A_JOIN_PROCESS_ACK, + /* S_POLICY_ENGINE ==> */ A_DC_JOIN_PROCESS_REQ, /* S_RECOVERY ==> */ A_WARN, - /* S_RECOVERY_DC ==> */ A_JOIN_PROCESS_ACK, /* S_RELEASE_DC ==> */ A_WARN, /* S_PENDING ==> */ A_WARN, /* S_STOPPING ==> */ A_WARN, /* S_TERMINATE ==> */ A_WARN, - /* S_TRANSITION_ENGINE ==> */ A_JOIN_PROCESS_ACK, + /* S_TRANSITION_ENGINE ==> */ A_DC_JOIN_PROCESS_REQ, }, +/* Got an I_JOIN_RESULT */ + { + /* S_IDLE ==> */ A_LOG, + /* S_ELECTION ==> */ A_LOG, + /* S_INTEGRATION ==> */ A_LOG, + /* S_FINALIZE_JOIN ==> */ A_DC_JOIN_PROCESS_ACK, + /* S_NOT_DC ==> */ A_LOG, + /* S_POLICY_ENGINE ==> */ A_LOG, + /* S_RECOVERY ==> */ A_LOG, + /* S_RELEASE_DC ==> */ A_LOG, + /* S_PENDING ==> */ A_CL_JOIN_RESULT, + /* S_STOPPING ==> */ A_LOG, + /* S_TERMINATE ==> */ A_LOG, + /* S_TRANSITION_ENGINE ==> */ A_LOG, + }, + /* Got an I_WAIT_FOR_EVENT */ { /* S_IDLE ==> */ A_LOG, /* S_ELECTION ==> */ A_LOG, /* S_INTEGRATION ==> */ A_LOG, + /* S_FINALIZE_JOIN ==> */ 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_FINALIZE_JOIN ==> */ 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_PENDING ==> */ A_LOG|O_DC_TICKLE|A_CL_JOIN_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_FINALIZE_JOIN ==> */ 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, }, + +/* Got an I_VOTE */ + { + /* S_IDLE ==> */ A_ELECTION_VOTE, + /* S_ELECTION ==> */ A_ELECTION_VOTE, + /* S_INTEGRATION ==> */ A_ELECTION_VOTE, + /* S_FINALIZE_JOIN ==> */ A_ELECTION_VOTE, + /* S_NOT_DC ==> */ A_ELECTION_VOTE, + /* S_POLICY_ENGINE ==> */ A_ELECTION_VOTE, + /* S_RECOVERY ==> */ A_WARN, + /* S_RELEASE_DC ==> */ A_WARN, + /* S_PENDING ==> */ A_ELECTION_VOTE, + /* S_STOPPING ==> */ A_WARN, + /* S_TERMINATE ==> */ A_WARN, + /* S_TRANSITION_ENGINE ==> */ A_ELECTION_VOTE, + }, }; #endif diff --git a/crm/crmd/fsa_proto.h b/crm/crmd/fsa_proto.h index 7d4ba5eeaf..8b686e22a9 100644 --- a/crm/crmd/fsa_proto.h +++ b/crm/crmd/fsa_proto.h @@ -1,337 +1,363 @@ -/* $Id: fsa_proto.h,v 1.11 2004/06/28 08:23:52 andrew Exp $ */ +/* $Id: fsa_proto.h,v 1.12 2004/09/21 19:40:18 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef XML_FSA_PROTO__H #define XML_FSA_PROTO__H +extern xmlNodePtr do_lrm_query(gboolean); + /* A_READCONFIG */ enum crmd_fsa_input do_read_config(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data); -/* A_ANNOUNCE */ -enum crmd_fsa_input -do_announce(long long action, - enum crmd_fsa_cause cause, - enum crmd_fsa_state cur_state, - enum crmd_fsa_input current_input, - void *data); - /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data); /* A_ERROR */ enum crmd_fsa_input do_error(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LOG */ enum crmd_fsa_input do_log(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STARTUP */ enum crmd_fsa_input do_startup(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CIB_START, STOP, RESTART */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_HA_CONNECT */ enum crmd_fsa_input do_ha_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_CONNECT */ enum crmd_fsa_input do_ccm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LRM_CONNECT */ enum crmd_fsa_input do_lrm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_PE_START, STOP, RESTART */ enum crmd_fsa_input do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_TE_START, STOP, RESTART */ enum crmd_fsa_input do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STARTED */ enum crmd_fsa_input do_started(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_MSG_ROUTE */ enum crmd_fsa_input do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_RECOVER */ enum crmd_fsa_input do_recover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECTION_VOTE */ enum crmd_fsa_input do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECTION_COUNT */ enum crmd_fsa_input do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_ELECT_TIMER_START, A_ELECTION_TIMEOUT */ enum crmd_fsa_input do_election_timer_ctrl(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_TIMER_STOP */ enum crmd_fsa_input do_dc_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_MSG_STORE */ enum crmd_fsa_input do_msg_store(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_UPDATE_CACHE */ enum crmd_fsa_input do_ccm_update_cache(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_CCM_EVENT */ enum crmd_fsa_input do_ccm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_TAKEOVER */ enum crmd_fsa_input do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_DC_RELEASE */ enum crmd_fsa_input do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); -/* A_JOIN_WELCOME_ALL */ +/* A_DC_JOIN_OFFER_ALL */ enum crmd_fsa_input -do_send_welcome_all(long long action, - enum crmd_fsa_cause cause, - enum crmd_fsa_state cur_state, - enum crmd_fsa_input cur_input, - void *data); +do_dc_join_offer_all(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input cur_input, + void *data); -/* A_JOIN_WELCOME */ +/* A_DC_JOIN_OFFER_ONE */ enum crmd_fsa_input -do_send_welcome(long long action, - enum crmd_fsa_cause cause, - enum crmd_fsa_state cur_state, - enum crmd_fsa_input cur_input, - void *data); +do_dc_join_offer_one(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input cur_input, + void *data); -/* A_JOIN_ACK */ +/* A_DC_JOIN_ACK */ enum crmd_fsa_input -do_ack_welcome(long long action, +do_dc_join_ack(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); -/* A_JOIN_PROCESS_ACK */ +/* A_DC_JOIN_REQ */ enum crmd_fsa_input -do_process_welcome_ack(long long action, - enum crmd_fsa_cause cause, - enum crmd_fsa_state cur_state, - enum crmd_fsa_input cur_input, - void *data); +do_dc_join_req(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input cur_input, + void *data); + +/* A_DC_JOIN_FINALIZE */ +enum crmd_fsa_input +do_dc_join_finalize(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input cur_input, + void *data); + +/* A_CL_JOIN_ANNOUNCE */ +enum crmd_fsa_input +do_cl_join_announce(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data); + +/* A_CL_JOIN_REQUEST */ +enum crmd_fsa_input +do_cl_join_request(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data); + +/* A_CL_JOIN_RESULT */ +enum crmd_fsa_input +do_cl_join_result(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data); /* A_CIB_INVOKE */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_UPDATE_NODESTATUS */ enum crmd_fsa_input do_update_node_status(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LRM_INVOKE */ enum crmd_fsa_input do_lrm_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_LRM_EVENT */ enum crmd_fsa_input do_lrm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_TE_INVOKE, A_TE_CANCEL */ enum crmd_fsa_input do_te_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_TE_INVOKE */ enum crmd_fsa_input do_te_copyto(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_SHUTDOWN_REQ */ enum crmd_fsa_input do_shutdown_req(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_SHUTDOWN */ enum crmd_fsa_input do_shutdown(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_STOP */ enum crmd_fsa_input do_stop(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); /* A_EXIT_0, A_EXIT_1 */ enum crmd_fsa_input do_exit(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data); #endif diff --git a/crm/crmd/join.c b/crm/crmd/join.c index d0a8203a2c..6e0da7b0d8 100644 --- a/crm/crmd/join.c +++ b/crm/crmd/join.c @@ -1,406 +1,405 @@ /* * 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 GHashTable *joined_nodes = NULL; /* A_JOIN_WELCOME */ enum crmd_fsa_input do_send_welcome(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr update = NULL; xmlNodePtr welcome = NULL; xmlNodePtr tmp1 = NULL; xmlNodePtr tmp2 = NULL; const char *join_to = NULL; if(action & A_JOIN_WELCOME && data == NULL) { crm_err("Attempt to send welcome message " "without a message to reply to!"); return I_NULL; /* return do_send_welcome_all( */ /* A_JOIN_WELCOME_ALL,cause,cur_state,current_input,data); */ } else if(action & A_JOIN_WELCOME) { welcome = (xmlNodePtr)data; join_to = xmlGetProp(welcome, XML_ATTR_HOSTFROM); if(join_to != NULL) { stopTimer(integration_timer); /* update node status */ crm_debug("Updating node state to %s for %s", CRMD_JOINSTATE_PENDING, join_to); update = create_node_state( join_to, join_to, NULL, NULL, CRMD_JOINSTATE_PENDING); tmp1 = create_cib_fragment(update, NULL); invoke_local_cib(NULL, tmp1, CRM_OP_UPDATE); free_xml(tmp1); /* Make sure they have the *whole* CIB */ crm_debug("Sending complete CIB to %s", join_to); tmp1 = get_cib_copy(); tmp2 = create_cib_fragment(tmp1, NULL); send_request(NULL, tmp2, CRM_OP_REPLACE, join_to, CRM_SYSTEM_CRMD, NULL); free_xml(tmp1); free_xml(tmp2); /* send the welcome */ crm_debug("Sending %s to %s", CRM_OP_WELCOME, join_to); send_request(NULL, NULL, CRM_OP_WELCOME, join_to, CRM_SYSTEM_CRMD, NULL); free_xml(update); /* if this client is sick, we shouldnt wait forever */ crm_debug("Restarting the integration timer"); startTimer(integration_timer); } else { crm_err("No recipient for welcome message"); } return I_NULL; } return I_ERROR; } /* A_JOIN_WELCOME_ALL */ enum crmd_fsa_input do_send_welcome_all(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { /* reset everyones status back to down or in_ccm in the CIB */ xmlNodePtr update = NULL; xmlNodePtr cib_copy = get_cib_copy(); xmlNodePtr tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy); xmlNodePtr tmp2 = NULL; /* Give everyone a chance to join before invoking the PolicyEngine */ stopTimer(integration_timer); startTimer(integration_timer); if(joined_nodes != NULL) { g_hash_table_destroy(joined_nodes); - joined_nodes = g_hash_table_new(&g_str_hash, &g_str_equal); } + joined_nodes = g_hash_table_new(&g_str_hash, &g_str_equal); /* catch any nodes that are active in the CIB but not in the CCM list*/ xml_child_iter( tmp1, node_entry, XML_CIB_TAG_STATE, const char *node_id = xmlGetProp(node_entry, XML_ATTR_UNAME); gpointer a_node = g_hash_table_lookup( fsa_membership_copy->members, node_id); if(a_node != NULL || (safe_str_eq(fsa_our_uname, node_id))) { /* handled by do_update_cib_node() */ continue; } tmp2 = create_node_state( node_id, node_id, XML_BOOLEAN_NO, NULL, CRMD_JOINSTATE_DOWN); if(update == NULL) { update = tmp2; } else { update = xmlAddSibling(update, tmp2); } ); /* now process the CCM data */ free_xml(do_update_cib_nodes(update, TRUE)); free_xml(cib_copy); /* Make sure everyone has the *whole* CIB */ tmp1 = get_cib_copy(); tmp2 = create_cib_fragment(tmp1, NULL); send_request(NULL, tmp2, CRM_OP_REPLACE, NULL, CRM_SYSTEM_CRMD, NULL); free_xml(tmp1); free_xml(tmp2); /* Avoid ordered message delays caused when the CRMd proc * isnt running yet (ie. send as a broadcast msg which are never * sent ordered. */ send_request(NULL, NULL, CRM_OP_WELCOME, NULL, CRM_SYSTEM_CRMD, NULL); /* No point hanging around in S_INTEGRATION if we're the only ones here! */ if(joined_nodes == NULL) { if(fsa_membership_copy->members_size == 1) { /* we're the only ones in here */ crm_info("Not expecting any join acks"); return I_SUCCESS; } } else if(g_hash_table_size(joined_nodes) >= (fsa_membership_copy->members_size -1)) { crm_info("That was the last outstanding join ack"); return I_SUCCESS; } /* dont waste time by invoking the pe yet; */ crm_debug("Still waiting on %d outstanding join acks", fsa_membership_copy->members_size - g_hash_table_size(joined_nodes) - 1); return 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; xmlNodePtr cib_copy; xmlNodePtr tmp1; xmlNodePtr tmp2; #if 0 if(we are sick) { log error ; return I_NULL; } #endif fsa_our_dc = xmlGetProp(welcome, XML_ATTR_HOSTFROM); if(fsa_our_dc == NULL) { crm_err("Failed to determin our DC"); return I_FAIL; } /* send our status section to the DC */ cib_copy = get_cib_copy(); tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy); if(tmp1 != NULL) { tmp2 = create_cib_fragment(tmp1->children, NULL); send_ha_reply(fsa_cluster_conn, welcome, tmp2); free_xml(tmp2); } free_xml(cib_copy); return 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) { xmlNodePtr msg = (xmlNodePtr)data; /* 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: crm_warn("Do not announce ourselves in state %s", fsa_state2string(cur_state)); return I_NULL; break; default: break; } if(AM_I_OPERATIONAL) { const char *from = xmlGetProp(msg, XML_ATTR_HOSTFROM); if(from == NULL) { crm_err("Failed to origin of ping message"); return I_FAIL; } send_request(NULL, NULL, CRM_OP_ANNOUNCE, from, CRM_SYSTEM_DC, NULL); } else { /* Delay announce until we have finished local startup */ crm_warn("Delaying announce until local startup is complete"); return I_NULL; } return 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) { xmlNodePtr tmp1; xmlNodePtr tmp2; xmlNodePtr cib_fragment; xmlNodePtr msg_cib; xmlNodePtr join_ack = (xmlNodePtr)data; gboolean is_a_member = FALSE; const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM); const char *ref = xmlGetProp(join_ack, XML_ATTR_REFERENCE); uuid_t uuid_raw; char *uuid_calc = NULL; gpointer join_node = g_hash_table_lookup(fsa_membership_copy->members, join_from); if(join_node != NULL) { is_a_member = TRUE; } cib_fragment = find_xml_node(join_ack, XML_TAG_FRAGMENT); crm_debug("Welcoming node %s after ACK (ref %s)", join_from, ref); if(is_a_member == FALSE) { crm_err("Node %s is not known to us (ref %s)", join_from, ref); /* make sure any information from this node is discarded, * it is invalid */ free_xml(cib_fragment); return I_FAIL; } /* add them to our list of CRMD_STATE_ACTIVE nodes - TODO: still used? TODO: check its not already there */ - g_hash_table_insert(joined_nodes, strdup(join_from),strdup(join_from)); + g_hash_table_insert(joined_nodes, strdup(join_from), strdup(join_from)); if(cib_fragment == NULL) { crm_err("No status information was part of the" " Welcome ACK from %s", join_from); return I_NULL; } create_node_entry(join_from, join_from, "member"); crm_malloc(uuid_calc, sizeof(char)*50); if(uuid_calc != NULL) { if(fsa_cluster_conn->llc_ops->get_uuid_by_name( fsa_cluster_conn, join_from, uuid_raw) == HA_FAIL) { crm_err("Could not calculate UUID for %s", join_from); crm_free(uuid_calc); uuid_calc = crm_strdup(join_from); } else { uuid_unparse(uuid_raw, uuid_calc); } } /* Make changes so that exp_state=active for this node when the update * is processed by A_CIB_INVOKE */ msg_cib = find_xml_node(cib_fragment, XML_TAG_CIB); tmp1 = get_object_root(XML_CIB_TAG_STATUS, msg_cib); tmp2 = find_entity(tmp1, XML_CIB_TAG_STATE, uuid_calc, FALSE); if(tmp2 == NULL) { crm_err("Status entry for %s not found in update, adding", join_from); tmp2 = create_xml_node(tmp1, XML_CIB_TAG_STATE); set_xml_property_copy(tmp2, XML_ATTR_UUID, uuid_calc); set_xml_property_copy(tmp2, XML_ATTR_UNAME, join_from); } crm_free(uuid_calc); /* make sure these values are correct in the CIB */ set_xml_property_copy( tmp2, XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE); set_xml_property_copy( - tmp2, XML_CIB_ATTR_JOINSTATE,CRMD_JOINSTATE_MEMBER); + tmp2, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_MEMBER); /* No point hanging around in S_INTEGRATION if we're the only ones here! */ if(g_hash_table_size(joined_nodes) >= (fsa_membership_copy->members_size -1)) { crm_info("That was the last outstanding join ack"); return I_SUCCESS; } /* dont waste time by invoking the pe yet; */ crm_debug("Still waiting on %d outstanding join acks", fsa_membership_copy->members_size - g_hash_table_size(joined_nodes) - 1); return I_CIB_OP; } diff --git a/crm/crmd/join_client.c b/crm/crmd/join_client.c new file mode 100644 index 0000000000..cafb961adc --- /dev/null +++ b/crm/crmd/join_client.c @@ -0,0 +1,175 @@ +/* + * 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 + + + +/* A_CL_JOIN_ANNOUNCE */ + +/* this is kind of a workaround for the the fact that we may not be around + * or are otherwise unable to reply when the DC sends out A_WELCOME_ALL + */ +enum crmd_fsa_input +do_cl_join_announce(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + xmlNodePtr msg = (xmlNodePtr)data; + + /* 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 */ + if(cur_state != S_PENDING) { + crm_warn("Do not announce ourselves in state %s", + fsa_state2string(cur_state)); + return I_NULL; + } + + if(AM_I_OPERATIONAL) { + const char *hb_from = xmlGetProp(msg, XML_ATTR_HOSTFROM); + + if(hb_from == NULL) { + crm_err("Failed to determin origin of hb message"); + return I_FAIL; + } + + if(fsa_our_dc == NULL) { + fsa_our_dc = hb_from; + + } else if(safe_str_eq(hb_from, fsa_our_dc)) { + crm_debug("Already announced to %s", hb_from); + return I_NULL; + + } else { + crm_warn("We announced ourselves to %s, but are" + " now receiving DC Heartbeats from %s", + fsa_our_dc, hb_from); + /* reset the fsa_our_dc to NULL */ + fsa_our_dc = NULL; + return I_NULL; /* for now, wait for the DC's + * to settle down + */ + } + send_request(NULL, NULL, CRM_OP_ANNOUNCE, + hb_from, CRM_SYSTEM_DC, NULL); + } else { + /* Delay announce until we have finished local startup */ + crm_warn("Delaying announce until local startup is complete"); + return I_NULL; + } + + return I_NULL; +} + + +/* A_CL_JOIN_REQUEST */ + +/* aka. accept the welcome offer */ +enum crmd_fsa_input +do_cl_join_request(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + xmlNodePtr tmp1; + xmlNodePtr welcome = (xmlNodePtr)data; + + const char *welcome_from = xmlGetProp(welcome, XML_ATTR_HOSTFROM); + +#if 0 + if(we are sick) { + log error ; + return I_NULL; + } +#endif + if(fsa_our_dc == NULL) { + fsa_our_dc = welcome_from; + + } else if(safe_str_neq(welcome_from, fsa_our_dc)) { + /* dont do anything until DC's sort themselves out */ + crm_err("Expected a welcome from %s, but %s replied", + fsa_our_dc, welcome_from); + + return I_NULL; + } + + /* include our CIB generation tuple */ + tmp1 = cib_get_generation(); + send_ha_reply(fsa_cluster_conn, welcome, tmp1); + free_xml(tmp1); + + return I_NULL; +} + +/* A_CL_JOIN_RESULT */ +/* aka. this is notification that we have (or have not) been accepted */ +enum crmd_fsa_input +do_cl_join_result(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + xmlNodePtr tmp1; + xmlNodePtr tmp2; + xmlNodePtr welcome = (xmlNodePtr)data; + + const char *welcome_from = xmlGetProp(welcome, XML_ATTR_HOSTFROM); + + gboolean was_nack = FALSE; +#if 0 + calculate if it was an ack or a nack +#endif + + if(was_nack) { + crm_err("Join with %s failed. NACK'd", welcome_from); + return I_ERROR; + } + + /* send our status section to the DC */ + tmp1 = do_lrm_query(TRUE); + if(tmp1 != NULL) { + tmp2 = create_cib_fragment(tmp1, NULL); + + send_ha_reply(fsa_cluster_conn, welcome, tmp2); + + free_xml(tmp2); + free_xml(tmp1); + } + + return I_SUCCESS; +} diff --git a/crm/crmd/join_dc.c b/crm/crmd/join_dc.c new file mode 100644 index 0000000000..a92662fdae --- /dev/null +++ b/crm/crmd/join_dc.c @@ -0,0 +1,331 @@ +/* + * 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 + +int num_join_invites = 0; +GHashTable *join_requests = NULL; +GHashTable *confirmed_nodes = NULL; +void finalize_join_for(gpointer key, gpointer value, gpointer user_data); + + +/* A_DC_JOIN_OFFER_ALL */ +enum crmd_fsa_input +do_dc_join_offer_all(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + /* reset everyones status back to down or in_ccm in the CIB */ + xmlNodePtr update = NULL; + xmlNodePtr cib_copy = get_cib_copy(); + xmlNodePtr tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy); + xmlNodePtr tmp2 = NULL; + + /* Give everyone a chance to join before invoking the PolicyEngine */ + stopTimer(integration_timer); + + if(join_requests != NULL) { + g_hash_table_destroy(join_requests); + } + join_requests = g_hash_table_new(&g_str_hash, &g_str_equal); + + /* mark ourselves joined */ + g_hash_table_insert(join_requests, crm_strdup(fsa_our_uname), + crm_strdup(CRMD_JOINSTATE_MEMBER)); + + + /* catch any nodes that are active in the CIB but not in the CCM list*/ + xml_child_iter( + tmp1, node_entry, XML_CIB_TAG_STATE, + + const char *node_id = xmlGetProp(node_entry, XML_ATTR_UNAME); + gpointer a_node = g_hash_table_lookup( + fsa_membership_copy->members, node_id); + + if(a_node != NULL || (safe_str_eq(fsa_our_uname, node_id))) { + /* handled by do_update_cib_node() */ + continue; + } + + tmp2 = create_node_state( + node_id, node_id, + XML_BOOLEAN_NO, NULL, CRMD_JOINSTATE_DOWN); + + if(update == NULL) { + update = tmp2; + } else { + update = xmlAddSibling(update, tmp2); + } + ); + + /* now process the CCM data */ + free_xml(do_update_cib_nodes(update, TRUE)); + free_xml(cib_copy); + + /* Avoid ordered message delays caused when the CRMd proc + * isnt running yet (ie. send as a broadcast msg which are never + * sent ordered. + */ + send_request(NULL, NULL, CRM_OP_WELCOME, + NULL, CRM_SYSTEM_CRMD, NULL); + +/* No point hanging around in S_INTEGRATION if we're the only ones here! */ + if(join_requests == NULL) { + if(fsa_membership_copy->members_size == 1) { + /* we're the only ones in here */ + crm_info("Not expecting any join acks"); + return I_SUCCESS; + } + + } else if(g_hash_table_size(join_requests) + >= (fsa_membership_copy->members_size -1)) { + crm_info("That was the last outstanding join ack"); + return I_SUCCESS; + } + + /* dont waste time by invoking the pe yet; */ + crm_debug("Still waiting on %d outstanding join acks", + fsa_membership_copy->members_size + - g_hash_table_size(join_requests) - 1); + + /* we shouldnt wait forever */ + crm_debug("Starting the integration timer"); + startTimer(integration_timer); + + return I_NULL; +} + +/* A_DC_JOIN_OFFER_ONE */ +enum crmd_fsa_input +do_dc_join_offer_one(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + xmlNodePtr update = NULL; + xmlNodePtr welcome = NULL; + const char *join_to = NULL; + + if(data == NULL) { + crm_err("Attempt to send welcome message " + "without a message to reply to!"); + return I_NULL; +/* return do_send_welcome_all( */ +/* A_JOIN_WELCOME_ALL,cause,cur_state,current_input,data); */ + + } + + welcome = (xmlNodePtr)data; + + join_to = xmlGetProp(welcome, XML_ATTR_HOSTFROM); + if(join_to != NULL) { + stopTimer(integration_timer); + + /* send the welcome */ + crm_debug("Sending %s to %s", CRM_OP_WELCOME, join_to); + + send_request(NULL, NULL, CRM_OP_WELCOME, + join_to, CRM_SYSTEM_CRMD, NULL); + + free_xml(update); + + /* if this client is sick, we shouldnt wait forever */ + crm_debug("Restarting the integration timer"); + startTimer(integration_timer); + + } else { + crm_err("No recipient for welcome message"); + } + + return I_NULL; +} + +/* A_DC_JOIN_PROCESS_REQ */ +enum crmd_fsa_input +do_dc_join_req(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + xmlNodePtr generation; + xmlNodePtr join_ack = (xmlNodePtr)data; + const char *ack_nack = "memeber"; + + gboolean is_a_member = FALSE; + const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM); + const char *ref = xmlGetProp(join_ack, XML_ATTR_REFERENCE); + + gpointer join_node = + g_hash_table_lookup(fsa_membership_copy->members, join_from); + + if(join_node != NULL) { + is_a_member = TRUE; + } + + generation = find_xml_node(join_ack, "generation_tuple"); + + crm_debug("Welcoming node %s after ACK (ref %s)", + join_from, ref); + + if(is_a_member == FALSE) { + crm_err("Node %s is not known to us (ref %s)", + join_from, ref); + /* NACK them */ + return I_FAIL; + + } else if(/* some reason */ 0) { + /* NACK this client */ + ack_nack = "down"; + } + + + /* add them to our list of CRMD_STATE_ACTIVE nodes + TODO: check its not already there + */ + g_hash_table_insert(join_requests, + crm_strdup(join_from), crm_strdup(ack_nack)); + +/* No point hanging around in S_INTEGRATION if we're the only ones here! */ + if(g_hash_table_size(join_requests) + >= fsa_membership_copy->members_size) { + crm_info("That was the last outstanding join ack"); + return I_SUCCESS; + } + + /* dont waste time by invoking the pe yet; */ + crm_debug("Still waiting on %d outstanding join acks", + fsa_membership_copy->members_size + - g_hash_table_size(join_requests)); + + return I_NULL; +} + + +/* A_DC_JOIN_FINALIZE */ +enum crmd_fsa_input +do_dc_join_finalize(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + num_join_invites = 0; + g_hash_table_foreach(join_requests, finalize_join_for, NULL); + + if(confirmed_nodes != NULL) { + g_hash_table_destroy(confirmed_nodes); + } + confirmed_nodes = g_hash_table_new(&g_str_hash, &g_str_equal); + + /* mark ourselves confirmed */ + g_hash_table_insert(confirmed_nodes, crm_strdup(fsa_our_uname), + crm_strdup(CRMD_JOINSTATE_MEMBER)); + + + return I_NULL; +} + +/* A_DC_JOIN_PROCESS_ACK */ +enum crmd_fsa_input +do_dc_join_ack(long long action, + enum crmd_fsa_cause cause, + enum crmd_fsa_state cur_state, + enum crmd_fsa_input current_input, + void *data) +{ + /* now update them to "member" */ + xmlNodePtr tmp1 = NULL, update = NULL; + xmlNodePtr join_ack = (xmlNodePtr)data; + const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM); + + const char *join_state = (const char *) + g_hash_table_lookup(join_requests, join_from); + + if(join_state == NULL + || safe_str_neq(join_state, CRMD_JOINSTATE_MEMBER)) { + crm_err("Node %s wasnt invited to join the cluster", join_from); + return I_NULL; + } + + g_hash_table_insert(confirmed_nodes, crm_strdup(join_from), + crm_strdup(CRMD_JOINSTATE_MEMBER)); + + /* update node entry in the status section */ + crm_debug("Updating node state to %s for %s", join_state, join_from); + update = create_node_state( + join_from, join_from, NULL, ONLINESTATUS, join_state); + + set_xml_property_copy(update,XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE); + + tmp1 = create_cib_fragment(update, NULL); + invoke_local_cib(NULL, tmp1, CRM_OP_UPDATE); + + free_xml(tmp1); + + if(num_join_invites <= g_hash_table_size(confirmed_nodes)) { + crm_info("That was the last outstanding join confirmation"); + return I_SUCCESS; + } + + /* dont waste time by invoking the pe yet; */ + crm_debug("Still waiting on %d outstanding join confirmations", + num_join_invites - g_hash_table_size(confirmed_nodes)); + + return I_CIB_OP; +} + +void +finalize_join_for(gpointer key, gpointer value, gpointer user_data) +{ + if(key == NULL || value == NULL) { + return; + } + xmlNodePtr tmp1 = NULL; + const char *join_to = (const char *)key; + const char *join_state = (const char *)value; + + /* make sure the node exists in the config section */ + create_node_entry(join_to, join_to, CRMD_JOINSTATE_MEMBER); + + if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { + num_join_invites++; + } + + /* TODO: create a ack or nack in tmp1 */ + + /* send the ack/nack to the node */ + send_request(NULL, tmp1, CRM_OP_JOINACK, + join_to, CRM_SYSTEM_CRMD, NULL); + + free_xml(tmp1); +} diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c index f91ceb1343..4a68034877 100644 --- a/crm/crmd/lrm.c +++ b/crm/crmd/lrm.c @@ -1,771 +1,736 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include /* for access */ #include #include #include #include #include #include #include #include #include -xmlNodePtr do_lrm_query(gboolean); gboolean build_suppported_RAs( xmlNodePtr metadata_list, xmlNodePtr xml_agent_list); gboolean build_active_RAs(xmlNodePtr rsc_list); void do_update_resource(lrm_rsc_t *rsc, lrm_op_t *op); enum crmd_fsa_input do_lrm_rsc_op( lrm_rsc_t *rsc, char *rid, const char *operation, xmlNodePtr msg); enum crmd_fsa_input do_fake_lrm_op(gpointer data); GHashTable *xml2list(xmlNodePtr parent, const char **attr_path, int depth); GHashTable *monitors = NULL; const char *rsc_path[] = { "msg_data", "rsc_op", "resource", "instance_attributes", "rsc_parameters" }; /* 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_FAIL; int ret = HA_OK; if(action & A_LRM_DISCONNECT) { fsa_lrm_conn->lrm_ops->signoff(fsa_lrm_conn); /* TODO: Clean up the hashtable */ } if(action & A_LRM_CONNECT) { crm_trace("LRM: connect..."); monitors = g_hash_table_new(g_str_hash, g_str_equal); fsa_lrm_conn = ll_lrm_new(XML_CIB_TAG_LRM); if(NULL == fsa_lrm_conn) { return failed; } crm_trace("LRM: sigon..."); ret = fsa_lrm_conn->lrm_ops->signon( fsa_lrm_conn, CRM_SYSTEM_CRMD); if(ret != HA_OK) { crm_err("Failed to sign on to the LRM"); return failed; } crm_trace("LRM: set_lrm_callback..."); ret = fsa_lrm_conn->lrm_ops->set_lrm_callback( fsa_lrm_conn, lrm_op_callback); if(ret != HA_OK) { crm_err("Failed to set LRM callbacks"); return failed; } /* TODO: create a destroy handler that causes * some recovery to happen */ G_main_add_fd(G_PRIORITY_LOW, fsa_lrm_conn->lrm_ops->inputfd(fsa_lrm_conn), FALSE, lrm_dispatch, fsa_lrm_conn, default_ipc_input_destroy); } if(action & ~(A_LRM_CONNECT|A_LRM_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return I_NULL; } gboolean build_suppported_RAs(xmlNodePtr metadata_list, xmlNodePtr xml_agent_list) { int lpc = 0, llpc = 0; GList *types = NULL; GList *classes = NULL; const char *version = NULL; const char *ra_data = NULL; /* GHashTable *metadata = NULL; */ xmlNodePtr xml_agent = NULL; xmlNodePtr xml_metadata = NULL; xmlNodePtr tmp = NULL; classes = fsa_lrm_conn->lrm_ops->get_rsc_class_supported(fsa_lrm_conn); slist_iter( class, char, classes, lpc, types = fsa_lrm_conn->lrm_ops->get_rsc_type_supported( fsa_lrm_conn, class); /* metadata = fsa_lrm_conn->lrm_ops->get_all_type_metadatas( fsa_lrm_conn, class); */ slist_iter( type, char, types, llpc, version = "1"; xml_agent = create_xml_node( xml_agent_list, "lrm_agent"); set_xml_property_copy(xml_agent, "class", class); set_xml_property_copy(xml_agent, XML_ATTR_TYPE, type); /* ra_data = g_hashtable_lookup(metadata, type); */ if(ra_data != NULL) { xml_metadata = create_xml_node( xml_metadata, "agent_metadata"); set_xml_property_copy( xml_metadata, "class", class); set_xml_property_copy( xml_metadata, XML_ATTR_TYPE, type); tmp = string2xml(ra_data); if(tmp != NULL) { xmlAddChild(xml_metadata, tmp); } /* extract version */ } set_xml_property_copy(xml_agent, "version", version); ) g_list_free(types); ); g_list_free(classes); return TRUE; } gboolean build_active_RAs(xmlNodePtr rsc_list) { int lpc = 0, llpc = 0; GList *op_list = NULL; GList *lrm_list = NULL; gboolean found_op = FALSE; state_flag_t cur_state = 0; const char *this_op = NULL; char *tmp = NULL; lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); slist_iter( rid, char, lrm_list, lpc, /* GHashTable* params; */ lrm_rsc_t *the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); xmlNodePtr xml_rsc = create_xml_node( rsc_list, XML_LRM_TAG_RESOURCE); crm_info("Processing lrm_rsc_t entry %s", rid); if(the_rsc == NULL) { crm_err("NULL resource returned from the LRM"); continue; } set_xml_property_copy(xml_rsc, XML_ATTR_ID, the_rsc->id); set_xml_property_copy( xml_rsc, XML_LRM_ATTR_TARGET, fsa_our_uname); op_list = the_rsc->ops->get_cur_state(the_rsc, &cur_state); crm_verbose("\tcurrent state:%s\n", cur_state==LRM_RSC_IDLE?"Idle":"Busy"); slist_iter( op, lrm_op_t, op_list, llpc, this_op = op->op_type; crm_debug("Processing op %s for %s (status=%d, rc=%d)", op->op_type, the_rsc->id, op->op_status, op->rc); if(op->rc != 0 || safe_str_neq(this_op, CRMD_RSCSTATE_MON)){ set_xml_property_copy( xml_rsc, XML_LRM_ATTR_RSCSTATE, op->user_data); set_xml_property_copy( xml_rsc, XML_LRM_ATTR_LASTOP, this_op); tmp = crm_itoa(op->rc); set_xml_property_copy( xml_rsc, XML_LRM_ATTR_RC, tmp); crm_free(tmp); tmp = crm_itoa(op->op_status); set_xml_property_copy( xml_rsc, XML_LRM_ATTR_OPSTATUS, tmp); crm_free(tmp); /* we only want the last one */ found_op = TRUE; break; } else { set_xml_property_copy( xml_rsc, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_START_OK); set_xml_property_copy( xml_rsc, XML_LRM_ATTR_LASTOP, CRMD_RSCSTATE_START); tmp = crm_itoa(op->rc); set_xml_property_copy( xml_rsc, XML_LRM_ATTR_RC, tmp); crm_free(tmp); set_xml_property_copy( xml_rsc, XML_LRM_ATTR_OPSTATUS, "0"); /* we only want the last one */ found_op = TRUE; break; } ); if(found_op == FALSE) { crm_err("Could not properly determin last op" " for %s from %d entries", the_rsc->id, g_list_length(op_list)); } g_list_free(op_list); ); g_list_free(lrm_list); return TRUE; } xmlNodePtr do_lrm_query(gboolean is_replace) { xmlNodePtr xml_result= NULL; xmlNodePtr xml_state = create_xml_node(NULL, XML_CIB_TAG_STATE); xmlNodePtr xml_data = create_xml_node(xml_state, XML_CIB_TAG_LRM); xmlNodePtr rsc_list = create_xml_node(xml_data,XML_LRM_TAG_RESOURCES); xmlNodePtr xml_agent_list = create_xml_node(xml_data, "lrm_agents"); xmlNodePtr xml_metadata_list = create_xml_node(xml_data, "metatdata"); /* Build a list of supported agents and metadata */ build_suppported_RAs(xml_metadata_list, xml_agent_list); /* Build a list of active (not always running) resources */ build_active_RAs(rsc_list); -#ifndef USE_FAKE_LRM if(is_replace) { set_xml_property_copy(xml_state, "replace", XML_CIB_TAG_LRM); } -#else - if(is_replace) { - set_xml_property_copy(xml_data, "replace", "lrm_agents"); - } -#endif set_uuid(xml_state, XML_ATTR_UUID, fsa_our_uname); set_xml_property_copy(xml_state, XML_ATTR_UNAME, fsa_our_uname); xml_result = create_cib_fragment(xml_state, NULL); return xml_result; } -/* A_UPDATE_NODESTATUS */ -enum crmd_fsa_input -do_update_node_status(long long action, - enum crmd_fsa_cause cause, - enum crmd_fsa_state cur_state, - enum crmd_fsa_input current_input, - void *data) -{ - xmlNodePtr update = NULL; - - if(action & A_UPDATE_NODESTATUS) { - - update = do_lrm_query(TRUE); - - /* this only happens locally. the updates are pushed out - * as part of the join process - */ - invoke_local_cib(NULL, update, CRM_OP_UPDATE); - - free_xml(update); - - return I_NULL; - } - - return I_ERROR; -} - - /* A_LRM_INVOKE */ enum crmd_fsa_input do_lrm_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input next_input = I_NULL; xmlNodePtr msg; const char *operation = NULL; char rid[64]; const char *id_from_cib = NULL; const char *crm_op = NULL; lrm_rsc_t *rsc = NULL; #ifdef USE_FAKE_LRM return do_fake_lrm_op(data); #endif msg = (xmlNodePtr)data; operation = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -3, XML_LRM_ATTR_TASK, TRUE); /* xmlNodePtr tmp = find_xml_node_nested(msg, rsc_path, DIMOF(rsc_path) -3); */ /* operation = xmlGetProp(tmp, XML_LRM_ATTR_TASK); */ if(operation == NULL) { crm_err("No value for %s in message at level %d.", XML_LRM_ATTR_TASK, DIMOF(rsc_path) -3); return I_NULL; } id_from_cib = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_ID, TRUE); if(id_from_cib == NULL) { crm_err("No value for %s in message at level %d.", XML_ATTR_ID, DIMOF(rsc_path) -2); return I_NULL; } /* only the first 16 chars are used by the LRM */ strncpy(rid, id_from_cib, 64); rid[63] = 0; crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); if(crm_op != NULL && safe_str_eq(crm_op, "lrm_query")) { xmlNodePtr data, reply; data = do_lrm_query(FALSE); reply = create_reply(msg, data); relay_message(reply, TRUE); free_xml(data); free_xml(reply); } else if(operation != NULL) { next_input = do_lrm_rsc_op(rsc, rid, operation, msg); } else { next_input = I_ERROR; } return next_input; } enum crmd_fsa_input do_lrm_rsc_op( lrm_rsc_t *rsc, char *rid, const char *operation, xmlNodePtr msg) { lrm_op_t* op = NULL; int monitor_call_id = 0; if(rsc == NULL) { /* add it to the list */ crm_verbose("adding rsc %s before operation", rid); fsa_lrm_conn->lrm_ops->add_rsc( fsa_lrm_conn, rid, get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, "class", TRUE), get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_TYPE, TRUE), NULL,NULL); rsc = fsa_lrm_conn->lrm_ops->get_rsc( fsa_lrm_conn, rid); } if(rsc == NULL) { crm_err("Could not add resource to LRM"); return I_FAIL; } /* now do the op */ crm_info("Performing op %s on %s", operation, rid); op = g_new(lrm_op_t, 1); op->op_type = g_strdup(operation); op->params = xml2list(msg, rsc_path, DIMOF(rsc_path)); op->timeout = 0; op->interval = 0; op->user_data = NULL; op->target_rc = EVERYTIME; if(safe_str_eq(CRMD_RSCSTATE_START, operation)) { op->user_data = crm_strdup(CRMD_RSCSTATE_START_OK); } else if(safe_str_eq(CRMD_RSCSTATE_STOP, operation)) { op->user_data = crm_strdup(CRMD_RSCSTATE_STOP_OK); } else { crm_warn("Using status \"complete\" for op \"%s\"" "... this is still in the experimental stage.", operation); op->user_data = crm_strdup(CRMD_RSCSTATE_GENERIC_OK); } rsc->ops->perform_op(rsc, op); if(safe_str_eq(operation, CRMD_RSCSTATE_START)) { /* initiate the monitor action */ op = g_new(lrm_op_t, 1); op->op_type = g_strdup(CRMD_RSCSTATE_MON); op->params = NULL; op->user_data = crm_strdup(CRMD_RSCSTATE_MON_OK); op->timeout = 0; op->interval = 9000; op->target_rc = CHANGED; monitor_call_id = rsc->ops->perform_op(rsc, op); if (monitor_call_id < 0) { g_hash_table_insert( monitors, strdup(rsc->id), GINT_TO_POINTER(monitor_call_id)); } } else if(safe_str_eq(operation, CRMD_RSCSTATE_STOP)) { gpointer foo = g_hash_table_lookup(monitors, rsc->id); int monitor_call_id = GPOINTER_TO_INT(foo); if(monitor_call_id > 0) { crm_info("Stopping status op for %s", rsc->id); rsc->ops->stop_op(rsc, monitor_call_id); g_hash_table_remove(monitors, rsc->id); /* TODO: Clean up key */ } else { crm_err("No monitor operation found for %s", rsc->id); } } return I_NULL; } GHashTable * xml2list(xmlNodePtr parent, const char**attr_path, int depth) { xmlNodePtr node_iter = NULL; GHashTable *nvpair_hash = g_hash_table_new(&g_str_hash, &g_str_equal); xmlNodePtr nvpair_list = find_xml_node_nested(parent, attr_path, depth); while(nvpair_list != NULL){ node_iter = nvpair_list->children; while(node_iter != NULL) { const char *key = xmlGetProp( node_iter, XML_NVPAIR_ATTR_NAME); const char *value = xmlGetProp( node_iter, XML_NVPAIR_ATTR_VALUE); crm_verbose("Added %s=%s", key, value); g_hash_table_insert (nvpair_hash, crm_strdup(key), crm_strdup(value)); node_iter = node_iter->next; } nvpair_list=nvpair_list->next; } return nvpair_hash; } void do_update_resource(lrm_rsc_t *rsc, lrm_op_t* op) { /* */ xmlNodePtr update, iter; char *tmp = NULL; xmlNodePtr fragment; int len = 0; char *fail_state = NULL; if(op == NULL || rsc == NULL) { crm_err("Either resouce or op was not specified"); return; } update = create_xml_node(NULL, XML_CIB_TAG_STATE); set_uuid(update, XML_ATTR_UUID, fsa_our_uname); set_xml_property_copy(update, XML_ATTR_UNAME, fsa_our_uname); iter = create_xml_node(update, XML_CIB_TAG_LRM); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); iter = create_xml_node(iter, "lrm_resource"); set_xml_property_copy(iter, XML_ATTR_ID, rsc->id); set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, op->op_type); len = strlen(op->op_type); len += strlen("_failed_"); crm_malloc(fail_state, sizeof(char)*len); if(fail_state != NULL) { sprintf(fail_state, "%s_failed", op->op_type); } switch(op->op_status) { case LRM_OP_CANCELLED: break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_err("An LRM operation failed" " or was aborted"); set_xml_property_copy( iter, XML_LRM_ATTR_RSCSTATE, fail_state); break; case LRM_OP_DONE: set_xml_property_copy( iter, XML_LRM_ATTR_RSCSTATE, (const char*)op->user_data); break; } crm_free(fail_state); tmp = crm_itoa(op->rc); set_xml_property_copy(iter, XML_LRM_ATTR_RC, tmp); crm_free(tmp); tmp = crm_itoa(op->op_status); set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATUS, tmp); crm_free(tmp); set_xml_property_copy(iter, XML_LRM_ATTR_TARGET, fsa_our_uname); fragment = create_cib_fragment(update, NULL); send_request(NULL, fragment, CRM_OP_UPDATE, fsa_our_dc, CRM_SYSTEM_DCIB, NULL); free_xml(fragment); free_xml(update); } enum crmd_fsa_input do_lrm_event(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, void *data) { if(cause == C_LRM_OP_CALLBACK) { lrm_op_t* op = (lrm_op_t*)data; lrm_rsc_t* rsc = op->rsc; switch(op->op_status) { case LRM_OP_ERROR: case LRM_OP_CANCELLED: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_err("An LRM operation failed" " or was aborted"); /* fall through */ case LRM_OP_DONE: do_update_resource(rsc, op); break; } } else { return I_FAIL; } return I_NULL; } enum crmd_fsa_input do_fake_lrm_op(gpointer data) { xmlNodePtr msg = NULL; const char *crm_op = NULL; const char *operation = NULL; const char *id_from_cib = NULL; long int op_code = 0; const char *op_status = NULL; xmlNodePtr update = NULL; xmlNodePtr state = NULL; xmlNodePtr iter = NULL; char *op_code_s = NULL; if(data == NULL) { return I_ERROR; } msg = (xmlNodePtr)data; operation = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -3, XML_LRM_ATTR_TASK, TRUE); id_from_cib = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_ID, TRUE); crm_op = get_xml_attr(msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); if(safe_str_eq(crm_op, "rsc_op")) { state = create_xml_node(NULL, XML_CIB_TAG_STATE); iter = create_xml_node(state, XML_CIB_TAG_LRM); crm_info("Performing %s on %s", operation, id_from_cib); /* so we can identify where to do the update */ set_uuid(state, XML_ATTR_UUID, fsa_our_uname); iter = create_xml_node(iter, XML_LRM_TAG_RESOURCES); iter = create_xml_node(iter, "lrm_resource"); set_xml_property_copy(iter, XML_ATTR_ID, id_from_cib); set_xml_property_copy(iter, XML_LRM_ATTR_LASTOP, operation); #if 0 /* introduce a 10% chance of an action failing */ op_code = random(); #endif if((op_code % 10) == 1) { op_code = 1; } else { op_code = 0; } op_code_s = crm_itoa(op_code); if(op_code) { /* fail */ if(safe_str_eq(operation, "start")){ op_status = "stopped"; } else { op_status = "started"; } } else { /* pass */ if(safe_str_eq(operation, "start")){ op_status = "started"; } else { op_status = "stopped"; } } set_xml_property_copy(iter, XML_LRM_ATTR_RSCSTATE,op_status); set_xml_property_copy(iter, XML_LRM_ATTR_OPSTATUS, op_code_s); set_xml_property_copy( iter, XML_LRM_ATTR_TARGET, fsa_our_uname); crm_free(op_code_s); update = create_cib_fragment(state, NULL); send_request(NULL, update, CRM_OP_UPDATE, fsa_our_dc, CRM_SYSTEM_DCIB, NULL); } return I_NULL; } diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c index 495477a81f..7af1505769 100644 --- a/crm/crmd/messages.c +++ b/crm/crmd/messages.c @@ -1,939 +1,1010 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include FILE *msg_out_strm = NULL; FILE *router_strm = NULL; GListPtr fsa_message_queue = NULL; extern void crm_shutdown(int nsig); gboolean relay_message( xmlNodePtr xml_relay_message, gboolean originated_locally); gboolean send_ha_reply( ll_cluster_t *hb_cluster, xmlNodePtr xml_request, xmlNodePtr xml_response_data); gboolean send_xmlha_message(ll_cluster_t *hb_fd, xmlNodePtr root); +enum crmd_fsa_input handle_request(xmlNodePtr stored_msg); +enum crmd_fsa_input handle_response(xmlNodePtr stored_msg); +enum crmd_fsa_input handle_shutdown_request(xmlNodePtr stored_msg); + + #ifdef MSG_LOG # define ROUTER_RESULT(x) char *msg_text = dump_xml_formatted(xml_relay_message);\ if(router_strm == NULL) { \ router_strm = fopen(DEVEL_DIR"/router.log", "w"); \ } \ fprintf(router_strm, "[%d RESULT (%s)]\t%s\t%s\n", \ AM_I_DC, \ xmlGetProp(xml_relay_message, XML_ATTR_REFERENCE), \ x, msg_text); \ fflush(router_strm); \ crm_free(msg_text); \ crm_xml_devel(xml_relay_message, x); #else # define ROUTER_RESULT(x) crm_xml_devel(xml_relay_message, x); #endif /* returns the current head of the FIFO queue */ GListPtr put_message(xmlNodePtr new_message) { int old_len = g_list_length(fsa_message_queue); /* make sure to free it properly later */ fsa_message_queue = g_list_append(fsa_message_queue, copy_xml_node_recursive(new_message)); crm_verbose("Queue len: %d -> %d", old_len, g_list_length(fsa_message_queue)); if(old_len == g_list_length(fsa_message_queue)){ crm_err("Couldnt add message to the queue"); } return fsa_message_queue; } /* returns the next message */ xmlNodePtr get_message(void) { xmlNodePtr message = g_list_nth_data(fsa_message_queue, 0); fsa_message_queue = g_list_remove(fsa_message_queue, message); return message; } /* returns the current head of the FIFO queue */ gboolean is_message(void) { return (g_list_length(fsa_message_queue) > 0); } /* A_MSG_STORE */ enum crmd_fsa_input do_msg_store(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { /* xmlNodePtr new_message = (xmlNodePtr)data; */ /* put_message(new_message); */ return 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; #if 0 /* if(cause == C_IPC_MESSAGE) { */ if (crmd_authorize_message(root_xml_node, msg, curr_client) == FALSE) { crm_debug("Message not authorized\t%s", dump_xml_formatted(root_xml_node, FALSE)); 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_trace("Defering local processing of message"); put_message(xml_message); result = I_REQUEST; break; } } } return result; } /* * This method adds a copy of xml_response_data */ gboolean send_request(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation, const char *host_to, const char *sys_to, char **msg_reference) { xmlNodePtr local_options = NULL; gboolean was_sent = FALSE; xmlNodePtr request = NULL; if(msg_options == NULL) { local_options = create_xml_node(NULL, XML_TAG_OPTIONS); msg_options = local_options; } set_xml_property_copy(msg_options, XML_ATTR_OP, operation); request = create_request( msg_options, msg_data, host_to, sys_to, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL, NULL); /* crm_xml_devel(request, "Final request..."); */ if(msg_reference != NULL) { *msg_reference = crm_strdup(xmlGetProp(request, XML_ATTR_REFERENCE)); } was_sent = relay_message(request, TRUE); if(was_sent == FALSE) { put_message(request); } free_xml(request); free_xml(local_options); return was_sent; } /* * This method adds a copy of xml_response_data */ gboolean store_request(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation, const char *sys_to) { xmlNodePtr request = NULL; msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS, XML_ATTR_OP, operation, TRUE); crm_verbose("Storing op=%s message for later processing", operation); request = create_request(msg_options, msg_data, NULL, sys_to, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL, NULL); put_message(request); free_xml(request); return 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 processing_complete = TRUE; const char *host_to = xmlGetProp(xml_relay_message,XML_ATTR_HOSTTO); const char *sys_to = xmlGetProp(xml_relay_message,XML_ATTR_SYSTO); crm_debug("Routing message %s", xmlGetProp(xml_relay_message, XML_ATTR_REFERENCE)); if(xml_relay_message == NULL) { crm_err("Cannot route empty message"); return TRUE; } if(strcmp(CRM_OP_HELLO, xml_relay_message->name) == 0) { /* quietly ignore */ return TRUE; } if(strcmp(XML_MSG_TAG, xml_relay_message->name) != 0) { crm_xml_err(xml_relay_message, "Bad message type, should be crm_message"); return TRUE; } if(sys_to == NULL) { crm_xml_err(xml_relay_message, "Message did not have any value for sys_to"); return 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; } crm_trace("is_local %d", is_local); crm_trace("is_for_dcib %d", is_for_dcib); crm_trace("is_for_dc %d", is_for_dc); crm_trace("is_for_crm %d", is_for_crm); crm_trace("AM_I_DC %d", AM_I_DC); crm_trace("sys_to %s", crm_str(sys_to)); crm_trace("host_to %s", crm_str(host_to)); 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); } else { ROUTER_RESULT("Message result: Discard, not DC"); /* discard */ } } else if(is_local && (is_for_crm || is_for_cib)) { ROUTER_RESULT("Message result: CRMd process"); processing_complete = FALSE; /* more to be done by caller */ } else if(is_local) { ROUTER_RESULT("Message result: Local relay"); send_msg_via_ipc(xml_relay_message, sys_to); } else { ROUTER_RESULT("Message result: External relay"); send_msg_via_ha(xml_relay_message, host_to); } return processing_complete; } gboolean crmd_authorize_message( xmlNodePtr root_xml_node, IPC_Message *client_msg, crmd_client_t *curr_client) { /* check the best case first */ const char *sys_from = xmlGetProp(root_xml_node, XML_ATTR_SYSFROM); char *uuid = NULL; char *client_name = NULL; char *major_version = NULL; char *minor_version = NULL; const char *filtered_from; gpointer table_key = NULL; gboolean result; struct crm_subsystem_s *the_subsystem = NULL; gboolean can_reply = FALSE; /* no-one has registered with this id */ const char *op = get_xml_attr( root_xml_node, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); if (safe_str_neq(CRM_OP_HELLO, op)) { if(sys_from == NULL) { crm_warn("Message [%s] was had no value for %s... discarding", xmlGetProp(root_xml_node, XML_ATTR_REFERENCE), XML_ATTR_SYSFROM); return FALSE; } 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_verbose("Message reply can%s be routed from %s.", can_reply?"":" not", sys_from); if(can_reply == FALSE) { crm_warn("Message [%s] not authorized", xmlGetProp(root_xml_node, XML_ATTR_REFERENCE)); } return can_reply; } crm_debug("received client join msg: %s", (char*)client_msg->msg_body); result = process_hello_message(root_xml_node, &uuid, &client_name, &major_version, &minor_version); if (result == TRUE) { /* check version */ int mav = atoi(major_version); int miv = atoi(minor_version); if (mav < 0 || miv < 0) { crm_err("Client version (%d:%d) is not acceptable", mav, miv); result = FALSE; } crm_free(major_version); crm_free(minor_version); } if (result == TRUE) { /* if we already have one of those clients * only applies to te, pe etc. not admin clients */ if (client_name == NULL) { crm_warn("Client had not registered with us yet"); } else if (strcmp(CRM_SYSTEM_PENGINE, client_name) == 0) { the_subsystem = pe_subsystem; } else if (strcmp(CRM_SYSTEM_TENGINE, client_name) == 0) { the_subsystem = te_subsystem; } else if (strcmp(CRM_SYSTEM_CIB, client_name) == 0) { the_subsystem = cib_subsystem; } if (the_subsystem != NULL) { /* do we already have one? */ result =(fsa_input_register & the_subsystem->flag)==0; if(result) { the_subsystem->ipc = curr_client->client_channel; } /* else we didnt ask for the client to start */ } else if(client_name != NULL && uuid != NULL) { table_key = (gpointer) generate_hash_key(client_name, uuid); } else { result = FALSE; crm_err("Bad client details (client_name=%s, uuid=%s)", crm_str(client_name), uuid); } } if(result == TRUE && table_key == NULL) { table_key = (gpointer)crm_strdup(client_name); } if (result == TRUE) { crm_info("Accepted client %s", (char*)table_key); curr_client->table_key = table_key; curr_client->sub_sys = crm_strdup(client_name); curr_client->uuid = crm_strdup(uuid); g_hash_table_insert (ipc_clients, table_key, curr_client->client_channel); send_hello_message(curr_client->client_channel, "n/a", CRM_SYSTEM_CRMD, "0", "1"); crm_debug("Updated client list with %s", (char*)table_key); if(the_subsystem != NULL) { set_bit_inplace(&fsa_input_register, the_subsystem->flag); } s_crmd_fsa(C_SUBSYSTEM_CONNECT, I_NULL, NULL); } else { crm_err("Rejected client logon request"); curr_client->client_channel->ch_status = IPC_DISC_PENDING; } if(uuid != NULL) crm_free(uuid); if(client_name != NULL) crm_free(client_name); /* hello messages should never be processed further */ return FALSE; } enum crmd_fsa_input handle_message(xmlNodePtr stored_msg) +{ + enum crmd_fsa_input next_input = I_NULL; + const char *type = get_xml_attr( + stored_msg, NULL, XML_ATTR_MSGTYPE, TRUE); + + if(safe_str_eq(type, XML_ATTR_REQUEST)) { + next_input = handle_request(stored_msg); + + } else if(safe_str_eq(type, XML_ATTR_RESPONSE)) { + next_input = handle_response(stored_msg); + + } else { + crm_err("Unknown message type: %s", type); + } + +/* crm_verbose("%s: Next input is %s", __FUNCTION__, */ +/* fsa_input2string(next_input)); */ + + return next_input; +} + + +enum crmd_fsa_input +handle_request(xmlNodePtr stored_msg) { xmlNodePtr wrapper = NULL; 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); + stored_msg, NULL, XML_ATTR_SYSTO, TRUE); const char *host_from= get_xml_attr( - stored_msg, NULL, XML_ATTR_HOSTFROM, FALSE); - - const char *msg_ref = get_xml_attr( - stored_msg, NULL, XML_ATTR_REFERENCE, TRUE); + stored_msg, NULL, XML_ATTR_HOSTFROM, FALSE); - 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); -/* crm_xml_devel(stored_msg, "Processing message"); */ - - crm_verbose("Received %s %s in state %s", - op, type, fsa_state2string(fsa_state)); + crm_verbose("Received %s in state %s", + op, fsa_state2string(fsa_state)); - if(type == NULL || op == NULL) { - crm_err("Ignoring message (type=%s), (op=%s)", - type, op); - crm_xml_devel(stored_msg, "Bad message"); + if(op == NULL) { + crm_xml_err(stored_msg, "Bad message"); + + /*========== common actions ==========*/ + } else if(strcmp(op, CRM_OP_VOTE) == 0) { + next_input = I_ELECTION; + + } else if(strcmp(op, "init_shutdown") == 0) { + + crm_shutdown(SIGTERM); + /*next_input = I_SHUTDOWN; */ + next_input = I_NULL; + + } else if(strcmp(op, CRM_OP_QUERY) == 0) { + + next_input = I_CIB_OP; + + } else if(strcmp(op, CRM_OP_PING) == 0) { + /* eventually do some stuff to figure out + * if we /are/ ok + */ + xmlNodePtr ping = createPingAnswerFragment(sys_to, "ok"); + + set_xml_property_copy(ping, "crmd_state", + fsa_state2string(fsa_state)); + + wrapper = create_reply(stored_msg, ping); + + relay_message(wrapper, TRUE); + free_xml(wrapper); + + } else if(strcmp(op, CRM_OP_JOINACK) == 0) { + next_input = I_JOIN_RESULT; + + } else if(strcmp(op, "init_shutdown") == 0) { - } else if(strcmp(type, XML_ATTR_REQUEST) == 0){ - if(strcmp(op, CRM_OP_HBEAT) == 0) { - next_input = I_DC_HEARTBEAT; + crm_shutdown(SIGTERM); + /*next_input = I_SHUTDOWN; */ + next_input = I_NULL; - } else if(strcmp(op, CRM_OP_VOTE) == 0) { - next_input = I_ELECTION; +#if 0 + /* probably better to do this via signals on the + * local node + */ + } else if(strcmp(op, "debug_inc") == 0) { + int level = get_crm_log_level(); + set_crm_log_level(level+1); + crm_info("Debug set to %d (was %d)", + get_crm_log_level(), level); + + } else if(strcmp(op, "debug_dec") == 0) { + int level = get_crm_log_level(); + set_crm_log_level(level-1); + crm_info("Debug set to %d (was %d)", + get_crm_log_level(), level); +#endif + /*========== (NOT_DC)-Only Actions ==========*/ + } else if(AM_I_DC == FALSE){ + + gboolean dc_match = safe_str_eq(host_from, fsa_our_dc); + + if(dc_match || fsa_our_dc == NULL) { + if(strcmp(op, CRM_OP_HBEAT) == 0) { + next_input = I_DC_HEARTBEAT; + } else if(strcmp(op, CRM_OP_WELCOME) == 0) { + next_input = I_JOIN_OFFER; - } else if(AM_I_DC && strcmp(op, CRM_OP_TEABORT) == 0) { + } else if(fsa_our_dc != NULL + && strcmp(op, CRM_OP_REPLACE) == 0) { + next_input = I_CIB_OP; + + } else if(fsa_our_dc != NULL + && strcmp(op, CRM_OP_UPDATE) == 0) { + next_input = I_CIB_OP; + + } else if(fsa_our_dc != NULL + && strcmp(op, CRM_OP_SHUTDOWN) == 0) { + next_input = I_TERMINATE; + + } else { + crm_err("%s didnt expect request: %s", + AM_I_DC?"DC":"CRMd", op); + } + + } else { + crm_warn("Discarding %s op from %s", op, host_from); + } + + /*========== DC-Only Actions ==========*/ + } else if(AM_I_DC){ + if(strcmp(op, CRM_OP_TEABORT) == 0) { if(fsa_state != S_INTEGRATION) { next_input = I_PE_CALC; } else { crm_debug("Ignoring %s in state %s." " Waiting for the integration to" " complete first.", op, fsa_state2string(fsa_state)); } - - } else if(AM_I_DC - && strcmp(op, CRM_OP_TECOMPLETE) == 0) { + } else if(strcmp(op, CRM_OP_TECOMPLETE) == 0) { if(fsa_state == S_TRANSITION_ENGINE) { next_input = I_SUCCESS; -/* silently ignore? probably means the TE is signaling OK too early } else { - crm_warn( - "Op %s is only valid in state %s (%s)", - op, - fsa_state2string(S_TRANSITION_ENGINE), - fsa_state2string(fsa_state)); -*/ - } - - } else if(strcmp(op, CRM_OP_WELCOME) == 0) { - next_input = I_WELCOME; - - } else if(strcmp(op, "init_shutdown") == 0) { - - crm_warn("This method of shutting down is somewhat untested"); - crm_shutdown(SIGTERM); - /*next_input = I_SHUTDOWN; */ - next_input = I_NULL; - - } else if(strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { - - /* create cib fragment and add to message */ - - /* handle here to avoid potential version issues - * where the shutdown message/proceedure may have - * been changed in later versions. - * - * This way the DC is always in control of the shutdown - */ - - xmlNodePtr frag = NULL; - time_t now = time(NULL); - char *now_s = crm_itoa((int)now); - xmlNodePtr node_state = - create_xml_node(NULL, XML_CIB_TAG_STATE); + crm_warn("Op %s is only valid in state %s..." + "We are in (%s)", + op, + fsa_state2string(S_TRANSITION_ENGINE), + fsa_state2string(fsa_state)); + } - crm_info("Creating shutdown request for %s",host_from); - - set_uuid(node_state, XML_ATTR_UUID, host_from); - set_xml_property_copy( - node_state, XML_ATTR_UNAME, host_from); - set_xml_property_copy( - node_state, XML_CIB_ATTR_SHUTDOWN, now_s); - set_xml_property_copy( - node_state, - XML_CIB_ATTR_EXPSTATE, - CRMD_STATE_INACTIVE); - - frag = create_cib_fragment(node_state, NULL); - xmlAddChild(stored_msg, frag); - - free_xml(node_state); - crm_free(now_s); - + } else if(strcmp(op, CRM_OP_CREATE) == 0 + || strcmp(op, CRM_OP_UPDATE) == 0 + || strcmp(op, CRM_OP_ERASE) == 0 + || strcmp(op, CRM_OP_REPLACE) == 0 + || strcmp(op, CRM_OP_DELETE) == 0) { next_input = I_CIB_OP; - } else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) { - next_input = I_TERMINATE; - - } else if(strcmp(op, "debug_inc") == 0) { - int level = get_crm_log_level(); - set_crm_log_level(level+1); - crm_info("Debug set to %d (was %d)", - get_crm_log_level(), level); - - } else if(strcmp(op, "debug_dec") == 0) { - int level = get_crm_log_level(); - set_crm_log_level(level-1); - crm_info("Debug set to %d (was %d)", - get_crm_log_level(), level); - } else if(strcmp(op, CRM_OP_ANNOUNCE) == 0) { next_input = I_NODE_JOIN; - } else if(strcmp(op, CRM_OP_REPLACE) == 0 - || strcmp(op, CRM_OP_QUERY) == 0 - || strcmp(op, CRM_OP_ERASE) == 0) { - next_input = I_CIB_OP; - fprintf(router_strm, "Message result: CIB Op\n"); + } else if(strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { + /* a slave wants to shut down */ + /* create cib fragment and add to message */ + next_input = handle_shutdown_request(stored_msg); + + } else { + crm_err("Unexpected request (op=%s) sent to the %s", + op, AM_I_DC?"DC":"CRMd"); + } + } + return next_input; +} - } else if(AM_I_DC - && (strcmp(op, CRM_OP_CREATE) == 0 - || strcmp(op, CRM_OP_UPDATE) == 0 - || strcmp(op, CRM_OP_DELETE) == 0)) { - /* updates should only be performed on the DC */ - next_input = I_CIB_OP; - - } else if(strcmp(op, CRM_OP_PING) == 0) { - /* eventually do some stuff to figure out - * if we /are/ ok - */ - xmlNodePtr ping = - createPingAnswerFragment(sys_to, "ok"); +enum crmd_fsa_input +handle_response(xmlNodePtr stored_msg) +{ + enum crmd_fsa_input next_input = I_NULL; - set_xml_property_copy(ping, "crmd_state", - fsa_state2string(fsa_state)); + const char *sys_from = get_xml_attr( + stored_msg, NULL, XML_ATTR_SYSFROM, TRUE); - wrapper = create_reply(stored_msg, ping); + const char *msg_ref = get_xml_attr( + stored_msg, NULL, XML_ATTR_REFERENCE, TRUE); - relay_message(wrapper, TRUE); - free_xml(wrapper); - - } else { - crm_err("Unexpected request (op=%s) sent to the %s", - op, AM_I_DC?"DC":"CRMd"); - } - - } else if(strcmp(type, XML_ATTR_RESPONSE) == 0) { + 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); - if(strcmp(op, CRM_OP_WELCOME) == 0) { - next_input = I_WELCOME_ACK; - - } else if(AM_I_DC - && strcmp(op, CRM_OP_PECALC) == 0) { + crm_verbose("Received %s %s in state %s", + op, type, fsa_state2string(fsa_state)); + + if(op == NULL) { + crm_xml_err(stored_msg, "Bad message"); - if(fsa_state == S_POLICY_ENGINE - && safe_str_eq(msg_ref, fsa_pe_ref)) { - next_input = I_SUCCESS; - } else if(fsa_state != S_POLICY_ENGINE) { - crm_err("Reply to %s is only valid in state %s", - op, fsa_state2string(S_POLICY_ENGINE)); + } else if(strcmp(op, CRM_OP_WELCOME) == 0) { + next_input = I_JOIN_REQUEST; - } else { - crm_verbose("Skipping superceeded reply from %s", - sys_from); - } - - } else if(strcmp(op, CRM_OP_VOTE) == 0 - || strcmp(op, CRM_OP_HBEAT) == 0 - || strcmp(op, CRM_OP_WELCOME) == 0 - || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 - || strcmp(op, CRM_OP_SHUTDOWN) == 0 - || strcmp(op, CRM_OP_ANNOUNCE) == 0) { - next_input = I_NULL; - - } else if(strcmp(op, CRM_OP_CREATE) == 0 - || strcmp(op, CRM_OP_UPDATE) == 0 - || strcmp(op, CRM_OP_DELETE) == 0 - || strcmp(op, CRM_OP_REPLACE) == 0 - || strcmp(op, CRM_OP_ERASE) == 0) { + } else if(strcmp(op, CRM_OP_JOINACK) == 0) { + next_input = I_JOIN_RESULT; + + } else if(AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) { + + if(fsa_state == S_POLICY_ENGINE + && safe_str_eq(msg_ref, fsa_pe_ref)) { + next_input = I_SUCCESS; + } else if(fsa_state != S_POLICY_ENGINE) { + crm_err("Reply to %s is only valid in state %s", + op, fsa_state2string(S_POLICY_ENGINE)); - /* perhaps we should do somethign with these replies, - * especially check that the actions passed - */ -/* fprintf(router_strm, "Message result: CIB Reply\n"); */ - } else { - crm_err("Unexpected response (op=%s) sent to the %s", - op, AM_I_DC?"DC":"CRMd"); - next_input = I_NULL; + crm_verbose("Skipping superceeded reply from %s", + sys_from); } + + } else if(strcmp(op, CRM_OP_VOTE) == 0 + || strcmp(op, CRM_OP_HBEAT) == 0 + || strcmp(op, CRM_OP_WELCOME) == 0 + || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 + || strcmp(op, CRM_OP_SHUTDOWN) == 0 + || strcmp(op, CRM_OP_ANNOUNCE) == 0) { + next_input = I_NULL; + + } else if(strcmp(op, CRM_OP_CREATE) == 0 + || strcmp(op, CRM_OP_UPDATE) == 0 + || strcmp(op, CRM_OP_DELETE) == 0 + || strcmp(op, CRM_OP_REPLACE) == 0 + || strcmp(op, CRM_OP_ERASE) == 0) { + + /* perhaps we should do somethign with these replies, + * especially check that the actions passed + */ +/* fprintf(router_strm, "Message result: CIB Reply\n"); */ + } else { - crm_err("Unexpected message type %s", type); - + crm_err("Unexpected response (op=%s) sent to the %s", + op, AM_I_DC?"DC":"CRMd"); + next_input = I_NULL; } - -/* crm_verbose("%s: Next input is %s", __FUNCTION__, */ -/* fsa_input2string(next_input)); */ - return next_input; } +enum crmd_fsa_input +handle_shutdown_request(xmlNodePtr stored_msg) +{ + /* handle here to avoid potential version issues + * where the shutdown message/proceedure may have + * been changed in later versions. + * + * This way the DC is always in control of the shutdown + */ + + xmlNodePtr frag = NULL; + time_t now = time(NULL); + char *now_s = crm_itoa((int)now); + xmlNodePtr node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); + const char *host_from= get_xml_attr( + stored_msg, NULL, XML_ATTR_HOSTFROM, FALSE); + + crm_info("Creating shutdown request for %s",host_from); + + set_uuid(node_state, XML_ATTR_UUID, host_from); + set_xml_property_copy(node_state, XML_ATTR_UNAME, host_from); + set_xml_property_copy(node_state, XML_CIB_ATTR_SHUTDOWN, now_s); + set_xml_property_copy( + node_state, XML_CIB_ATTR_EXPSTATE, CRMD_STATE_INACTIVE); + + frag = create_cib_fragment(node_state, NULL); + + /* attach it to the original request + * and make sure its sent to the CIB + */ + xmlAddChild(stored_msg, frag); + + /* cleanup intermediate steps */ + free_xml(node_state); + crm_free(now_s); + + return I_CIB_OP; +} + gboolean send_xmlha_message(ll_cluster_t *hb_fd, xmlNodePtr root) { int xml_len = -1; int send_result = -1; char *xml_text = NULL; const char *host_to = NULL; const char *sys_to = NULL; struct ha_msg *msg = NULL; gboolean all_is_good = TRUE; gboolean broadcast = FALSE; int log_level = LOG_DEBUG; xmlNodePtr opts = find_xml_node(root, XML_TAG_OPTIONS); const char *op = xmlGetProp(opts, XML_ATTR_OP); #ifdef MSG_LOG char *msg_text = NULL; #endif if (root == NULL) { crm_err("Attempt to send NULL Message via HA failed."); all_is_good = FALSE; } host_to = xmlGetProp(root, XML_ATTR_HOSTTO); sys_to = xmlGetProp(root, XML_ATTR_SYSTO); if (all_is_good) { msg = ha_msg_new(4); ha_msg_add(msg, F_TYPE, "CRM"); ha_msg_add(msg, F_COMMENT, "A CRM xml message"); xml_text = dump_xml_unformatted(root); xml_len = strlen(xml_text); if (xml_text == NULL || xml_len <= 0) { crm_err( "Failed sending an invalid XML Message via HA"); all_is_good = FALSE; crm_xml_devel(root, "Bad message was"); } else { if(ha_msg_add(msg, "xml", xml_text) == HA_FAIL) { crm_err("Could not add xml to HA message"); all_is_good = FALSE; } } } if (all_is_good) { if (sys_to == NULL || strlen(sys_to) == 0) { crm_err("You did not specify a destination sub-system" " for this message."); all_is_good = FALSE; } } /* There are a number of messages may not need to be ordered. * At a later point perhaps we should detect them and send them * as unordered messages. */ if (all_is_good) { if (host_to == NULL || strlen(host_to) == 0) { broadcast = TRUE; send_result=hb_fd->llc_ops->sendclustermsg(hb_fd, msg); } else { send_result = hb_fd->llc_ops->send_ordered_nodemsg( hb_fd, msg, host_to); } if(send_result != HA_OK) all_is_good = FALSE; } if(all_is_good == FALSE) { log_level = LOG_ERR; } if(log_level == LOG_ERR || (safe_str_neq(op, CRM_OP_HBEAT))) { do_crm_log(log_level, __FUNCTION__, "Sending %sHA message (ref=%s,len=%d) to %s@%s %s.", broadcast?"broadcast ":"directed ", xmlGetProp(root, XML_ATTR_REFERENCE), xml_len, sys_to, host_to==NULL?"":host_to, all_is_good?"succeeded":"failed"); } #ifdef MSG_LOG msg_text = dump_xml_formatted(root); if(msg_out_strm == NULL) { msg_out_strm = fopen(DEVEL_DIR"/outbound.log", "w"); } fprintf(msg_out_strm, "[%s HA (%s:%d)]\t%s\n", all_is_good?"succeeded":"failed", xmlGetProp(root, XML_ATTR_REFERENCE), send_result, msg_text); fflush(msg_out_strm); crm_free(msg_text); if(msg != NULL) { ha_msg_del(msg); } #endif return all_is_good; } /* required? or just send to self an let relay_message do its thing? */ /* * This method adds a copy of xml_response_data */ gboolean send_ha_reply(ll_cluster_t *hb_cluster, xmlNodePtr xml_request, xmlNodePtr xml_response_data) { gboolean was_sent = FALSE; xmlNodePtr reply; was_sent = FALSE; reply = create_reply(xml_request, xml_response_data); if (reply != NULL) { was_sent = send_xmlha_message(hb_cluster, reply); free_xml(reply); } return was_sent; } void send_msg_via_ha(xmlNodePtr action, const char *dest_node) { if (action == NULL) return; if (validate_crm_message(action, NULL, NULL, NULL) == NULL) { crm_err("Relay message to (%s) via HA was invalid, ignoring", dest_node); return; } /* crm_verbose("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); return; } void send_msg_via_ipc(xmlNodePtr action, const char *sys) { IPC_Channel *client_channel; enum crmd_fsa_input next_input; crm_trace("relaying msg to sub_sys=%s via IPC", sys); client_channel = (IPC_Channel*)g_hash_table_lookup (ipc_clients, sys); if(xmlGetProp(action, XML_ATTR_HOSTFROM) == NULL) { set_xml_property_copy( action, XML_ATTR_HOSTFROM, fsa_our_uname); } if (client_channel != NULL) { crm_debug("Sending message via channel %s.", sys); send_xmlipc_message(client_channel, action); } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_CIB) == 0) { crm_err("Sub-system (%s) has been incorporated into the CRMd.", sys); crm_xml_devel(action, "Change the way we handle"); relay_message(process_cib_message(action, TRUE), TRUE); } else if(sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) { #ifdef FSA_TRACE crm_verbose("Invoking action %s (%.16llx)", fsa_action2string(A_LRM_INVOKE), A_LRM_INVOKE); #endif next_input = do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, action); /* todo: feed this back in for anything != I_NULL */ #ifdef FSA_TRACE crm_verbose("Result of action %s was %s", fsa_action2string(A_LRM_INVOKE), fsa_input2string(next_input)); #endif } else { crm_err("Unknown Sub-system (%s)... discarding message.", sys); } return; } diff --git a/crm/crmd/subsystems.c b/crm/crmd/subsystems.c index c62645cd73..a87e5192a2 100644 --- a/crm/crmd/subsystems.c +++ b/crm/crmd/subsystems.c @@ -1,641 +1,641 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include /* for access */ #include #include #include /* for calls to open */ #include /* for calls to open */ #include /* for calls to open */ #include /* for getpwuid */ #include /* for initgroups */ #include /* for getrlimit */ #include /* for getrlimit */ #include #include #include #include #include #include #include #include -#define CLIENT_EXIT_WAIT 10 +#define CLIENT_EXIT_WAIT 30 static gboolean stop_subsystem (struct crm_subsystem_s *centry); static gboolean start_subsystem(struct crm_subsystem_s *centry); struct crm_subsystem_s *cib_subsystem = NULL; struct crm_subsystem_s *te_subsystem = NULL; struct crm_subsystem_s *pe_subsystem = NULL; /* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */ enum crmd_fsa_input do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = cib_subsystem; long long stop_actions = A_CIB_STOP; long long start_actions = A_CIB_START; if(action & stop_actions) { /* dont do anything, its embedded now */ } if(action & start_actions) { if(cur_state != S_STOPPING) { if(startCib(CIB_FILENAME) == FALSE) result = I_FAIL; } else { crm_info("Ignoring request to start %s after shutdown", this_subsys->command); } } return result; } /* A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS */ enum crmd_fsa_input do_cib_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr cib_msg = NULL; xmlNodePtr answer = NULL; xmlNodePtr new_options = NULL; const char *section = NULL; enum crmd_fsa_input result = I_NULL; if(data != NULL) { cib_msg = (xmlNodePtr)data; } if(action & A_CIB_INVOKE || action & A_CIB_INVOKE_LOCAL) { /* gboolean is_update = FALSE; */ xmlNodePtr options = find_xml_node(cib_msg, XML_TAG_OPTIONS); const char *sys_from = xmlGetProp(cib_msg, XML_ATTR_SYSFROM); const char *op = xmlGetProp(options, XML_ATTR_OP); crm_xml_devel(cib_msg, "[CIB b4]"); if(cib_msg == NULL) { crm_err("No message for CIB command"); return I_NULL; /* I_ERROR */ } else if(op == NULL) { crm_xml_devel(cib_msg, "Invalid CIB Message"); return I_NULL; /* I_ERROR */ } set_xml_property_copy(cib_msg, XML_ATTR_SYSTO, "cib"); answer = process_cib_message(cib_msg, TRUE); if(action & A_CIB_INVOKE) { if(AM_I_DC == FALSE) { if(relay_message(answer, TRUE) == FALSE) { crm_err("Confused what to do with cib result"); crm_xml_devel(answer, "Couldnt route: "); result = I_ERROR; } } else if(strcmp(op, CRM_OP_CREATE) == 0 || strcmp(op, CRM_OP_UPDATE) == 0 || strcmp(op, CRM_OP_DELETE) == 0 || strcmp(op, CRM_OP_REPLACE) == 0 || strcmp(op, CRM_OP_WELCOME) == 0 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { result = I_CIB_UPDATE; } else if(strcmp(op, CRM_OP_ERASE) == 0) { /* regenerate everyone's state and our node entry */ result = I_ELECTION_DC; } /* the TENGINE will get CC'd by other means. */ if(AM_I_DC && sys_from != NULL && safe_str_neq(sys_from, CRM_SYSTEM_TENGINE) && safe_str_neq(sys_from, CRM_SYSTEM_CRMD) && safe_str_neq(sys_from, CRM_SYSTEM_DC) && relay_message(answer, TRUE) == FALSE) { crm_err("Confused what to do with cib result"); crm_xml_devel(answer, "Couldnt route: "); result = I_ERROR; } /* } else { */ /* put_message(answer); */ /* return I_REQUEST; */ } crm_xml_devel(cib_msg, "[CIB after]"); return result; } else if(action & A_CIB_BUMPGEN) { /* xmlNodePtr options = find_xml_node(cib_msg, XML_TAG_OPTIONS); */ /* const char *op = xmlGetProp(options, XML_ATTR_OP); */ if(AM_I_DC == FALSE) { return I_NULL; } /* check if the response was ok before next bit */ /* if(safe_str_neq(op, CRM_OP_WELCOME)) { */ /* set the section so that we dont always send the * whole thing */ section = get_xml_attr( cib_msg, XML_TAG_OPTIONS, XML_ATTR_FILTER_TYPE, FALSE); /* } */ if(section != NULL) { new_options = set_xml_attr( NULL, XML_TAG_OPTIONS, XML_ATTR_FILTER_TYPE, section, TRUE); } answer = process_cib_request( CRM_OP_BUMP, new_options, NULL); free_xml(new_options); if(answer == NULL) { crm_err("Result of BUMP in %s was NULL", __FUNCTION__); return I_FAIL; } send_request(NULL, answer, CRM_OP_REPLACE, NULL, CRM_SYSTEM_CRMD, NULL); free_xml(answer); } else { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return I_NULL; } /* A_PE_START, A_PE_STOP, A_TE_RESTART */ enum crmd_fsa_input do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = pe_subsystem; long long stop_actions = A_PE_STOP; long long start_actions = A_PE_START; if(action & stop_actions) { if(stop_subsystem(this_subsys) == FALSE) result = I_FAIL; else if(this_subsys->pid > 0){ int lpc = CLIENT_EXIT_WAIT; int pid_status = -1; while(lpc-- > 0 && this_subsys->pid > 0 && CL_PID_EXISTS(this_subsys->pid)) { sleep(1); waitpid(this_subsys->pid, &pid_status, WNOHANG); } if(CL_PID_EXISTS(this_subsys->pid)) { crm_err("Process %s is still active with pid=%d", this_subsys->command, this_subsys->pid); result = I_FAIL; } } cleanup_subsystem(this_subsys); } if(action & start_actions) { if(cur_state != S_STOPPING) { if(start_subsystem(this_subsys) == FALSE) { result = I_FAIL; cleanup_subsystem(this_subsys); } } else { crm_info("Ignoring request to start %s while shutting down", this_subsys->command); } } return result; } char *fsa_pe_ref = NULL; /* A_PE_INVOKE */ enum crmd_fsa_input do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr local_cib = NULL; stopTimer(integration_timer); if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){ crm_info("Waiting for the PE to connect"); return I_WAIT_FOR_EVENT; } local_cib = get_cib_copy(); crm_verbose("Invoking %s with %p", CRM_SYSTEM_PENGINE, local_cib); if(fsa_pe_ref) { crm_free(fsa_pe_ref); fsa_pe_ref = NULL; } send_request(NULL, local_cib, CRM_OP_PECALC, NULL, CRM_SYSTEM_PENGINE, &fsa_pe_ref); return I_NULL; } /* A_TE_START, A_TE_STOP, A_TE_RESTART */ enum crmd_fsa_input do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { enum crmd_fsa_input result = I_NULL; struct crm_subsystem_s *this_subsys = te_subsystem; long long stop_actions = A_TE_STOP; long long start_actions = A_TE_START; int lpc, pid_status; /* if(action & stop_actions && cur_state != S_STOPPING */ /* && is_set(fsa_input_register, R_TE_PEND)) { */ /* result = I_WAIT_FOR_EVENT; */ /* return result; */ /* } */ if(action & stop_actions) { if(stop_subsystem(this_subsys) == FALSE) result = I_FAIL; else if(this_subsys->pid > 0){ lpc = CLIENT_EXIT_WAIT; pid_status = -1; while(lpc-- > 0 && this_subsys->pid > 0 && CL_PID_EXISTS(this_subsys->pid)) { sleep(1); waitpid(this_subsys->pid, &pid_status, WNOHANG); } if(CL_PID_EXISTS(this_subsys->pid)) { crm_err("Process %s is still active with pid=%d", this_subsys->command, this_subsys->pid); result = I_FAIL; } } cleanup_subsystem(this_subsys); } if(action & start_actions) { if(cur_state != S_STOPPING) { if(start_subsystem(this_subsys) == FALSE) { result = I_FAIL; cleanup_subsystem(this_subsys); } } else { crm_info("Ignoring request to start %s while shutting down", this_subsys->command); } } return result; } static xmlNodePtr te_last_input = NULL; static xmlNodePtr te_lastcc = NULL; /* A_TE_COPYTO */ enum crmd_fsa_input do_te_copyto(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr message = NULL; xmlNodePtr opts = NULL; const char *true_op = NULL; if(data != NULL) { crm_xml_devel(data, "[TE imput]"); message = copy_xml_node_recursive((xmlNodePtr)data); opts = find_xml_node(message, XML_TAG_OPTIONS); true_op = xmlGetProp(opts, XML_ATTR_OP); set_xml_property_copy(opts, XML_ATTR_OP, CRM_OP_EVENTCC); set_xml_property_copy(opts, XML_ATTR_TRUEOP, true_op); set_xml_property_copy( message, XML_ATTR_SYSTO, CRM_SYSTEM_TENGINE); } if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){ crm_info("Waiting for the TE to connect"); if(data != NULL) { free_xml(te_lastcc); te_lastcc = message; } return I_WAIT_FOR_EVENT; } if(message == NULL) { message = te_lastcc; te_lastcc = NULL; } else { free_xml(te_lastcc); } relay_message(message, FALSE); /* only free it if it was a local copy */ if(data == NULL) { free_xml(message); } return I_NULL; } /* A_TE_INVOKE, A_TE_CANCEL */ enum crmd_fsa_input do_te_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, void *data) { xmlNodePtr graph = NULL; xmlNodePtr msg = (xmlNodePtr)data; if(is_set(fsa_input_register, R_TE_CONNECTED) == FALSE){ crm_info("Waiting for the TE to connect"); if(data != NULL) { free_xml(te_last_input); te_last_input = copy_xml_node_recursive(msg); } return I_WAIT_FOR_EVENT; } if(msg == NULL) { msg = te_last_input; te_last_input = NULL; } else { free_xml(te_last_input); } if(action & A_TE_INVOKE) { graph = find_xml_node(msg, "transition_graph"); if(graph == NULL) { return I_FAIL; } send_request(NULL, graph, CRM_OP_TRANSITION, NULL, CRM_SYSTEM_TENGINE, NULL); } else { send_request(NULL, graph, CRM_OP_ABORT, NULL, CRM_SYSTEM_TENGINE, NULL); } /* only free it if it was a local copy */ if(data == NULL) { free_xml(msg); } return I_NULL; } gboolean crmd_client_connect(IPC_Channel *client_channel, gpointer user_data) { if (client_channel == NULL) { crm_err("Channel was NULL"); } else if (client_channel->ch_status == IPC_DISCONNECT) { crm_err("Channel was disconnected"); } else { crmd_client_t *blank_client = NULL; crm_malloc(blank_client, sizeof(crmd_client_t)); if (blank_client == NULL) { return FALSE; } client_channel->ops->set_recv_qlen(client_channel, 100); client_channel->ops->set_send_qlen(client_channel, 100); blank_client->client_channel = client_channel; blank_client->sub_sys = NULL; blank_client->uuid = NULL; blank_client->table_key = NULL; blank_client->client_source = G_main_add_IPC_Channel(G_PRIORITY_LOW, client_channel, FALSE, crmd_ipc_input_callback, blank_client, default_ipc_input_destroy); } return TRUE; } static gboolean stop_subsystem(struct crm_subsystem_s* centry) { crm_info("Stopping sub-system \"%s\"", centry->name); if (centry->pid <= 0) { crm_err("OOPS! client %s not running yet", centry->command); } else { crm_info("Sending quit message to %s.", centry->name); send_request(NULL, NULL, CRM_OP_QUIT, NULL, centry->name, NULL); } return TRUE; } static gboolean start_subsystem(struct crm_subsystem_s* centry) { pid_t pid; struct stat buf; int s_res; crm_info("Starting sub-system \"%s\"", centry->command); if (centry->pid > 0) { crm_err("OOPS! client %s already running as pid %d" , centry->command, (int) centry->pid); } /* * We need to ensure that the exec will succeed before * we bother forking. We don't want to respawn something that * won't exec in the first place. */ if (access(centry->path, F_OK|X_OK) != 0) { cl_perror("Cannot (access) exec %s", centry->path); return FALSE; } s_res = stat(centry->command, &buf); if(s_res != 0) { cl_perror("Cannot (stat) exec %s", centry->command); return FALSE; } /* We need to fork so we can make child procs not real time */ switch(pid=fork()) { case -1: crm_err("start_a_child_client: Cannot fork."); return FALSE; default: /* Parent */ centry->pid = pid; return TRUE; case 0: /* Child */ break; } /* Child process: start the managed child */ cl_make_normaltime(); setpgid(0,0); /* Limit peak resource usage, maximize success chances */ if (centry->shortrcount > 0) { alarm(0); sleep(1); } crm_info("Executing \"%s\" (pid %d)", centry->command, (int) getpid()); if(CL_SIGINTERRUPT(SIGALRM, 0) < 0) { cl_perror("Cannot set interrupt for child process %s", centry->command); }else{ const char * devnull = "/dev/null"; unsigned int j; struct rlimit oflimits; CL_SIGNAL(SIGCHLD, SIG_DFL); alarm(0); CL_IGNORE_SIG(SIGALRM); /* A precautionary measure */ getrlimit(RLIMIT_NOFILE, &oflimits); for (j=0; j < oflimits.rlim_cur; ++j) { close(j); } (void)devnull; (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */ (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */ (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */ (void)execl("/bin/sh", "sh", "-c", centry->command, (const char *)NULL); /* Should not happen */ cl_perror("Cannot exec %s", centry->command); } /* Suppress respawning */ exit(100); /* never reached */ return TRUE; } diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c index 8f223e4905..0128ab3f56 100644 --- a/crm/crmd/utils.c +++ b/crm/crmd/utils.c @@ -1,719 +1,731 @@ /* * 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 gboolean timer_popped(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; crm_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 startTimer(fsa_timer_t *timer) { if(((int)timer->source_id) < 0 && timer->period_ms > 0) { timer->source_id = Gmain_timeout_add(timer->period_ms, timer->callback, (void*)timer); /* crm_verbose("#!!#!!# Started %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); */ } else if(timer->period_ms < 0) { crm_err("Tried to start timer %s with -ve period", fsa_input2string(timer->fsa_input)); } else { crm_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_verbose("#!!#!!# Stopping %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); */ g_source_remove(timer->source_id); timer->source_id = -2; } else { crm_info("#!!#!!# Timer %s already stopped (%d)", fsa_input2string(timer->fsa_input), timer->source_id); return FALSE; } return TRUE; } long long toggle_bit(long long action_list, long long action) { crm_trace("Toggling bit %.16llx", action); action_list ^= action; crm_trace("Result %.16llx", action_list & action); return action_list; } long long clear_bit(long long action_list, long long action) { crm_trace("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_trace("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_verbose("Checking bit\t%.16llx", action); */ return ((action_list & action) == action); } const char * fsa_input2string(enum crmd_fsa_input 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_PE_CALC: inputAsText = "I_PE_CALC"; 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"; + case I_JOIN_OFFER: + inputAsText = "I_JOIN_OFFER"; + break; + case I_JOIN_REQUEST: + inputAsText = "I_JOIN_REQUEST"; + break; + case I_JOIN_RESULT: + inputAsText = "I_JOIN_RESULT"; 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_STARTUP: inputAsText = "I_STARTUP"; break; case I_SUCCESS: inputAsText = "I_SUCCESS"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; break; - case I_WELCOME: - inputAsText = "I_WELCOME"; - break; - case I_WELCOME_ACK: - inputAsText = "I_WELCOME_ACK"; - break; case I_DC_HEARTBEAT: inputAsText = "I_DC_HEARTBEAT"; break; case I_WAIT_FOR_EVENT: inputAsText = "I_WAIT_FOR_EVENT"; break; case I_LRM_EVENT: inputAsText = "I_LRM_EVENT"; break; + case I_VOTE: + inputAsText = "I_VOTE"; + break; case I_ILLEGAL: inputAsText = "I_ILLEGAL"; break; } if(inputAsText == NULL) { crm_err("Input %d is unknown", input); inputAsText = ""; } return inputAsText; } const char * fsa_state2string(enum crmd_fsa_state 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_FINALIZE_JOIN: + stateAsText = "S_FINALIZE_JOIN"; + 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) { crm_err("State %d is unknown", state); stateAsText = ""; } return stateAsText; } const char * fsa_cause2string(enum crmd_fsa_cause cause) { const char *causeAsText = NULL; switch(cause){ case C_UNKNOWN: causeAsText = "C_UNKNOWN"; break; case C_STARTUP: causeAsText = "C_STARTUP"; break; case C_IPC_MESSAGE: causeAsText = "C_IPC_MESSAGE"; break; case C_HA_MESSAGE: causeAsText = "C_HA_MESSAGE"; break; case C_CCM_CALLBACK: causeAsText = "C_CCM_CALLBACK"; break; case C_TIMER_POPPED: causeAsText = "C_TIMER_POPPED"; break; case C_SHUTDOWN: causeAsText = "C_SHUTDOWN"; break; case C_HEARTBEAT_FAILED: causeAsText = "C_HEARTBEAT_FAILED"; break; case C_SUBSYSTEM_CONNECT: causeAsText = "C_SUBSYSTEM_CONNECT"; break; case C_LRM_OP_CALLBACK: causeAsText = "C_LRM_OP_CALLBACK"; break; case C_LRM_MONITOR_CALLBACK: causeAsText = "C_LRM_MONITOR_CALLBACK"; break; case C_CRMD_STATUS_CALLBACK: causeAsText = "C_CRMD_STATUS_CALLBACK"; break; case C_HA_DISCONNECT: causeAsText = "C_HA_DISCONNECT"; break; case C_ILLEGAL: causeAsText = "C_ILLEGAL"; break; } if(causeAsText == NULL) { crm_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 A_READCONFIG: actionAsText = "A_READCONFIG"; 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_EVENT: actionAsText = "A_LRM_EVENT"; break; case A_LRM_INVOKE: actionAsText = "A_LRM_INVOKE"; 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"; + case A_CL_JOIN_ANNOUNCE: + actionAsText = "A_CL_JOIN_ANNOUNCE"; + break; + case A_CL_JOIN_REQUEST: + actionAsText = "A_CL_JOIN_REQUEST"; + break; + case A_CL_JOIN_RESULT: + actionAsText = "A_CL_JOIN_RESULT"; + break; + case A_DC_JOIN_OFFER_ALL: + actionAsText = "A_DC_JOIN_OFFER_ALL"; break; - case A_JOIN_ACK: - actionAsText = "A_JOIN_ACK"; + case A_DC_JOIN_OFFER_ONE: + actionAsText = "A_DC_JOIN_OFFER_ONE"; break; - case A_JOIN_WELCOME: - actionAsText = "A_JOIN_WELCOME"; + case A_DC_JOIN_PROCESS_REQ: + actionAsText = "A_DC_JOIN_PROCESS_REQ"; break; - case A_JOIN_WELCOME_ALL: - actionAsText = "A_JOIN_WELCOME_ALL"; + case A_DC_JOIN_PROCESS_ACK: + actionAsText = "A_DC_JOIN_PROCESS_ACK"; break; - case A_JOIN_PROCESS_ACK: - actionAsText = "A_JOIN_PROCESS_ACK"; + case A_DC_JOIN_FINALIZE: + actionAsText = "A_DC_JOIN_FINALIZE"; 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_TE_CANCEL: actionAsText = "A_TE_CANCEL"; break; case A_TE_COPYTO: actionAsText = "A_TE_COPYTO"; 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) { crm_err("Action %.16llx is unknown", action); actionAsText = ""; } return actionAsText; } 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; } enum crmd_fsa_input invoke_local_cib(xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation) { enum crmd_fsa_input result = I_NULL; xmlNodePtr request = NULL; msg_options = set_xml_attr(msg_options, XML_TAG_OPTIONS, XML_ATTR_OP, operation, TRUE); request = create_request(msg_options, msg_data, NULL, CRM_SYSTEM_CIB, AM_I_DC?CRM_SYSTEM_DC:CRM_SYSTEM_CRMD, NULL, NULL); result = do_cib_invoke(A_CIB_INVOKE_LOCAL, C_UNKNOWN, fsa_state, I_CIB_OP, request); free_xml(request); return result; } void create_node_entry(const char *uuid, const char *uname, const char *type) { /* make sure a node entry exists for the new node * * this will add anyone except the first ever node in the cluster * since it will also be the DC which doesnt go through the * join process (with itself). We can include a special case * later if desired. */ xmlNodePtr tmp2 = NULL; xmlNodePtr tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE); crm_debug("Creating node entry for %s", uname); set_uuid(tmp1, XML_ATTR_UUID, uname); set_xml_property_copy(tmp1, XML_ATTR_UNAME, uname); set_xml_property_copy(tmp1, XML_ATTR_TYPE, type); tmp2 = create_cib_fragment(tmp1, NULL); /* do not forward this to the TE */ invoke_local_cib(NULL, tmp2, CRM_OP_UPDATE); free_xml(tmp2); free_xml(tmp1); } xmlNodePtr create_node_state(const char *uuid, const char *uname, const char *ccm_state, const char *crmd_state, const char *join_state) { xmlNodePtr node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_debug("Creating node state entry for %s", uname); set_uuid(node_state, XML_ATTR_UUID, uname); set_xml_property_copy(node_state, XML_ATTR_UNAME, uname); if(ccm_state != NULL) { set_xml_property_copy( node_state, XML_CIB_ATTR_INCCM, ccm_state); } if(crmd_state != NULL) { set_xml_property_copy( node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state); } if(join_state != NULL) { set_xml_property_copy( node_state, XML_CIB_ATTR_JOINSTATE, join_state); } crm_xml_devel(node_state, "created"); return node_state; } void set_uuid(xmlNodePtr node, const char *attr, const char *uname) { uuid_t uuid_raw; char *uuid_calc = NULL; crm_malloc(uuid_calc, sizeof(char)*50); if(uuid_calc != NULL) { if(fsa_cluster_conn->llc_ops->get_uuid_by_name( fsa_cluster_conn, uname, uuid_raw) == HA_FAIL) { crm_err("Could not calculate UUID for %s", uname); crm_free(uuid_calc); uuid_calc = crm_strdup(uname); } else { uuid_unparse(uuid_raw, uuid_calc); } set_xml_property_copy(node, attr, uuid_calc); } crm_free(uuid_calc); }