diff --git a/crm/crmd/Makefile.am b/crm/crmd/Makefile.am index 00735ece6b..9a271067c0 100644 --- a/crm/crmd/Makefile.am +++ b/crm/crmd/Makefile.am @@ -1,96 +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/crm/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 join_client.c join_dc.c subsystems.c \ cib.c pengine.c tengine.c lrm.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/callbacks.c b/crm/crmd/callbacks.c index 803907bd1b..e7f7bda373 100644 --- a/crm/crmd/callbacks.c +++ b/crm/crmd/callbacks.c @@ -1,539 +1,518 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FILE *msg_in_strm = NULL; FILE *msg_ipc_strm = NULL; xmlNodePtr find_xml_in_hamessage(const struct ha_msg* msg); void crmd_ha_connection_destroy(gpointer user_data); void crmd_ha_msg_callback(const struct ha_msg* msg, void* private_data) { const char *to = NULL; char *xml_text = NULL; xmlNodePtr root_xml_node = NULL; const char *from = ha_msg_value(msg, F_ORIG); const char *seq = ha_msg_value(msg, F_SEQ); const char *type = ha_msg_value(msg, F_TYPE); #ifdef MSG_LOG if(msg_in_strm == NULL) { msg_in_strm = fopen(DEVEL_DIR"/inbound.log", "w"); } #endif if(from == NULL) { crm_err("Value of %s was NULL", F_ORIG); } else if(safe_str_eq(from, fsa_our_uname)) { if(safe_str_eq(type, T_CRM)) { #ifdef MSG_LOG fprintf(msg_in_strm, "Discarded %s message [F_SEQ=%s] from ourselves.\n", T_CRM, seq); fflush(msg_in_strm); #endif return; } } root_xml_node = find_xml_in_hamessage(msg); to = xmlGetProp(root_xml_node, XML_ATTR_HOSTTO); #ifdef MSG_LOG xml_text = dump_xml_formatted(root_xml_node); fprintf(msg_in_strm, "[%s (%s:%s)]\t%s\n", crm_str(from), seq, ha_msg_value(msg, F_TYPE), xml_text ); fflush(msg_in_strm); crm_free(xml_text); #endif if(to != NULL && strlen(to) > 0 && strcmp(to, fsa_our_uname) != 0) { #ifdef MSG_LOG fprintf(msg_in_strm, "Discarding message [F_SEQ=%s] for someone else", seq); #endif return; } set_xml_property_copy(root_xml_node, XML_ATTR_HOSTFROM, from); set_xml_property_copy(root_xml_node, "F_SEQ", seq); register_fsa_input(C_HA_MESSAGE, I_ROUTER, root_xml_node); s_crmd_fsa(C_HA_MESSAGE); free_xml(root_xml_node); return; } /* * Apparently returning TRUE means "stay connected, keep doing stuff". * Returning FALSE means "we're all done, close the connection" */ gboolean crmd_ipc_msg_callback(IPC_Channel *client, gpointer user_data) { int lpc = 0; char *buffer = NULL; IPC_Message *msg = NULL; gboolean hack_return_good = TRUE; xmlNodePtr root_xml_node; crmd_client_t *curr_client = (crmd_client_t*)user_data; crm_verbose("Processing IPC message from %s", curr_client->table_key); #ifdef MSG_LOG if(msg_ipc_strm == NULL) { msg_ipc_strm = fopen(DEVEL_DIR"/inbound.ipc.log", "w"); } #endif while(client->ops->is_message_pending(client)) { if (client->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if (client->ops->recv(client, &msg) != IPC_OK) { perror("Receive failure:"); #ifdef MSG_LOG fprintf(msg_ipc_strm, "[%s] [receive failure]\n", curr_client->table_key); fflush(msg_in_strm); #endif return !hack_return_good; } if (msg == NULL) { #ifdef MSG_LOG fprintf(msg_ipc_strm, "[%s] [__nothing__]\n", curr_client->table_key); fflush(msg_in_strm); #endif crm_err("No message this time"); continue; } lpc++; buffer = (char*)msg->msg_body; crm_verbose("Processing xml from %s [text=%s]\n", curr_client->table_key, buffer); #ifdef MSG_LOG fprintf(msg_ipc_strm, "[%s] [text=%s]\n", curr_client->table_key, buffer); fflush(msg_in_strm); #endif root_xml_node = find_xml_in_ipcmessage(msg, FALSE); if (root_xml_node != NULL) { crmd_authorize_message( root_xml_node, msg, curr_client); } else { crm_info("IPC Message was not valid... discarding."); } free_xml(root_xml_node); msg->msg_done(msg); msg = NULL; buffer = NULL; root_xml_node = NULL; } crm_verbose("Processed %d messages", lpc); if (client->ch_status == IPC_DISCONNECT) { crm_info("received HUP from %s", curr_client->table_key); if (curr_client != NULL) { struct crm_subsystem_s *the_subsystem = NULL; if (curr_client->sub_sys == NULL) { crm_warn("Client hadn't registered with us yet"); } else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) { the_subsystem = pe_subsystem; } else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) { the_subsystem = te_subsystem; } else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){ the_subsystem = cib_subsystem; } if(the_subsystem != NULL) { cleanup_subsystem(the_subsystem); } /* else that was a transient client */ if (curr_client->table_key != NULL) { /* * Key is destroyed below: * curr_client->table_key * Value is cleaned up by: * G_main_del_IPC_Channel */ g_hash_table_remove( ipc_clients, curr_client->table_key); } if(curr_client->client_source != NULL) { gboolean det = G_main_del_IPC_Channel( curr_client->client_source); crm_verbose("crm_client was %s detached", det?"successfully":"not"); } crm_free(curr_client->table_key); crm_free(curr_client->sub_sys); crm_free(curr_client->uuid); crm_free(curr_client); } return !hack_return_good; } return hack_return_good; } void lrm_op_callback (lrm_op_t* op) { /* todo: free op->rsc */ crm_debug("received callback"); register_fsa_input(C_LRM_OP_CALLBACK, I_LRM_EVENT, op); s_crmd_fsa(C_LRM_OP_CALLBACK); } void crmd_ha_status_callback( const char *node, const char * status, void* private_data) { xmlNodePtr update = NULL; xmlNodePtr fragment = NULL; - xmlNodePtr msg_options = NULL; - xmlNodePtr request = NULL; crm_debug("received callback"); crm_notice("Status update: Node %s now has status [%s]\n",node,status); if(AM_I_DC == FALSE) { crm_debug("Got nstatus callback in non-DC mode"); return; } else if(safe_str_neq(status, DEADSTATUS)) { crm_debug("nstatus callback was not for a dead node"); return; } /* this node is taost */ update = create_node_state( node, node, status, NULL, NULL, NULL, NULL); set_xml_property_copy( update, XML_CIB_ATTR_CLEAR_SHUTDOWN, XML_BOOLEAN_TRUE); fragment = create_cib_fragment(update, NULL); - msg_options = set_xml_attr( - NULL, XML_TAG_OPTIONS, XML_ATTR_OP, CRM_OP_UPDATE, TRUE); - - request = create_request( - msg_options, fragment, NULL, - CRM_SYSTEM_DCIB, CRM_SYSTEM_DC, NULL, NULL); - crm_xml_debug(fragment, "Node status update"); + update_local_cib(fragment, TRUE); + free_xml(fragment); free_xml(update); - - register_fsa_input(C_CRMD_STATUS_CALLBACK, I_CIB_OP, request); - s_crmd_fsa(C_CRMD_STATUS_CALLBACK); - } void crmd_client_status_callback(const char * node, const char * client, const char * status, void * private) { const char *join = NULL; const char *extra = NULL; xmlNodePtr update = NULL; xmlNodePtr fragment = NULL; - xmlNodePtr msg_options = NULL; - xmlNodePtr request = NULL; crm_debug("received callback"); set_bit_inplace(fsa_input_register, R_PEER_DATA); if(safe_str_eq(status, JOINSTATUS)){ status = ONLINESTATUS; extra = XML_CIB_ATTR_CLEAR_SHUTDOWN; } else if(safe_str_eq(status, LEAVESTATUS)){ status = OFFLINESTATUS; join = CRMD_JOINSTATE_DOWN; extra = XML_CIB_ATTR_CLEAR_SHUTDOWN; } crm_notice("Status update: Client %s/%s now has status [%s]\n", node, client, status); if(AM_I_DC == FALSE) { crm_debug("Got client status callback in non-DC mode"); return; } update = create_node_state( node, node, NULL, NULL, status, join, NULL); set_xml_property_copy(update, extra, XML_BOOLEAN_TRUE); fragment = create_cib_fragment(update, NULL); - msg_options = set_xml_attr( - NULL, XML_TAG_OPTIONS, XML_ATTR_OP, CRM_OP_UPDATE, TRUE); - - request = create_request( - msg_options, fragment, NULL, - CRM_SYSTEM_DCIB, CRM_SYSTEM_DC, NULL, NULL); - crm_xml_debug(fragment, "Client status update"); + update_local_cib(fragment, TRUE); + free_xml(fragment); free_xml(update); - - register_fsa_input(C_CRMD_STATUS_CALLBACK, I_CIB_OP, request); - s_crmd_fsa(C_CRMD_STATUS_CALLBACK); } xmlNodePtr find_xml_in_hamessage(const struct ha_msg* msg) { const char *xml; xmlDocPtr doc; xmlNodePtr root; if (msg == NULL) { crm_info("**** ha_crm_msg_callback called on a NULL message"); return NULL; } #if 0 crm_debug("[F_TYPE=%s]", ha_msg_value(msg, F_TYPE)); crm_debug("[F_ORIG=%s]", ha_msg_value(msg, F_ORIG)); crm_debug("[F_TO=%s]", ha_msg_value(msg, F_TO)); crm_debug("[F_COMMENT=%s]", ha_msg_value(msg, F_COMMENT)); crm_debug("[F_XML=%s]", ha_msg_value(msg, "xml")); /* crm_debug("[F_=%s]", ha_msg_value(ha_msg, F_)); */ #endif if (strcmp(T_CRM, ha_msg_value(msg, F_TYPE)) != 0) { crm_info("Received a (%s) message by mistake.", ha_msg_value(msg, F_TYPE)); return NULL; } xml = ha_msg_value(msg, "xml"); if (xml == NULL) { crm_info("No XML attached to this message."); return NULL; } doc = xmlParseMemory(xml, strlen(xml)); if (doc == NULL) { crm_info("XML Buffer was not valid."); return NULL; } root = xmlDocGetRootElement(doc); if (root == NULL) { crm_info("Root node was NULL."); return NULL; } return root; } gboolean lrm_dispatch(int fd, gpointer user_data) { int rc = 0; ll_lrm_t *lrm = (ll_lrm_t*)user_data; crm_debug("received callback"); rc = lrm->lrm_ops->rcvmsg(lrm, FALSE); return TRUE; } /* #define MAX_EMPTY_CALLBACKS 20 */ /* int empty_callbacks = 0; */ gboolean crmd_ha_msg_dispatch(IPC_Channel *channel, gpointer user_data) { int lpc = 0; ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data; while(hb_cluster->llc_ops->msgready(hb_cluster)) { lpc++; /* invoke the callbacks but dont block */ hb_cluster->llc_ops->rcvmsg(hb_cluster, 0); } crm_trace("%d HA messages dispatched", lpc); if (channel && (channel->ch_status == IPC_DISCONNECT)) { crm_crit("Lost connection to heartbeat service."); return FALSE; } return TRUE; } void crmd_ha_connection_destroy(gpointer user_data) { crm_crit("Heartbeat has left us"); /* this is always an error */ /* feed this back into the FSA */ register_fsa_input(C_HA_DISCONNECT, I_ERROR, NULL); s_crmd_fsa(C_HA_DISCONNECT); } 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_debug("Channel connected"); 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_msg_callback, blank_client, default_ipc_connection_destroy); } return TRUE; } gboolean ccm_dispatch(int fd, gpointer user_data) { int rc = 0; oc_ev_t *ccm_token = (oc_ev_t*)user_data; crm_debug("received callback"); rc = oc_ev_handle_event(ccm_token); if(0 == rc) { return TRUE; } else { crm_err("CCM connection appears to have failed: rc=%d.", rc); register_fsa_input(C_CCM_CALLBACK, I_ERROR, NULL); s_crmd_fsa(C_CCM_CALLBACK); return FALSE; } } void crmd_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data) { struct crmd_ccm_data_s *event_data = NULL; crm_debug("received callback"); if(data != NULL) { crm_malloc(event_data, sizeof(struct crmd_ccm_data_s)); if(event_data != NULL) { event_data->event = &event; event_data->oc = copy_ccm_oc_data( (const oc_ev_membership_t *)data); crm_debug("Sending callback to the FSA"); register_fsa_input( C_CCM_CALLBACK, I_CCM_EVENT, (void*)event_data); s_crmd_fsa(C_CCM_CALLBACK); 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; } diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c index e16df922ec..01e5478041 100644 --- a/crm/crmd/ccm.c +++ b/crm/crmd/ccm.c @@ -1,673 +1,660 @@ -/* $Id: ccm.c,v 1.43 2004/11/23 11:18:54 andrew Exp $ */ +/* $Id: ccm.c,v 1.44 2004/12/05 16:35:09 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 #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_msg_callback(oc_ed_t event, void *cookie, size_t size, const void *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; int num_ccm_register_fails = 0; int max_ccm_register_fails = 30; /* 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, fsa_data_t *msg_data) { int ret; int fsa_ev_fd; gboolean did_fail = FALSE; if(action & A_CCM_DISCONNECT){ oc_ev_unregister(fsa_ev_token); } if(action & A_CCM_CONNECT) { crm_info("Registering with CCM"); ret = oc_ev_register(&fsa_ev_token); if (ret != 0) { crm_warn("CCM registration failed"); did_fail = TRUE; } if(did_fail == FALSE) { crm_info("Setting up CCM callbacks"); ret = oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS, crmd_ccm_msg_callback, NULL); if (ret != 0) { crm_warn("CCM callback not set"); did_fail = TRUE; } } if(did_fail == FALSE) { 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 != 0){ crm_warn("CCM Activation failed"); did_fail = TRUE; } } if(did_fail) { num_ccm_register_fails++; oc_ev_unregister(fsa_ev_token); if(num_ccm_register_fails < max_ccm_register_fails) { crm_warn("CCM Connection failed" " %d times (%d max)", num_ccm_register_fails, max_ccm_register_fails); startTimer(wait_timer); crmd_fsa_stall(); return I_NULL; } else { crm_err("CCM Activation failed %d (max) times", num_ccm_register_fails); 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_connection_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, fsa_data_t *msg_data) { enum crmd_fsa_input return_input = I_NULL; oc_ed_t *event = NULL; const oc_ev_membership_t *oc = NULL; if(msg_data == NULL || msg_data->data == NULL) { crm_err("No data provided to FSA function"); return I_FAIL; } else if(msg_data->fsa_cause != C_CCM_CALLBACK) { crm_err("FSA function called in response to incorect input"); return I_NULL; } event = ((struct crmd_ccm_data_s *)msg_data->data)->event; oc = ((struct crmd_ccm_data_s *)msg_data->data)->oc; 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(AM_I_DC == FALSE || return_input == I_SHUTDOWN) { return return_input; } /* 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) { int lpc = 0; int offset = oc->m_out_idx; for(lpc=0; lpc < oc->m_n_out; lpc++) { - xmlNodePtr request = NULL; xmlNodePtr fragment = NULL; xmlNodePtr node_state = NULL; - xmlNodePtr msg_options = NULL; const char *uname = oc->m_array[offset+lpc].node_uname; crm_info("Node %s has left the cluster," " updating the CIB.", uname); if(uname == NULL) { crm_err("CCM node had no name"); continue; } node_state = create_node_state( NULL, uname, NULL, XML_BOOLEAN_NO, NULL, NULL, NULL); fragment = create_cib_fragment(node_state, NULL); - msg_options = set_xml_attr( - NULL, XML_TAG_OPTIONS, - XML_ATTR_OP, CRM_OP_UPDATE, TRUE); - - request = create_request( - msg_options, fragment, NULL, - CRM_SYSTEM_DCIB, CRM_SYSTEM_DC, NULL, NULL); - - register_fsa_input( - C_FSA_INTERNAL, I_CIB_OP, request); + update_local_cib(fragment, TRUE); - free_xml(msg_options); free_xml(node_state); free_xml(fragment); - free_xml(request); s_crmd_fsa(C_FSA_INTERNAL); } } else if(oc->m_n_in !=0) { /* delay the I_NODE_JOIN until they acknowledge our * DC status and send us their CIB */ } 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, fsa_data_t *msg_data) { enum crmd_fsa_input next_input = I_NULL; int lpc, offset; GHashTable *members = NULL; oc_ed_t *event = NULL; const oc_ev_membership_t *oc = NULL; oc_node_list_t *tmp = NULL, *membership_copy = NULL; if(msg_data == NULL || msg_data->data == NULL) { crm_err("No data provided to FSA function"); return I_FAIL; } else if(msg_data->fsa_cause != C_CCM_CALLBACK) { crm_err("FSA function called in response to incorect input"); return I_NULL; } event = ((struct crmd_ccm_data_s *)msg_data->data)->event; oc = ((struct crmd_ccm_data_s *)msg_data->data)->oc; 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"); crm_debug("instace=%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_malloc(membership_copy, sizeof(oc_node_list_t)); if(membership_copy == NULL) { crm_crit("Couldnt create membership copy - out of memory"); return I_ERROR; } crm_debug("Copying members"); /*--*-- 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_debug("Copying member %d", lpc); 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 = NULL; if(oc->m_array[offset+lpc].node_uname != NULL) { member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); } else { crm_err("Node %d had a NULL uname", member->node_id); } g_hash_table_insert( members, member->node_uname, member); } } else { membership_copy->members = NULL; } crm_debug("Copying new members"); /*--*-- 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_uname = NULL; member->node_id = oc->m_array[offset+lpc].node_id; member->node_born_on = oc->m_array[offset+lpc].node_born_on; if(oc->m_array[offset+lpc].node_uname != NULL) { member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); } else { crm_err("Node %d had a NULL uname", member->node_id); } g_hash_table_insert( members, member->node_uname, member); g_hash_table_insert(members, member->node_uname, member); } } else { membership_copy->new_members = NULL; } crm_debug("Copying dead members"); /*--*-- 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 = NULL; if(oc->m_array[offset+lpc].node_uname != NULL) { member->node_uname = crm_strdup(oc->m_array[offset+lpc].node_uname); } else { crm_err("Node %d had a NULL uname", member->node_id); } g_hash_table_insert( members, member->node_uname, member); g_hash_table_insert(members, member->node_uname, member); } } else { membership_copy->dead_members = NULL; } crm_debug("Replacing old copies"); tmp = fsa_membership_copy; fsa_membership_copy = membership_copy; /* 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); } crm_debug("Free'd old copies"); if(AM_I_DC) { /* should be sufficient for only the DC to do this */ crm_debug("Updating the CIB"); free_xml(do_update_cib_nodes(NULL, FALSE)); } set_bit_inplace(fsa_input_register, R_CCM_DATA); 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_trace("%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 && 0 == strcmp(fsa_our_uname, oc->m_array[oc->m_out_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; } 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); + update_local_cib(fragment, TRUE); 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, NULL, data->state, NULL, state, NULL); 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/cib.c b/crm/crmd/cib.c index c0233be0af..ace4e59497 100644 --- a/crm/crmd/cib.c +++ b/crm/crmd/cib.c @@ -1,281 +1,196 @@ /* * 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 struct crm_subsystem_s *cib_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, fsa_data_t *msg_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 */ + fsa_cib_conn->cmds->signoff(fsa_cib_conn); } if(action & start_actions) { - + if(cur_state != S_STOPPING) { - if(startCib(CIB_FILENAME) == FALSE) + if(fsa_cib_conn->cmds->signon( + fsa_cib_conn, cib_command) != cib_ok) { result = I_FAIL; - + } + } else { crm_info("Ignoring request to start %s after shutdown", this_subsys->name); } } 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, fsa_data_t *msg_data) { xmlNodePtr cib_msg = NULL; xmlNodePtr answer = NULL; - xmlNodePtr new_options = NULL; - const char *section = NULL; enum crmd_fsa_input result = I_NULL; - + if(msg_data->data != NULL) { cib_msg = (xmlNodePtr)msg_data->data; } if(action & A_CIB_INVOKE || action & A_CIB_INVOKE_LOCAL) { -/* gboolean is_update = FALSE; */ + enum cib_errors rc = cib_ok; + xmlNodePtr cib_frag = NULL; xmlNodePtr msg_copy = copy_xml_node_recursive(cib_msg); xmlNodePtr options = find_xml_node(msg_copy, XML_TAG_OPTIONS); - + const char *sys_from = xmlGetProp(msg_copy, XML_ATTR_SYSFROM); - const char *host_from= xmlGetProp(msg_copy, XML_ATTR_HOSTFROM); const char *type = xmlGetProp(options, XML_ATTR_MSGTYPE); const char *op = xmlGetProp(options, XML_ATTR_OP); + cib_t *cib = NULL; + crm_xml_devel(msg_copy, "[CIB update]"); if(cib_msg == NULL) { crm_err("No message for CIB command"); return I_NULL; /* I_ERROR */ - + } else if(op == NULL) { crm_xml_devel(msg_copy, "Invalid CIB Message"); return I_NULL; /* I_ERROR */ - - } - if(AM_I_DC - && safe_str_eq(op, CRM_OP_RETRIVE_CIB) - && safe_str_eq(type, XML_ATTR_RESPONSE)) { - /* we actually need to process this as a REPLACE, - * not pretty, but fake the op type... - */ - crm_debug("Mapping %s reply to a %s request", - CRM_OP_RETRIVE_CIB, CRM_OP_REPLACE); - - set_xml_property_copy( - options, XML_ATTR_OP, CRM_OP_REPLACE); - - crm_xml_devel(msg_copy, "[CIB revised update]"); - } else if(safe_str_eq(op, CRM_OP_RETRIVE_CIB)) { - crm_debug("is dc? %d, type=%s", AM_I_DC, type); } - set_xml_property_copy(msg_copy, XML_ATTR_SYSTO, "cib"); - answer = process_cib_message(msg_copy, 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_RETRIVE_CIB) == 0 - || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { - register_fsa_input( - C_IPC_MESSAGE, I_CIB_UPDATE, cib_msg); - - } else if(strcmp(op, CRM_OP_RETRIVE_CIB) == 0) { - crm_info("Retrieved latest CIB from %s", - host_from); - set_bit_inplace(fsa_input_register,R_HAVE_CIB); - - } else if(strcmp(op, CRM_OP_ERASE) == 0) { - /* regenerate everyone's state and our node entry */ - register_fsa_input( - C_UNKNOWN, I_ELECTION_DC, NULL); - } - - /* 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_debug("is dc? %d, type=%s", AM_I_DC, type); + rc = cib->cmds->variant_op(cib, op, NULL, NULL, &cib_frag, + cib_scope_local|cib_sync_call); + + answer = create_reply(cib_msg, cib_frag); + set_xml_attr(answer, XML_TAG_OPTIONS, + XML_ATTR_RESULT, cib_error2string(rc), TRUE); + + 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 { */ -/* put_message(answer); */ -/* return I_REQUEST; */ - - } - - 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; +#if 0 +// ---# do in CIB notify callbacks #--- + + } else if(strcmp(op, CRM_OP_RETRIVE_CIB) == 0) { + crm_info("Retrieved latest CIB from %s", host_from); + set_bit_inplace(fsa_input_register,R_HAVE_CIB); + } else if(strcmp(op, CRM_OP_CIB_ERASE) == 0) { + /* regenerate everyone's state and our node entry */ + register_fsa_input(C_UNKNOWN, I_ELECTION_DC, NULL); +#endif } - - /* 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); + /* 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; } - 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; - } + return result; - 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__); + fsa_action2string(action), __FUNCTION__); } - return I_NULL; } enum crmd_fsa_input -invoke_local_cib(xmlNodePtr msg_options, - xmlNodePtr msg_data, - const char *operation) +update_local_cib(xmlNodePtr msg_data, gboolean callbacks) { enum crmd_fsa_input result = I_NULL; - xmlNodePtr request = NULL; - fsa_data_t *fsa_data = 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); - - crm_malloc(fsa_data, sizeof(fsa_data_t)); - fsa_data->fsa_input = I_CIB_UPDATE; - fsa_data->fsa_cause = C_IPC_MESSAGE; - fsa_data->data = request; - - result = do_cib_invoke( - A_CIB_INVOKE_LOCAL, C_FSA_INTERNAL, fsa_state, - I_CIB_OP, fsa_data); - - crm_free(fsa_data); - free_xml(request); - - return I_NULL; + enum cib_errors rc = cib_ok; + + const char *section = xmlGetProp(msg_data, XML_ATTR_SECTION); + int call_options = cib_scope_local|cib_discard_reply|cib_sync_call; + + if(callbacks == FALSE) { + call_options |= cib_inhibit_notify; + } + + rc = fsa_cib_conn->cmds->modify( + fsa_cib_conn, section, msg_data, NULL, call_options); + + if(rc != cib_ok) { + result = I_FAIL; + } + return result; } diff --git a/crm/crmd/control.c b/crm/crmd/control.c index 0174e99032..1d95108d45 100644 --- a/crm/crmd/control.c +++ b/crm/crmd/control.c @@ -1,631 +1,575 @@ /* * 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 extern void crmd_ha_connection_destroy(gpointer user_data); extern gboolean stop_all_resources(void); void crm_shutdown(int nsig); -IPC_WaitConnection *wait_channel_init(char daemonsocket[]); +/* IPC_WaitConnection *wait_channel_init(char daemonsocket[]); */ gboolean register_with_ha(ll_cluster_t *hb_cluster, const char *client_name); -int init_server_ipc_comms( - const char *child, - gboolean (*channel_client_connect)( - IPC_Channel *newclient, gpointer user_data), - void (*channel_connection_destroy)(gpointer user_data)); GHashTable *ipc_clients = NULL; /* A_HA_CONNECT */ enum crmd_fsa_input do_ha_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { gboolean registered = FALSE; if(action & A_HA_DISCONNECT) { if(fsa_cluster_conn != NULL) { fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn); } } if(action & A_HA_CONNECT) { if(fsa_cluster_conn == NULL) fsa_cluster_conn = ll_cluster_new("heartbeat"); /* make sure we are disconnected first */ fsa_cluster_conn->llc_ops->signoff(fsa_cluster_conn); registered = register_with_ha( fsa_cluster_conn, crm_system_name); if(registered == FALSE) { return I_FAIL; } } if(action & ~(A_HA_CONNECT|A_HA_DISCONNECT)) { crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__); } return I_NULL; } /* A_SHUTDOWN */ enum crmd_fsa_input do_shutdown(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { enum crmd_fsa_input next_input = I_NULL; enum crmd_fsa_input tmp = I_NULL; /* just in case */ set_bit_inplace(fsa_input_register, R_SHUTDOWN); /* last attempt to shut these down */ if(is_set(fsa_input_register, R_PE_CONNECTED)) { crm_warn("Last attempt to shutdown the PolicyEngine"); tmp = do_pe_control(A_PE_STOP, cause, cur_state, current_input, msg_data); if(tmp != I_NULL) { next_input = I_ERROR; crm_err("Failed to shutdown the PolicyEngine"); } } if(is_set(fsa_input_register, R_TE_CONNECTED)) { crm_warn("Last attempt to shutdown the Transitioner"); tmp = do_pe_control(A_TE_STOP, cause, cur_state, current_input, msg_data); if(tmp != I_NULL) { next_input = I_ERROR; crm_err("Failed to shutdown the Transitioner"); } } crm_info("Stopping all remaining local resources"); stop_all_resources(); return next_input; } /* A_SHUTDOWN_REQ */ enum crmd_fsa_input do_shutdown_req(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { enum crmd_fsa_input next_input = I_NULL; if(send_request(NULL, NULL, CRM_OP_SHUTDOWN_REQ, NULL, CRM_SYSTEM_DC, NULL) == FALSE){ next_input = I_ERROR; } return next_input; } /* A_EXIT_0, A_EXIT_1 */ enum crmd_fsa_input do_exit(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { if(action & A_EXIT_0) { crm_info("Performing %s - gracefully exiting the CRMd\n", fsa_action2string(action)); g_main_quit(crmd_mainloop); } else { crm_warn("Performing %s - forcefully exiting the CRMd\n", fsa_action2string(action)); exit(1); } return I_NULL; } /* A_STARTUP */ enum crmd_fsa_input do_startup(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { int was_error = 0; int interval = 1; /* seconds between DC heartbeats */ crm_info("Register PID"); register_pid(PID_FILE, FALSE, crm_shutdown); ipc_clients = g_hash_table_new(&g_str_hash, &g_str_equal); if(was_error == 0) { crm_info("Init server comms"); was_error = init_server_ipc_comms( - CRM_SYSTEM_CRMD, crmd_client_connect, + crm_strdup(CRM_SYSTEM_CRMD), crmd_client_connect, default_ipc_connection_destroy); } + if(was_error == 0) { + crm_info("Creating CIB object"); + fsa_cib_conn = cib_new(); + } + /* set up the timers */ crm_malloc(dc_heartbeat, sizeof(fsa_timer_t)); crm_malloc(integration_timer, sizeof(fsa_timer_t)); crm_malloc(finalization_timer, sizeof(fsa_timer_t)); crm_malloc(election_trigger, sizeof(fsa_timer_t)); crm_malloc(election_timeout, sizeof(fsa_timer_t)); crm_malloc(shutdown_escalation_timer, sizeof(fsa_timer_t)); crm_malloc(wait_timer, sizeof(fsa_timer_t)); interval = interval * 1000; if(election_trigger != NULL) { election_trigger->source_id = -1; election_trigger->period_ms = -1; election_trigger->fsa_input = I_DC_TIMEOUT; election_trigger->callback = timer_popped; } else { was_error = TRUE; } if(dc_heartbeat != NULL) { dc_heartbeat->source_id = -1; dc_heartbeat->period_ms = -1; dc_heartbeat->fsa_input = I_NULL; dc_heartbeat->callback = do_dc_heartbeat; } else { was_error = TRUE; } if(election_timeout != NULL) { election_timeout->source_id = -1; election_timeout->period_ms = -1; election_timeout->fsa_input = I_ELECTION_DC; election_timeout->callback = timer_popped; } else { was_error = TRUE; } if(integration_timer != NULL) { integration_timer->source_id = -1; integration_timer->period_ms = -1; integration_timer->fsa_input = I_INTEGRATED; integration_timer->callback = timer_popped; } else { was_error = TRUE; } if(finalization_timer != NULL) { finalization_timer->source_id = -1; finalization_timer->period_ms = -1; finalization_timer->fsa_input = I_FINALIZED; finalization_timer->callback = timer_popped; } else { was_error = TRUE; } if(shutdown_escalation_timer != NULL) { shutdown_escalation_timer->source_id = -1; shutdown_escalation_timer->period_ms = -1; shutdown_escalation_timer->fsa_input = I_TERMINATE; shutdown_escalation_timer->callback = timer_popped; } else { was_error = TRUE; } if(wait_timer != NULL) { wait_timer->source_id = -1; wait_timer->period_ms = 3*1000; wait_timer->fsa_input = I_NULL; wait_timer->callback = timer_popped; } else { was_error = TRUE; } /* set up the sub systems */ crm_malloc(cib_subsystem, sizeof(struct crm_subsystem_s)); crm_malloc(te_subsystem, sizeof(struct crm_subsystem_s)); crm_malloc(pe_subsystem, sizeof(struct crm_subsystem_s)); if(cib_subsystem != NULL) { cib_subsystem->pid = -1; cib_subsystem->flag = R_CIB_CONNECTED; cib_subsystem->path = BIN_DIR; cib_subsystem->name = CRM_SYSTEM_CIB; cib_subsystem->command = BIN_DIR"/"CRM_SYSTEM_CIB; cib_subsystem->args = "-VVc"; } else { was_error = TRUE; } if(te_subsystem != NULL) { te_subsystem->pid = -1; te_subsystem->flag = R_TE_CONNECTED; te_subsystem->path = BIN_DIR; te_subsystem->name = CRM_SYSTEM_TENGINE; te_subsystem->command = BIN_DIR"/"CRM_SYSTEM_TENGINE; te_subsystem->args = "-VVc"; } else { was_error = TRUE; } if(pe_subsystem != NULL) { pe_subsystem->pid = -1; pe_subsystem->flag = R_PE_CONNECTED; pe_subsystem->path = BIN_DIR; pe_subsystem->name = CRM_SYSTEM_PENGINE; pe_subsystem->command = BIN_DIR"/"CRM_SYSTEM_PENGINE; pe_subsystem->args = "-VVc"; } else { was_error = TRUE; } if(was_error) return I_FAIL; return I_NULL; } /* A_STOP */ enum crmd_fsa_input do_stop(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { /* nothing to do yet */ /* todo: shut down any remaining CRM resources */ return I_NULL; } /* A_STARTED */ enum crmd_fsa_input do_started(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { if(is_set(fsa_input_register, R_CCM_DATA) == FALSE /* || is_set(fsa_input_register, R_PE_CONNECTED) == FALSE */ /* || is_set(fsa_input_register, R_TE_CONNECTED) == FALSE */ || is_set(fsa_input_register, R_LRM_CONNECTED) == FALSE ) { crm_info("Delaying start, some systems not connected %.16llx (%.16llx)", fsa_input_register, (long long)R_CCM_DATA|R_LRM_CONNECTED); crmd_fsa_stall(); return I_NULL; } else if(is_set(fsa_input_register, R_PEER_DATA) == FALSE) { struct ha_msg* msg = NULL; /* try reading from HA */ crm_info("Delaying start, some systems not connected %.16llx (%.16llx)", fsa_input_register, (long long)R_PEER_DATA); crm_debug("Looking for a HA message"); msg = fsa_cluster_conn->llc_ops->readmsg(fsa_cluster_conn, 0); if(msg != NULL) { crm_debug("There was a HA message"); ha_msg_del(msg); } startTimer(wait_timer); crmd_fsa_stall(); return I_NULL; } crm_info("The local CRM is operational"); clear_bit_inplace(fsa_input_register, R_STARTING); register_fsa_input(msg_data->fsa_cause, I_PENDING, NULL); return I_NULL; } /* A_RECOVER */ enum crmd_fsa_input do_recover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { crm_err("Action %s (%.16llx) not supported\n", fsa_action2string(action), action); return I_SHUTDOWN; } /* 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, fsa_data_t *msg_data) { - xmlNodePtr cib_copy = get_cib_copy(); + xmlNodePtr cib_copy = get_cib_copy(fsa_cib_conn); xmlNodePtr config = get_object_root(XML_CIB_TAG_CRMCONFIG, cib_copy); xml_child_iter( config, iter, XML_CIB_TAG_NVPAIR, const char *name = xmlGetProp(iter, XML_NVPAIR_ATTR_NAME); const char *value = xmlGetProp(iter, XML_NVPAIR_ATTR_VALUE); if(name == NULL || value == NULL) { continue; } else if(safe_str_eq(name, "dc_heartbeat")) { dc_heartbeat->period_ms = atoi(value); } else if(safe_str_eq(name, "dc_deadtime")) { election_trigger->period_ms = atoi(value); } else if(safe_str_eq(name, "shutdown_escalation")) { shutdown_escalation_timer->period_ms = atoi(value); } else if(safe_str_eq(name, "join_reannouce")) { fsa_join_reannouce = atoi(value); } ); if(dc_heartbeat->period_ms < 1) { /* sensible default */ dc_heartbeat->period_ms = 1000; } if(election_trigger->period_ms < 1) { /* sensible default */ election_trigger->period_ms = dc_heartbeat->period_ms * 4; } if(shutdown_escalation_timer->period_ms < 1) { /* sensible default */ shutdown_escalation_timer->period_ms = election_trigger->period_ms * 3 *10;/* 10 for testing */ } if(fsa_join_reannouce < 0) { fsa_join_reannouce = 100; /* how many times should we let * go by before reannoucning * ourselves to the DC */ } election_timeout->period_ms = dc_heartbeat->period_ms * 6; integration_timer->period_ms = dc_heartbeat->period_ms * 6; finalization_timer->period_ms = dc_heartbeat->period_ms * 6; return I_NULL; } void crm_shutdown(int nsig) { CL_SIGNAL(nsig, crm_shutdown); if (crmd_mainloop != NULL && g_main_is_running(crmd_mainloop)) { if(is_set(fsa_input_register, R_SHUTDOWN)) { crm_err("Escalating the shutdown"); register_fsa_input(C_SHUTDOWN, I_ERROR, NULL); s_crmd_fsa(C_SHUTDOWN); } else { set_bit_inplace(fsa_input_register, R_SHUTDOWN); if(is_set(fsa_input_register, R_SHUTDOWN)) { /* cant rely on this... */ startTimer(shutdown_escalation_timer); register_fsa_input(C_SHUTDOWN, I_SHUTDOWN, NULL); s_crmd_fsa(C_SHUTDOWN); } else { crm_err("Could not set R_SHUTDOWN"); exit(LSB_EXIT_ENOTSUPPORTED); } } } else { crm_info("exit from shutdown"); exit(LSB_EXIT_OK); } return; } -IPC_WaitConnection * -wait_channel_init(char daemonsocket[]) -{ - IPC_WaitConnection *wait_ch; - mode_t mask; - char path[] = IPC_PATH_ATTR; - GHashTable * attrs; - - - attrs = g_hash_table_new(g_str_hash,g_str_equal); - g_hash_table_insert(attrs, path, daemonsocket); - - mask = umask(0); - wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs); - if (wait_ch == NULL) { - cl_perror("Can't create wait channel of type %s", - IPC_ANYTYPE); - exit(1); - } - mask = umask(mask); - - g_hash_table_destroy(attrs); - - return wait_ch; -} - -int -init_server_ipc_comms( - const char *child, - gboolean (*channel_client_connect)(IPC_Channel *newclient,gpointer user_data), - void (*channel_connection_destroy)(gpointer user_data)) -{ - /* the clients wait channel is the other source of events. - * This source delivers the clients connection events. - * listen to this source at a relatively lower priority. - */ - - char commpath[SOCKET_LEN]; - IPC_WaitConnection *wait_ch; - - sprintf(commpath, WORKING_DIR "/%s", child); - - wait_ch = wait_channel_init(commpath); - - if (wait_ch == NULL) { - return 1; - } - - G_main_add_IPC_WaitConnection( - G_PRIORITY_LOW, wait_ch, NULL, FALSE, - channel_client_connect, wait_ch, channel_connection_destroy); - - crm_debug("Listening on: %s", commpath); - - return 0; -} - -#define safe_val3(def, t,u,v) (t?t->u?t->u->v:def:def) - gboolean register_with_ha(ll_cluster_t *hb_cluster, const char *client_name) { int facility; if(safe_val3(NULL, hb_cluster, llc_ops, errmsg) == NULL) { crm_crit("cluster errmsg function unavailable"); } crm_info("Signing in with Heartbeat"); if (hb_cluster->llc_ops->signon(hb_cluster, client_name)!= HA_OK) { crm_err("Cannot sign on with heartbeat: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } /* change the logging facility to the one used by heartbeat daemon */ crm_info("Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } crm_verbose("Facility: %d", facility); crm_debug("Be informed of CRM messages"); if (HA_OK != hb_cluster->llc_ops->set_msg_callback( hb_cluster, T_CRM, crmd_ha_msg_callback, hb_cluster)){ crm_err("Cannot set msg callback: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } #if 0 crm_debug("Be informed of Node Status changes"); if (HA_OK != hb_cluster->llc_ops->set_nstatus_callback( hb_cluster, crmd_ha_status_callback, hb_cluster)){ crm_err("Cannot set nstatus callback: %s", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } #endif crm_debug("Be informed of CRM Client Status changes"); if (HA_OK != hb_cluster->llc_ops->set_cstatus_callback( hb_cluster, crmd_client_status_callback, hb_cluster)) { crm_err("Cannot set cstatus callback: %s\n", hb_cluster->llc_ops->errmsg(hb_cluster)); return FALSE; } + crm_info("beekhof: Client Status callback set"); + crm_debug("Adding channel to mainloop"); G_main_add_IPC_Channel( G_PRIORITY_HIGH, hb_cluster->llc_ops->ipcchan(hb_cluster), FALSE, crmd_ha_msg_dispatch, hb_cluster /* userdata */, crmd_ha_connection_destroy); crm_debug("Finding our node name"); if ((fsa_our_uname = hb_cluster->llc_ops->get_mynodeid(hb_cluster)) == NULL) { crm_err("get_mynodeid() failed"); return FALSE; } crm_info("FSA Hostname: %s", fsa_our_uname); /* Async get client status information in the cluster */ crm_debug("Requesting an initial dump of CRMD client_status"); + crm_info("beekhof: Requesting Client Status"); fsa_cluster_conn->llc_ops->client_status( fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1); return TRUE; } diff --git a/crm/crmd/crmd_fsa.h b/crm/crmd/crmd_fsa.h index c522f4ad60..15253f2b5a 100644 --- a/crm/crmd/crmd_fsa.h +++ b/crm/crmd/crmd_fsa.h @@ -1,127 +1,131 @@ -/* $Id: crmd_fsa.h,v 1.32 2004/11/24 15:37:44 andrew Exp $ */ +/* $Id: crmd_fsa.h,v 1.33 2004/12/05 16:35:09 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CRMD_FSA__H #define CRMD_FSA__H #include #include #include #include #include #include #include +#include struct crmd_ccm_data_s { oc_ev_membership_t *oc; oc_ed_t *event; }; struct oc_node_list_s { int members_size; GHashTable *members; /* contents: oc_node_t * */ int new_members_size; GHashTable *new_members; /* contents: oc_node_t * */ int dead_members_size; GHashTable *dead_members; /* contents: oc_node_t * */ }; typedef struct oc_node_list_s oc_node_list_t; /* copy from struct client_child in heartbeat.h * * Plus a couple of other things */ struct crm_subsystem_s { pid_t pid; /* Process id of child process */ const char* name; /* executable name */ const char* path; /* Command location */ const char* command; /* Command with path */ const char* args; /* Command arguments */ IPC_Channel *ipc; /* How can we communicate with it */ long long flag; /* */ }; typedef struct fsa_timer_s fsa_timer_t; struct fsa_timer_s { guint source_id; /* timer source id */ int period_ms; /* timer period */ enum crmd_fsa_input fsa_input; gboolean (*callback)(gpointer data); }; typedef struct fsa_data_s fsa_data_t; struct fsa_data_s { int id; enum crmd_fsa_input fsa_input; enum crmd_fsa_cause fsa_cause; long long actions; const char *where; void *data; }; extern enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause); /* Global FSA stuff */ extern volatile gboolean do_fsa_stall; extern volatile enum crmd_fsa_state fsa_state; +extern volatile long long fsa_input_register; +extern volatile long long fsa_actions; + extern oc_node_list_t *fsa_membership_copy; extern ll_cluster_t *fsa_cluster_conn; extern ll_lrm_t *fsa_lrm_conn; -extern volatile long long fsa_input_register; -extern volatile long long fsa_actions; -extern const char *fsa_our_uname; -extern char *fsa_pe_ref; /* the last invocation of the PE */ -extern char *fsa_our_dc; -extern GListPtr fsa_message_queue; +extern cib_t *fsa_cib_conn; + +extern const char *fsa_our_uname; +extern char *fsa_pe_ref; /* the last invocation of the PE */ +extern char *fsa_our_dc; +extern GListPtr fsa_message_queue; extern fsa_timer_t *election_trigger; /* */ extern fsa_timer_t *election_timeout; /* */ extern fsa_timer_t *shutdown_escalation_timer; /* */ extern fsa_timer_t *dc_heartbeat; extern fsa_timer_t *integration_timer; extern fsa_timer_t *finalization_timer; extern fsa_timer_t *wait_timer; extern int fsa_join_reannouce; extern struct crm_subsystem_s *cib_subsystem; extern struct crm_subsystem_s *te_subsystem; extern struct crm_subsystem_s *pe_subsystem; /* these two should be moved elsewhere... */ extern xmlNodePtr do_update_cib_nodes(xmlNodePtr updates, gboolean overwrite); extern gboolean do_dc_heartbeat(gpointer data); #define AM_I_DC is_set(fsa_input_register, R_THE_DC) #define AM_I_OPERATIONAL (is_set(fsa_input_register, R_STARTING)==FALSE) #include #include #endif diff --git a/crm/crmd/crmd_utils.h b/crm/crmd/crmd_utils.h index 1f2ea2a97c..b04845b8ef 100644 --- a/crm/crmd/crmd_utils.h +++ b/crm/crmd/crmd_utils.h @@ -1,68 +1,69 @@ -/* $Id: crmd_utils.h,v 1.9 2004/10/21 18:25:42 andrew Exp $ */ +/* $Id: crmd_utils.h,v 1.10 2004/12/05 16:35:09 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CRMD_UTILS__H #define CRMD_UTILS__H #include #include +#define CLIENT_EXIT_WAIT 30 + +extern enum crmd_fsa_input update_local_cib( + xmlNodePtr msg_data, gboolean callbacks); + + extern long long toggle_bit (long long action_list, long long action); extern long long clear_bit (long long action_list, long long action); extern long long set_bit (long long action_list, long long action); #define set_bit_inplace(word, bit) word = set_bit(word, bit) #define clear_bit_inplace(word, bit) word = clear_bit(word, bit) #define toggle_bit_inplace(word, bit) word = toggle_bit(word, bit) extern gboolean is_set(long long action_list, long long action); extern gboolean is_set_any(long long action_list, long long action); +extern gboolean stopTimer (fsa_timer_t *timer); extern gboolean startTimer(fsa_timer_t *timer); -extern gboolean stopTimer(fsa_timer_t *timer); extern gboolean timer_popped(gpointer data); extern void cleanup_subsystem(struct crm_subsystem_s *the_subsystem); extern xmlNodePtr create_node_state( const char *uuid, const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_state); extern void create_node_entry( const char *uuid, const char *uname, const char *type); -extern enum crmd_fsa_input invoke_local_cib( - xmlNodePtr msg_options, xmlNodePtr msg_data, const char *operation); - extern void set_uuid(xmlNodePtr node, const char *attr, const char *uname); -#define CLIENT_EXIT_WAIT 30 - extern gboolean stop_subsystem (struct crm_subsystem_s *centry); extern gboolean start_subsystem(struct crm_subsystem_s *centry); extern lrm_op_t *copy_lrm_op(const lrm_op_t *op); extern lrm_rsc_t *copy_lrm_rsc(const lrm_rsc_t *rsc); extern struct crmd_ccm_data_s *copy_ccm_data( const struct crmd_ccm_data_s *ccm_input); extern oc_ev_membership_t *copy_ccm_oc_data(const oc_ev_membership_t *oc_in) ; extern void fsa_dump_actions(long long action, const char *text); #endif diff --git a/crm/crmd/election.c b/crm/crmd/election.c index c126d7f650..a03c699cad 100644 --- a/crm/crmd/election.c +++ b/crm/crmd/election.c @@ -1,316 +1,312 @@ /* * 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, fsa_data_t *msg_data) { gboolean not_voting = FALSE; xmlNodePtr msg_options = NULL; /* dont vote if we're in one of these states or wanting to shut down */ switch(cur_state) { case S_RECOVERY: 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 == FALSE) { if(is_set(fsa_input_register, R_STARTING)) { not_voting = TRUE; } } if(not_voting) { 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); startTimer(election_timeout); return I_NULL; } 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 */ register_fsa_input(C_HEARTBEAT_FAILED, I_SHUTDOWN, NULL); s_crmd_fsa(C_HEARTBEAT_FAILED); } 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, fsa_data_t *msg_data) { gboolean we_loose = FALSE; xmlNodePtr vote = (xmlNodePtr)msg_data->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 == NULL) { /* if the membership copy is NULL we REALLY shouldnt be voting * the question is how we managed to get here. */ crm_err("Membership copy was NULL"); return I_NULL; } else if(fsa_membership_copy->members_size < 1) { /* if even we are not in the cluster then we should not vote */ return I_NULL; } 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(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_ELECTION; /* 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_PENDING; } } 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, fsa_data_t *msg_data) { 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, fsa_data_t *msg_data) { 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); crm_free(fsa_our_dc); fsa_our_dc = crm_strdup(fsa_our_uname); - /* Async get client status information in the cluster */ - fsa_cluster_conn->llc_ops->client_status( - fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD, -1); - 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); - + 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, fsa_data_t *msg_data) { enum crmd_fsa_input result = I_NULL; crm_trace("################## Releasing the DC ##################"); stopTimer(dc_heartbeat); if(action & A_DC_RELEASE) { clear_bit_inplace(fsa_input_register, R_THE_DC); /* get a new CIB from the new DC */ clear_bit_inplace(fsa_input_register, R_HAVE_CIB); } else if (action & A_DC_RELEASED) { if(cur_state == S_STOPPING) { result = I_SHUTDOWN; /* necessary? */ result = I_RELEASE_SUCCESS; } #if 0 else if( are there errors ) { /* we cant stay up if not healthy */ /* or perhaps I_ERROR and go to S_RECOVER? */ result = I_SHUTDOWN; } #endif else result = I_RELEASE_SUCCESS; } else { 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 500e210b8a..b07de13c9e 100644 --- a/crm/crmd/fsa.c +++ b/crm/crmd/fsa.c @@ -1,756 +1,757 @@ /* * 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 int num_join_invites; extern GHashTable *join_requests; extern GHashTable *confirmed_nodes; extern void initialize_join(gboolean before); 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, fsa_data_t *msg_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)) { \ last_action = x; \ actions = clear_bit(actions, x); \ crm_verbose("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ next_input = y(x, cause, cur_state, last_input, fsa_data); \ crm_verbose("Action complete: %s (%.16llx)", \ fsa_action2string(x), x); \ if(next_input != I_NULL) { \ crm_warn("Action %s returned %s", \ fsa_action2string(x), \ fsa_input2string(next_input)); \ } \ if((x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ){ \ fprintf(dot_strm, "\t// %s\n", \ fsa_action2string(x)); \ } \ fflush(dot_strm); \ } # 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, fsa_data); \ if( (x & O_DC_TICKLE) == 0 && next_input != I_DC_HEARTBEAT ) \ fprintf(dot_strm, "\t// %s\n", fsa_action2string(x)); \ fflush(dot_strm); \ } # endif #else # ifdef FSA_TRACE # define IF_FSA_ACTION(x,y) \ if(is_set(actions,x)) { \ last_action = x; \ actions = clear_bit(actions, x); \ crm_verbose("Invoking action %s (%.16llx)", \ fsa_action2string(x), x); \ next_input = y(x, cause, cur_state, last_input, fsa_data); \ crm_verbose("Action complete: %s (%.16llx)", \ fsa_action2string(x), x); \ if(next_input != I_NULL) { \ crm_warn("Action %s returned %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, fsa_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_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; volatile enum crmd_fsa_state fsa_state = S_STARTING; oc_node_list_t *fsa_membership_copy; ll_cluster_t *fsa_cluster_conn; ll_lrm_t *fsa_lrm_conn; volatile long long fsa_input_register; volatile long long fsa_actions = A_NOTHING; const char *fsa_our_uname; char *fsa_our_dc; +cib_t *fsa_cib_conn = NULL; fsa_timer_t *election_trigger = NULL; /* */ fsa_timer_t *election_timeout = NULL; /* */ fsa_timer_t *shutdown_escalation_timer = NULL; /* */ fsa_timer_t *integration_timer = NULL; fsa_timer_t *finalization_timer = NULL; fsa_timer_t *dc_heartbeat = NULL; fsa_timer_t *wait_timer = NULL; int fsa_join_reannouce = 0; volatile gboolean do_fsa_stall = FALSE; enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause) { fsa_data_t *fsa_data = NULL; long long actions = fsa_actions; long long new_actions = A_NOTHING; long long last_action = A_NOTHING; enum crmd_fsa_input last_input = I_NULL; enum crmd_fsa_input cur_input = I_NULL; enum crmd_fsa_input next_input = I_NULL; enum crmd_fsa_state starting_state = fsa_state; enum crmd_fsa_state last_state = starting_state; enum crmd_fsa_state cur_state = starting_state; enum crmd_fsa_state next_state = starting_state; #ifdef FSA_TRACE crm_verbose("FSA invoked with Cause: %s\tState: %s", fsa_cause2string(cause), fsa_state2string(cur_state)); #endif #ifdef DOT_FSA_ACTIONS if(dot_strm == NULL) { dot_strm = fopen(DEVEL_DIR"/live.dot", "w"); fprintf(dot_strm, "%s", dot_intro); 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. * */ do_fsa_stall = FALSE; while(next_input != I_NULL || actions != A_NOTHING || is_message()) { if(do_fsa_stall) { /* we may be waiting for an a-sync task to "happen" * and until it does, we cant do anything else */ crm_info("Wait until something else happens"); break; } else if((is_message() && fsa_data == NULL) || (is_message() && actions == A_NOTHING && next_input == I_NULL)) { fsa_data_t *stored_msg = NULL; crm_debug("Finished with current input..." " Checking messages (%d remaining)", g_list_length(fsa_message_queue)); next_input = I_NULL; stored_msg = get_message(); if(stored_msg == NULL) { crm_crit("Invalid stored message"); exit(1); } delete_fsa_input(fsa_data); if(stored_msg->fsa_cause == C_CCM_CALLBACK) { crm_devel("FSA processing CCM callback from %s", stored_msg->where); } else if(stored_msg->fsa_cause == C_LRM_OP_CALLBACK) { crm_devel("FSA processing LRM callback from %s", stored_msg->where); } else if(stored_msg->data == NULL) { crm_devel("FSA processing input from %s", stored_msg->where); } else { crm_devel("FSA processing XML message from %s", stored_msg->where); crm_xml_devel(stored_msg->data, "FSA processing message"); } fsa_data = stored_msg; /* set up the input */ next_input = fsa_data->fsa_input; /* add any actions back to the queue */ actions |= fsa_data->actions; /* update the cause */ cause = fsa_data->fsa_cause; fsa_dump_actions(fsa_data->actions, "\tadded back"); crm_debug("FSA input: State=%s\tCause=%s" "\tInput=%s\tOrigin=%s()", fsa_state2string(cur_state), fsa_cause2string(fsa_data->fsa_cause), fsa_input2string(fsa_data->fsa_input), fsa_data->where); #ifdef DOT_FSA_ACTIONS fprintf(dot_strm, "\t// FSA input: State=%s\tCause=%s" "\tInput=%s\tOrigin=%s()\n", fsa_state2string(cur_state), fsa_cause2string(fsa_data->fsa_cause), fsa_input2string(fsa_data->fsa_input), fsa_data->where); fflush(dot_strm); #endif } else if(fsa_data == NULL) { crm_malloc(fsa_data, sizeof(fsa_data_t)); fsa_data->fsa_input = I_NULL; fsa_data->fsa_cause = cause; fsa_data->actions = A_NOTHING; fsa_data->where = crm_strdup("s_crmd_fsa (enter)"); fsa_data->data = NULL; if(fsa_data->where == NULL) { crm_crit("Out of memory"); exit(1); } } /* update input variables */ cur_input = next_input; if(cur_input != I_NULL) { /* record the most recent non I_NULL input */ crm_devel("Updating last_input to %s", fsa_input2string(cur_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); fsa_dump_actions(new_actions, "\tscheduled"); #endif actions |= new_actions; } if(fsa_data == NULL) { crm_err("No input for FSA.... terminating"); exit(1); } #ifdef FSA_TRACE crm_verbose("FSA while loop:\tState: %s, Cause: %s," " Input: %s, Origin=%s", fsa_state2string(cur_state), fsa_cause2string(fsa_data->fsa_cause), fsa_input2string(fsa_data->fsa_input), fsa_data->where); #endif /* 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, cur_input, fsa_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 */ /* get out of here NOW! before anything worse happens */ IF_FSA_ACTION(A_EXIT_1, do_exit) /* essential start tasks */ else IF_FSA_ACTION(A_HA_CONNECT, do_ha_control) 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) /* sub-system start/connect */ 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_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) /* Timers */ else IF_FSA_ACTION(O_DC_TIMER_RESTART, do_timer_control) else IF_FSA_ACTION(A_DC_TIMER_STOP, do_timer_control) else IF_FSA_ACTION(A_DC_TIMER_START, do_timer_control) else IF_FSA_ACTION(A_INTEGRATE_TIMER_STOP, do_timer_control) else IF_FSA_ACTION(A_INTEGRATE_TIMER_START, do_timer_control) else IF_FSA_ACTION(A_FINALIZE_TIMER_STOP, do_timer_control) else IF_FSA_ACTION(A_FINALIZE_TIMER_START, do_timer_control) /* * Highest priority actions */ 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_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_ELECTION_COUNT, do_election_count_vote) /* * "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) else IF_FSA_ACTION(A_STARTED, do_started) /* * 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_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) /* * 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_DC_JOIN_FINALIZE, do_dc_join_finalize) 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_CL_JOIN_ANNOUNCE, do_cl_join_announce) /* sub-system stop */ else IF_FSA_ACTION(A_DC_RELEASED, do_dc_release) 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_CCM_DISCONNECT, do_ccm_control) else IF_FSA_ACTION(A_SHUTDOWN, do_shutdown) else IF_FSA_ACTION(A_LRM_DISCONNECT, do_lrm_control) else IF_FSA_ACTION(A_HA_DISCONNECT, do_ha_control) else IF_FSA_ACTION(A_CIB_STOP, do_cib_control) 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_) */ /* Error checking and reporting */ else if(cur_input != I_NULL && 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 && actions == A_NOTHING) { #ifdef FSA_TRACE crm_info("Nothing left to do..."); fsa_dump_actions(actions, "still here"); #endif break; } else { crm_err("Action %s (0x%llx) not supported ", fsa_action2string(actions), actions); next_input = I_ERROR; } } #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; delete_fsa_input(fsa_data); 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, fsa_data_t *msg_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_DC_HEARTBEAT && cur_state != S_NOT_DC){ fprintf(dot_strm, "\t\"%s\" -> \"%s\" [ label=\"%s\" cause=%s origin=%s ] // %s", state_from, state_to, input, fsa_cause2string(cause), msg_data->where, asctime(localtime(&now))); fflush(dot_strm); } crm_info("State transition \"%s\" -> \"%s\"" " [ input=%s cause=%s origin=%s %s ]", state_from, state_to, input, fsa_cause2string(cause), msg_data->where, asctime(localtime(&now))); - if(next_state != S_ELECTION) { + if(next_state != S_ELECTION && election_timeout != NULL) { stopTimer(election_timeout); /* } else { */ /* startTimer(election_timeout); */ } if(is_set(fsa_input_register, R_SHUTDOWN)){ set_bit_inplace(tmp, A_DC_TIMER_STOP); } else if(next_state == S_PENDING || next_state == S_NOT_DC) { set_bit_inplace(tmp, A_DC_TIMER_START); /* } else we are the DC and dont want to shut down { */ } switch(next_state) { case S_PENDING: case S_ELECTION: crm_info("Resetting our DC to NULL on election"); crm_free(fsa_our_dc); fsa_our_dc = NULL; 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"); set_bit_inplace(tmp, A_SHUTDOWN_REQ); } if(fsa_our_dc == NULL) { crm_err("Reached S_NOT_DC without a DC" " being recorded"); } break; case S_RECOVERY: clear_recovery_bit = FALSE; break; case S_INTEGRATION: initialize_join(TRUE); set_bit_inplace(tmp, A_INTEGRATE_TIMER_START); set_bit_inplace(tmp, A_FINALIZE_TIMER_STOP); break; case S_FINALIZE_JOIN: set_bit_inplace(tmp, A_INTEGRATE_TIMER_STOP); set_bit_inplace(tmp, A_FINALIZE_TIMER_START); if(cause != C_FSA_INTERNAL) { crm_warn("Progressed to state %s after %s", fsa_state2string(cur_state), fsa_cause2string(cause)); } if(g_hash_table_size(join_requests) != fsa_membership_copy->members_size) { crm_warn("Only %d (of %d) cluster nodes " "responded to the join offer.", g_hash_table_size(join_requests), fsa_membership_copy->members_size); } else { crm_info("All %d clusters nodes " "responded to the join offer.", fsa_membership_copy->members_size); } break; case S_POLICY_ENGINE: initialize_join(FALSE); set_bit_inplace(tmp, A_FINALIZE_TIMER_STOP); if(cause != C_FSA_INTERNAL) { crm_warn("Progressed to state %s after %s", fsa_state2string(cur_state), fsa_cause2string(cause)); } if(g_hash_table_size(confirmed_nodes) == fsa_membership_copy->members_size) { crm_info("All %d clusters nodes are" " eligable to run resources.", fsa_membership_copy->members_size); } else if(g_hash_table_size(confirmed_nodes) == num_join_invites) { crm_warn("All %d (%d total) cluster " "nodes are eligable to run resources", g_hash_table_size(confirmed_nodes), fsa_membership_copy->members_size); } else { crm_warn("Only %d of %d (%d total) cluster " "nodes are eligable to run resources", num_join_invites, g_hash_table_size(confirmed_nodes), fsa_membership_copy->members_size); } break; case S_IDLE: dump_rsc_info(); break; 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); } if(cur_state == S_STOPPING) { clear_bit_inplace( actions, A_CCM_CONNECT|A_STARTED|A_LRM_CONNECT| A_HA_CONNECT|A_CIB_START); } return actions; } void dump_rsc_info(void) { - xmlNodePtr local_cib = get_cib_copy(); + xmlNodePtr local_cib = get_cib_copy(fsa_cib_conn); 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; */ /* } */ if(safe_str_neq(op_status, "-1")) { 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); } else { crm_warn("Resource state: %s %s " "[pending %s] on %s", rsc_id, rsc_state, last_op, node_id); } ); ); } diff --git a/crm/crmd/join_client.c b/crm/crmd/join_client.c index ab39d2e65e..ffd480058d 100644 --- a/crm/crmd/join_client.c +++ b/crm/crmd/join_client.c @@ -1,192 +1,192 @@ /* * 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 reannounce_count = 0; /* 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, fsa_data_t *msg_data) { xmlNodePtr msg = (xmlNodePtr)msg_data->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) { crm_info("Set DC to %s", hb_from); fsa_our_dc = crm_strdup(hb_from); } else if(safe_str_eq(hb_from, fsa_our_dc)) { reannounce_count++; if(fsa_join_reannouce > 0 && reannounce_count < fsa_join_reannouce) { crm_warn("Already announced to %s", hb_from); return I_NULL; } crm_warn("Re-announcing ourselves to %s (%d times)", hb_from, reannounce_count); } 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 */ crm_warn("Resetting our DC to NULL after DC_HB" " from unrecognised node."); crm_free(fsa_our_dc); fsa_our_dc = NULL; return I_NULL; /* for now, wait for the DC's * to settle down */ } reannounce_count = 0; /* send as a broadcast */ send_request(NULL, NULL, CRM_OP_ANNOUNCE, NULL, 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, fsa_data_t *msg_data) { xmlNodePtr tmp1; xmlNodePtr welcome = (xmlNodePtr)msg_data->data; const char *welcome_from = xmlGetProp(welcome, XML_ATTR_HOSTFROM); #if 0 if(we are sick) { log error ; /* save the request for later? */ return I_NULL; } #endif if(fsa_our_dc == NULL) { crm_info("Set DC to %s", welcome_from); fsa_our_dc = crm_strdup(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(); + tmp1 = cib_get_generation(fsa_cib_conn); 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, fsa_data_t *msg_data) { gboolean was_nack = TRUE; xmlNodePtr welcome = (xmlNodePtr)msg_data->data; xmlNodePtr tmp1 = find_xml_node(welcome, XML_TAG_OPTIONS); const char *ack_nack = xmlGetProp(tmp1, CRM_OP_JOINACK); const char *welcome_from = xmlGetProp(welcome, XML_ATTR_HOSTFROM); /* calculate if it was an ack or a nack */ if(safe_str_eq(ack_nack, XML_BOOLEAN_TRUE)) { was_nack = FALSE; } 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) { crm_debug("Sending local LRM status"); send_ha_reply(fsa_cluster_conn, welcome, tmp1); free_xml(tmp1); } else { crm_err("Could send our LRM state to the DC"); return I_FAIL; } register_fsa_input(cause, I_NOT_DC, NULL); return I_NULL; } diff --git a/crm/crmd/join_dc.c b/crm/crmd/join_dc.c index cb418b81b4..ee837c92ca 100644 --- a/crm/crmd/join_dc.c +++ b/crm/crmd/join_dc.c @@ -1,530 +1,525 @@ /* * 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_offers = NULL; GHashTable *join_requests = NULL; GHashTable *confirmed_nodes = NULL; xmlNodePtr our_generation = NULL; const char *max_generation_from = NULL; void initialize_join(gboolean before); void finalize_join_for(gpointer key, gpointer value, gpointer user_data); void join_send_offer(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, fsa_data_t *msg_data) { /* reset everyones status back to down or in_ccm in the CIB */ xmlNodePtr update = NULL; - xmlNodePtr cib_copy = get_cib_copy(); + xmlNodePtr cib_copy = get_cib_copy(fsa_cib_conn); xmlNodePtr tmp1 = get_object_root(XML_CIB_TAG_STATUS, cib_copy); xmlNodePtr tmp2 = NULL; /* 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, NULL, XML_BOOLEAN_NO, NULL, CRMD_JOINSTATE_PENDING, NULL); 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); #if 0 /* 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); #else crm_debug("Offering membership to %d clients", fsa_membership_copy->members_size); g_hash_table_foreach(fsa_membership_copy->members, join_send_offer, NULL); #endif /* 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("Not expecting any join acks"); register_fsa_input(C_FSA_INTERNAL, I_INTEGRATED, NULL); return I_NULL; } /* 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_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, fsa_data_t *msg_data) { gpointer a_node = NULL; xmlNodePtr welcome = NULL; const char *join_to = NULL; if(msg_data->data == NULL) { crm_err("Attempt to send welcome message " "without a message to reply to!"); return I_NULL; } welcome = (xmlNodePtr)msg_data->data; join_to = xmlGetProp(welcome, XML_ATTR_HOSTFROM); a_node = g_hash_table_lookup(join_requests, join_to); if(a_node != NULL && (cur_state == S_INTEGRATION || cur_state == S_FINALIZE_JOIN)) { /* note: it _is_ possible that a node will have been * sick or starting up when the original offer was made. * however, it will either re-announce itself in due course * _or_ we can re-store the original offer on the client. */ crm_warn("Already offered membership to %s... discarding", join_to); /* Make sure we end up in the correct state again */ if(g_hash_table_size(join_requests) >= fsa_membership_copy->members_size) { crm_info("False alarm, returning to %s", fsa_state2string(S_FINALIZE_JOIN)); register_fsa_input(C_FSA_INTERNAL, I_INTEGRATED, NULL); return I_NULL; } crm_debug("Still waiting on %d outstanding join acks", fsa_membership_copy->members_size - g_hash_table_size(join_requests)); } else { oc_node_t member; crm_debug("Processing annouce request from %s in state %s", join_to, fsa_state2string(cur_state)); member.node_uname = crm_strdup(join_to); join_send_offer(NULL, &member, NULL); crm_free(member.node_uname); /* this was a genuine join request, cancel any existing * transition and invoke the PE */ register_fsa_input_w_actions( msg_data->fsa_cause, I_NULL, NULL, A_TE_CANCEL); } 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, fsa_data_t *msg_data) { xmlNodePtr generation; xmlNodePtr join_ack = (xmlNodePtr)msg_data->data; const char *ack_nack = CRMD_JOINSTATE_MEMBER; 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); crm_debug("Processing req from %s", join_from); if(join_node != NULL) { is_a_member = TRUE; } generation = find_xml_node(join_ack, "generation_tuple"); - if(compare_cib_generation(our_generation, generation) < 0) { + if(cib_compare_generation(our_generation, generation) < 0) { clear_bit_inplace(fsa_input_register, R_HAVE_CIB); crm_debug("%s has a better generation number than us", join_from); crm_xml_debug(our_generation, "Our generation"); crm_xml_debug(generation, "Their generation"); max_generation_from = join_from; } crm_debug("Welcoming node %s after ACK (ref %s)", join_from, ref); if(is_a_member == FALSE) { /* nack them now so they are not counted towards the * expected responses */ char *local_from = crm_strdup(join_from); char *local_down = crm_strdup(CRMD_JOINSTATE_DOWN); crm_err("Node %s is not known to us (ref %s)", join_from, ref); finalize_join_for(local_from, local_down, NULL); crm_free(local_from); crm_free(local_down); return I_FAIL; } else if(/* some reason */ 0) { /* NACK this client */ ack_nack = CRMD_JOINSTATE_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)); if(g_hash_table_size(join_requests) >= fsa_membership_copy->members_size) { crm_info("That was the last outstanding join ack"); register_fsa_input(C_FSA_INTERNAL, I_INTEGRATED, NULL); return I_NULL; } /* dont waste time by invoking the PE yet; */ crm_debug("Still waiting on %d (of %d) outstanding join acks", fsa_membership_copy->members_size - g_hash_table_size(join_requests), fsa_membership_copy->members_size); 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, fsa_data_t *msg_data) { if(max_generation_from == NULL) { crm_warn("There is no CIB to get..." " how did R_HAVE_CIB get unset?"); set_bit_inplace(fsa_input_register, R_HAVE_CIB); } if(! is_set(fsa_input_register, R_HAVE_CIB)) { - if(is_set(fsa_input_register, R_CIB_ASKED)) { - crm_info("Waiting for the CIB from %s", - crm_str(max_generation_from)); - crmd_fsa_stall(); - return I_NULL; - } - - set_bit_inplace(fsa_input_register, R_CIB_ASKED); - /* ask for the agreed best CIB */ + enum cib_errors rc = cib_ok; crm_info("Asking %s for its copy of the CIB", crm_str(max_generation_from)); - - send_request(NULL, NULL, CRM_OP_RETRIVE_CIB, - max_generation_from, CRM_SYSTEM_CRMD, NULL); - - crmd_fsa_stall(); - return I_NULL; - } + rc = fsa_cib_conn->cmds->sync_from( + fsa_cib_conn, max_generation_from, NULL, cib_sync_call); + if(rc != cib_ok) { + return I_FAIL; + } + } + + fsa_cib_conn->cmds->bump_epoch( + fsa_cib_conn, cib_scope_local|cib_sync_call|cib_discard_reply); + fsa_cib_conn->cmds->sync(fsa_cib_conn, NULL, cib_sync_call); + num_join_invites = 0; crm_debug("Notifying %d clients of join results", g_hash_table_size(join_requests)); g_hash_table_foreach(join_requests, finalize_join_for, NULL); if(num_join_invites <= g_hash_table_size(confirmed_nodes)) { crm_info("Not expecting any join confirmations"); register_fsa_input(C_FSA_INTERNAL, I_FINALIZED, NULL); return I_NULL; } /* 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_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, fsa_data_t *msg_data) { /* now update them to "member" */ xmlNodePtr tmp1 = NULL, update = NULL; xmlNodePtr join_ack = (xmlNodePtr)msg_data->data; const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM); const char *join_state = NULL; crm_debug("Processing ack from %s", join_from); join_state = (const char *) g_hash_table_lookup(join_requests, join_from); if(join_state == NULL) { crm_err("Join not in progress: ignoring join from %s", join_from); return I_FAIL; } else if(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, ACTIVESTATUS, NULL, ONLINESTATUS, join_state, 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); + update_local_cib(tmp1, TRUE); - register_fsa_input(cause, I_CIB_OP, msg_data->data); + free_xml(tmp1); if(num_join_invites <= g_hash_table_size(confirmed_nodes)) { crm_info("That was the last outstanding join confirmation"); register_fsa_input_later(C_FSA_INTERNAL, I_FINALIZED, NULL); return I_NULL; } /* 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_NULL; } void finalize_join_for(gpointer key, gpointer value, gpointer user_data) { xmlNodePtr tmp1 = NULL; xmlNodePtr tmp2 = NULL; xmlNodePtr cib_copy = NULL; xmlNodePtr options = NULL; const char *join_to = NULL; const char *join_state = NULL; if(key == NULL || value == NULL) { return; } options = create_xml_node(NULL, XML_TAG_OPTIONS); join_to = (const char *)key; join_state = (const char *)value; /* make sure the node exists in the config section */ create_node_entry(join_to, join_to, CRMD_JOINSTATE_MEMBER); /* perhaps we shouldnt special case this... */ if(safe_str_eq(join_to, fsa_our_uname)) { /* mark ourselves confirmed */ g_hash_table_insert(confirmed_nodes, crm_strdup(fsa_our_uname), crm_strdup(CRMD_JOINSTATE_MEMBER)); /* make sure our cluster state is set correctly */ tmp1 = create_node_state( join_to, join_to, ACTIVESTATUS, NULL, ONLINESTATUS, join_state, join_state); if(tmp1 != NULL) { tmp2 = create_cib_fragment(tmp1, NULL); - invoke_local_cib(NULL, tmp2, CRM_OP_UPDATE); + update_local_cib(tmp2, TRUE); free_xml(tmp2); free_xml(tmp1); } else { crm_err("Could not create our node state"); /* TODO: raise an error input */ } /* update our LRM data */ tmp1 = do_lrm_query(TRUE); if(tmp1 != NULL) { - invoke_local_cib(NULL, tmp1, CRM_OP_UPDATE); + update_local_cib(tmp1, TRUE); free_xml(tmp1); } else { crm_err("Could not determin current LRM state"); /* TODO: raise an error input */ } num_join_invites++; crm_info("Completed local cluster membership"); return; } /* create the ack/nack */ if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER)) { num_join_invites++; set_xml_property_copy( options, CRM_OP_JOINACK, XML_BOOLEAN_TRUE); } else { crm_info("NACK'ing join request from %s, state %s", join_to, join_state); set_xml_property_copy( options, CRM_OP_JOINACK, XML_BOOLEAN_FALSE); } /* send the CIB to the node */ - cib_copy = get_cib_copy(); - send_request(NULL, cib_copy, CRM_OP_REPLACE, + cib_copy = get_cib_copy(fsa_cib_conn); + send_request(NULL, cib_copy, CRM_OP_CIB_REPLACE, join_to, CRM_SYSTEM_CRMD, NULL); free_xml(cib_copy); /* send the ack/nack to the node */ send_request(options, NULL, CRM_OP_JOINACK, join_to, CRM_SYSTEM_CRMD, NULL); } void initialize_join(gboolean before) { /* clear out/reset a bunch of stuff */ if(join_offers != NULL) { g_hash_table_destroy(join_offers); } if(join_requests != NULL) { g_hash_table_destroy(join_requests); } if(confirmed_nodes != NULL) { g_hash_table_destroy(confirmed_nodes); } if(before) { free_xml(our_generation); - our_generation = cib_get_generation(); + our_generation = cib_get_generation(fsa_cib_conn); max_generation_from = NULL; set_bit_inplace(fsa_input_register, R_HAVE_CIB); clear_bit_inplace(fsa_input_register, R_CIB_ASKED); } join_offers = g_hash_table_new(&g_str_hash, &g_str_equal); join_requests = g_hash_table_new(&g_str_hash, &g_str_equal); confirmed_nodes = 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)); } void join_send_offer(gpointer key, gpointer value, gpointer user_data) { const char *join_to = NULL; const oc_node_t *member = (const oc_node_t*)value; crm_debug("Sending %s offer", CRM_OP_WELCOME); if(member != NULL) { join_to = member->node_uname; } if(join_to == NULL) { crm_err("No recipient for welcome message"); } else if(safe_str_eq(join_to, fsa_our_uname)) { crm_debug("Skipping %s msg for ourselves (%s)", CRM_OP_WELCOME, join_to); } else { /* 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); g_hash_table_insert(join_offers, crm_strdup(join_to), crm_strdup(CRMD_JOINSTATE_PENDING)); } } diff --git a/crm/crmd/lrm.c b/crm/crmd/lrm.c index cd6faaa412..0ea63bf5a8 100644 --- a/crm/crmd/lrm.c +++ b/crm/crmd/lrm.c @@ -1,895 +1,907 @@ /* * 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 #include gboolean stop_all_resources(void); 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; int num_lrm_register_fails = 0; int max_lrm_register_fails = 30; const char *rsc_path[] = { "msg_data", "rsc_op", "resource", "instance_attributes", "rsc_parameters" }; enum crmd_rscstate { crmd_rscstate_NULL, crmd_rscstate_START, crmd_rscstate_START_PENDING, crmd_rscstate_START_OK, crmd_rscstate_START_FAIL, crmd_rscstate_STOP, crmd_rscstate_STOP_PENDING, crmd_rscstate_STOP_OK, crmd_rscstate_STOP_FAIL, crmd_rscstate_MON, crmd_rscstate_MON_PENDING, crmd_rscstate_MON_OK, crmd_rscstate_MON_FAIL, crmd_rscstate_GENERIC_PENDING, crmd_rscstate_GENERIC_OK, crmd_rscstate_GENERIC_FAIL }; +void free_lrm_op(lrm_op_t *op); const char *crmd_rscstate2string(enum crmd_rscstate state); const char * crmd_rscstate2string(enum crmd_rscstate state) { switch(state) { case crmd_rscstate_NULL: return NULL; case crmd_rscstate_START: return CRMD_RSCSTATE_START; case crmd_rscstate_START_PENDING: return CRMD_RSCSTATE_START_PENDING; case crmd_rscstate_START_OK: return CRMD_RSCSTATE_START_OK; case crmd_rscstate_START_FAIL: return CRMD_RSCSTATE_START_FAIL; case crmd_rscstate_STOP: return CRMD_RSCSTATE_STOP; case crmd_rscstate_STOP_PENDING: return CRMD_RSCSTATE_STOP_PENDING; case crmd_rscstate_STOP_OK: return CRMD_RSCSTATE_STOP_OK; case crmd_rscstate_STOP_FAIL: return CRMD_RSCSTATE_STOP_FAIL; case crmd_rscstate_MON: return CRMD_RSCSTATE_MON; case crmd_rscstate_MON_PENDING: return CRMD_RSCSTATE_MON_PENDING; case crmd_rscstate_MON_OK: return CRMD_RSCSTATE_MON_OK; case crmd_rscstate_MON_FAIL: return CRMD_RSCSTATE_MON_FAIL; case crmd_rscstate_GENERIC_PENDING: return CRMD_RSCSTATE_GENERIC_PENDING; case crmd_rscstate_GENERIC_OK: return CRMD_RSCSTATE_GENERIC_OK; case crmd_rscstate_GENERIC_FAIL: return CRMD_RSCSTATE_GENERIC_FAIL; } return ""; } /* 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, fsa_data_t *msg_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) { if(++num_lrm_register_fails < max_lrm_register_fails) { crm_warn("Failed to sign on to the LRM %d" " (%d max) times", num_lrm_register_fails, max_lrm_register_fails); startTimer(wait_timer); crmd_fsa_stall(); return I_NULL; } else { crm_err("Failed to sign on to the LRM %d" " (max) times", num_lrm_register_fails); 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_connection_destroy); set_bit_inplace(fsa_input_register, R_LRM_CONNECTED); } 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) { 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); 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 stop_all_resources(void) { GList *op_list = NULL; GList *lrm_list = NULL; state_flag_t cur_state = 0; const char *this_op = NULL; lrm_list = fsa_lrm_conn->lrm_ops->get_all_rscs(fsa_lrm_conn); slist_iter( rid, char, lrm_list, lpc, /* GHashTable* params; */ lrm_rsc_t *the_rsc = fsa_lrm_conn->lrm_ops->get_rsc(fsa_lrm_conn, rid); crm_info("Processing lrm_rsc_t entry %s", rid); if(the_rsc == NULL) { crm_err("NULL resource returned from the LRM"); continue; } 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(safe_str_neq(this_op, CRMD_RSCSTATE_STOP)){ do_lrm_rsc_op(the_rsc, the_rsc->id, CRMD_RSCSTATE_STOP, NULL); } break; ); ); return TRUE; } gboolean build_active_RAs(xmlNodePtr rsc_list) { 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); if(is_replace) { set_xml_property_copy(xml_state, "replace", XML_CIB_TAG_LRM); } 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); crm_xml_debug(xml_state, "Current state of the LRM"); return xml_result; } /* 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, fsa_data_t *msg_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; msg = (xmlNodePtr)msg_data->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 op_result = HA_OK; - int monitor_call_id = 0; - int action_timeout = 0; + int call_id = 0; + int action_timeout = 0; const char *class = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, "class", TRUE); const char *type = get_xml_attr_nested( msg, rsc_path, DIMOF(rsc_path) -2, XML_ATTR_TYPE, TRUE); const char *timeout = get_xml_attr_nested( - msg, rsc_path, DIMOF(rsc_path) -2, "timeout", TRUE); + msg, rsc_path, DIMOF(rsc_path) -2, "timeout", FALSE); 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, class, type, 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; } if(timeout) { action_timeout = atoi(timeout); if(action_timeout < 0) { action_timeout = 0; } } + /* stop the monitor before stopping the resource */ + if(safe_str_eq(operation, CRMD_RSCSTATE_STOP)) { + gpointer foo = g_hash_table_lookup(monitors, rsc->id); + call_id = GPOINTER_TO_INT(foo); + + if(call_id > 0) { + crm_debug("Stopping status op for %s", rsc->id); + rsc->ops->cancel_op(rsc, call_id); + g_hash_table_remove(monitors, rsc->id); + /* TODO: Clean up key */ + + } else { + crm_warn("No monitor operation found for %s", rsc->id); + /* TODO: we probably need to look up the LRM to find it */ + } + } + /* 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); + crm_malloc(op, sizeof(lrm_op_t)); + op->op_type = crm_strdup(operation); op->params = xml2list(msg, rsc_path, DIMOF(rsc_path)); op->timeout = action_timeout; 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); } op->user_data_len = 1+strlen(op->user_data); - op_result = rsc->ops->perform_op(rsc, op); - crm_free(op->user_data); + call_id = rsc->ops->perform_op(rsc, op); + free_lrm_op(op); - if(op_result != EXECRA_OK) { - crm_err("Operation %s on %s failed with code: %d", - operation, rid, op_result); + if(call_id <= 0) { + crm_err("Operation %s on %s failed", operation, rid); return I_FAIL; } 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); + crm_malloc(op, sizeof(lrm_op_t)); + op->op_type = crm_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; op->user_data_len = 1+strlen(op->user_data); - monitor_call_id = rsc->ops->perform_op(rsc, op); - crm_free(op->user_data); + call_id = rsc->ops->perform_op(rsc, op); + free_lrm_op(op); - if (monitor_call_id > 0) { + if (call_id > 0) { crm_debug("Adding monitor op for %s", rsc->id); g_hash_table_insert( monitors, strdup(rsc->id), - GINT_TO_POINTER(monitor_call_id)); + GINT_TO_POINTER(call_id)); } else { crm_err("Monitor op for %s did not have a call id", rsc->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_debug("Stopping status op for %s", rsc->id); - rsc->ops->cancel_op(rsc, monitor_call_id); - g_hash_table_remove(monitors, rsc->id); - /* TODO: Clean up key */ - - } else { - crm_warn("No monitor operation found for %s", rsc->id); - } } return I_NULL; } +void +free_lrm_op(lrm_op_t *op) +{ + crm_free(op->user_data); + crm_free(op->op_type); + crm_free(op); +} + + GHashTable * xml2list(xmlNodePtr parent, const char**attr_path, int depth) { xmlNodePtr node_iter = NULL; xmlNodePtr nvpair_list = NULL; GHashTable *nvpair_hash = g_hash_table_new(&g_str_hash, &g_str_equal); if(parent != NULL) { 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, 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, + send_request(NULL, fragment, CRM_OP_CIB_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, fsa_data_t *msg_data) { lrm_op_t* op = NULL; lrm_rsc_t* rsc = NULL; if(msg_data->fsa_cause != C_LRM_OP_CALLBACK) { return I_FAIL; } op = (lrm_op_t*)msg_data->data; rsc = op->rsc; crm_debug("Processing %d event for %s/%s", op->op_status, op->op_type, rsc->id); 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; } 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); 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, + send_request(NULL, update, CRM_OP_CIB_UPDATE, fsa_our_dc, CRM_SYSTEM_DCIB, NULL); } return I_NULL; } diff --git a/crm/crmd/messages.c b/crm/crmd/messages.c index e591f53594..72f6ec3f37 100644 --- a/crm/crmd/messages.c +++ b/crm/crmd/messages.c @@ -1,1216 +1,1196 @@ /* * 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 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 /* debug only, can wrap all it likes */ int last_data_id = 0; void register_fsa_input_adv( enum crmd_fsa_cause cause, enum crmd_fsa_input input, void *data, long long with_actions, gboolean after, const char *raised_from) { int old_len = g_list_length(fsa_message_queue); fsa_data_t *fsa_data = NULL; crm_debug("%s raised FSA input %s (cause=%s) %s data", raised_from,fsa_input2string(input), fsa_cause2string(cause), data?"with":"without"); if(input == I_WAIT_FOR_EVENT) { do_fsa_stall = TRUE; /* zero out the action register but make sure its added back later */ /* with_actions |= fsa_actions; */ /* fsa_actions = A_NOTHING; */ crm_debug("Stalling the FSA pending further input"); } if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */){ /* no point doing anything */ return; } crm_malloc(fsa_data, sizeof(fsa_data_t)); fsa_data->id = ++last_data_id; fsa_data->fsa_input = input; fsa_data->fsa_cause = cause; fsa_data->where = raised_from; fsa_data->data = NULL; fsa_data->actions = with_actions; if(with_actions != A_NOTHING) { crm_debug("Adding actions %.16llx to input", with_actions); } if(data != NULL) { switch(cause) { case C_FSA_INTERNAL: case C_CRMD_STATUS_CALLBACK: case C_IPC_MESSAGE: case C_HA_MESSAGE: crm_debug("Copying %s data from %s as XML", fsa_cause2string(cause), raised_from); fsa_data->data = copy_xml_node_recursive(data); break; case C_LRM_OP_CALLBACK: crm_debug("Copying %s data from %s as lrm_op_t", fsa_cause2string(cause), raised_from); fsa_data->data = copy_lrm_op((lrm_op_t*)data); break; case C_CCM_CALLBACK: crm_debug("Copying %s data from %s as CCM data", fsa_cause2string(cause), raised_from); fsa_data->data = copy_ccm_data(data); break; case C_SUBSYSTEM_CONNECT: case C_LRM_MONITOR_CALLBACK: case C_TIMER_POPPED: case C_SHUTDOWN: case C_HEARTBEAT_FAILED: case C_HA_DISCONNECT: case C_ILLEGAL: case C_UNKNOWN: case C_STARTUP: crm_err("Copying %s data (from %s)" " not yet implemented", fsa_cause2string(cause), raised_from); exit(1); break; } crm_trace("%s data copied", fsa_cause2string(fsa_data->fsa_cause)); } /* make sure to free it properly later */ if(after) { fsa_message_queue = g_list_append( fsa_message_queue, fsa_data); } else { fsa_message_queue = g_list_prepend( fsa_message_queue, fsa_data); } 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"); } } void delete_fsa_input(fsa_data_t *fsa_data) { lrm_op_t *op = NULL; struct crmd_ccm_data_s *ccm_input = NULL; if(fsa_data == NULL) { return; } crm_trace("About to free %s data", fsa_cause2string(fsa_data->fsa_cause)); if(fsa_data->data != NULL) { switch(fsa_data->fsa_cause) { case C_FSA_INTERNAL: case C_CRMD_STATUS_CALLBACK: case C_IPC_MESSAGE: case C_HA_MESSAGE: free_xml(fsa_data->data); break; case C_LRM_OP_CALLBACK: op = (lrm_op_t*)fsa_data->data; crm_free(op->rsc->id); crm_free(op->rsc->type); crm_free(op->rsc->class); crm_free(op->rsc->provider); crm_free(op->rsc); -/* crm_free(op->user_data); */ + crm_free(op->user_data); crm_free(op->output); crm_free(op->rsc_id); crm_free(op->app_name); crm_free(op); break; case C_CCM_CALLBACK: ccm_input = (struct crmd_ccm_data_s *) fsa_data->data; crm_free(ccm_input->oc); crm_free(ccm_input); break; case C_LRM_MONITOR_CALLBACK: case C_TIMER_POPPED: case C_SHUTDOWN: case C_HEARTBEAT_FAILED: case C_SUBSYSTEM_CONNECT: case C_HA_DISCONNECT: case C_ILLEGAL: case C_UNKNOWN: case C_STARTUP: crm_err("Dont know how to free %s data from %s", fsa_cause2string(fsa_data->fsa_cause), fsa_data->where); exit(1); break; } crm_trace("%s data freed", fsa_cause2string(fsa_data->fsa_cause)); } crm_free(fsa_data); } /* returns the current head of the FIFO queue */ GListPtr put_message(fsa_data_t *new_message) { crm_err("Not implemented anymore"); return NULL; } /* returns the next message */ fsa_data_t * get_message(void) { fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0); fsa_message_queue = g_list_remove(fsa_message_queue, message); return message; } gboolean have_wait_message(void) { gboolean ret = FALSE; fsa_data_t* message = g_list_nth_data(fsa_message_queue, 0); if(message->fsa_input == I_WAIT_FOR_EVENT) { ret = TRUE; /* message->fsa_input = I_NULL; */ } return ret; } /* 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, fsa_data_t *msg_data) { register_fsa_input(cause, current_input, msg_data->data); 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, fsa_data_t *msg_data) { enum crmd_fsa_input result = I_NULL; xmlNodePtr xml_message = (xmlNodePtr)(msg_data->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(msg_data->fsa_cause != C_IPC_MESSAGE && msg_data->fsa_cause != C_HA_MESSAGE) { /* dont try and route these */ crm_warn("Can only process HA and IPC messages"); return I_NULL; } if(do_process) { /* try passing the buck first */ crm_trace("Attempting to route message"); routed = relay_message(xml_message, cause==C_IPC_MESSAGE); if(routed == FALSE) { crm_trace("Message wasn't routed... try handling locally"); defer = TRUE; /* calculate defer */ result = handle_message(xml_message); switch(result) { case I_NULL: defer = FALSE; break; case I_DC_HEARTBEAT: defer = FALSE; break; case I_CIB_OP: defer = FALSE; break; /* what else should go here? */ default: crm_trace("Defering local processing of message"); register_fsa_input_later( cause, result, msg_data->data); result = I_NULL; break; } if( ! defer ) { crm_trace("Message processed"); } } else { crm_trace("Message routed..."); } } 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) { register_fsa_input(C_IPC_MESSAGE, I_ROUTER, 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); register_fsa_input_later(C_IPC_MESSAGE, I_ROUTER, 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)); } register_fsa_input( C_IPC_MESSAGE, I_ROUTER, root_xml_node); s_crmd_fsa(C_IPC_MESSAGE); 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", crm_str(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", crm_str(table_key)); if(the_subsystem != NULL) { set_bit_inplace( fsa_input_register, the_subsystem->flag); } s_crmd_fsa(C_SUBSYSTEM_CONNECT); } 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 *host_from= get_xml_attr( stored_msg, NULL, XML_ATTR_HOSTFROM, FALSE); const char *op = get_xml_attr( stored_msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); crm_verbose("Received %s in state %s", op, fsa_state2string(fsa_state)); if(op == NULL) { crm_xml_err(stored_msg, "Bad message"); /*========== common actions ==========*/ } else if(strcmp(op, CRM_OP_VOTE) == 0) { /* count the vote and decide what to do after that */ register_fsa_input_w_actions( C_HA_MESSAGE, I_NULL, stored_msg, A_ELECTION_COUNT); #if 0 /* force the DC into an election mode? * its the old way of doing things but what is gained? */ if(AM_I_DC) { next_input = I_ELECTION; } #endif } 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); #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(fsa_our_dc == NULL) { crm_warn("CRMd discarding request: %s" " (DC: %s, from: %s)", op, crm_str(fsa_our_dc), host_from); crm_xml_warn(stored_msg, "Ignored Request"); - } else if(strcmp(op, CRM_OP_RETRIVE_CIB) == 0) { - next_input = I_CIB_OP; - } else if(strcmp(op, CRM_OP_JOINACK) == 0) { next_input = I_JOIN_RESULT; - } else if(strcmp(op, CRM_OP_REPLACE) == 0) { - next_input = I_CIB_OP; - - } else if(strcmp(op, CRM_OP_UPDATE) == 0) { - next_input = I_CIB_OP; - } else if(strcmp(op, CRM_OP_SHUTDOWN) == 0) { next_input = I_TERMINATE; } else { crm_err("CRMd didnt expect request: %s", op); crm_xml_err(stored_msg, "Bad Request"); } } 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(strcmp(op, CRM_OP_TECOMPLETE) == 0) { /* if(fsa_state == S_TRANSITION_ENGINE) { */ next_input = I_TE_SUCCESS; /* } else { */ /* crm_warn("Op %s is only valid in state %s..." */ /* "We are in (%s)", */ /* op, */ /* fsa_state2string(S_TRANSITION_ENGINE), */ /* fsa_state2string(fsa_state)); */ /* } */ - } 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_ANNOUNCE) == 0) { next_input = I_NODE_JOIN; } 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 (%s) sent to the DC", op); crm_xml_err(stored_msg, "Bad Request"); } } return next_input; } enum crmd_fsa_input handle_response(xmlNodePtr stored_msg) { enum crmd_fsa_input next_input = I_NULL; const char *sys_from = get_xml_attr( stored_msg, NULL, XML_ATTR_SYSFROM, TRUE); const char *msg_ref = get_xml_attr( stored_msg, NULL, XML_ATTR_REFERENCE, TRUE); const char *type = get_xml_attr( stored_msg, NULL, XML_ATTR_MSGTYPE, TRUE); const char *op = get_xml_attr( stored_msg, XML_TAG_OPTIONS, XML_ATTR_OP, TRUE); crm_verbose("Received %s %s in state %s", op, type, fsa_state2string(fsa_state)); if(op == NULL) { crm_xml_err(stored_msg, "Bad message"); } else if(AM_I_DC && strcmp(op, CRM_OP_WELCOME) == 0) { next_input = I_JOIN_REQUEST; } else if(AM_I_DC && strcmp(op, CRM_OP_JOINACK) == 0) { next_input = I_JOIN_RESULT; - } else if(AM_I_DC && strcmp(op, CRM_OP_RETRIVE_CIB) == 0) { - next_input = I_CIB_OP; - } else if(AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) { if(safe_str_eq(msg_ref, fsa_pe_ref)) { next_input = I_PE_SUCCESS; } 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_CIB_CREATE) == 0 + || strcmp(op, CRM_OP_CIB_UPDATE) == 0 + || strcmp(op, CRM_OP_CIB_DELETE) == 0 + || strcmp(op, CRM_OP_CIB_REPLACE) == 0 + || strcmp(op, CRM_OP_CIB_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 response (op=%s) sent to the %s", op, AM_I_DC?"DC":"CRMd"); next_input = I_NULL; } 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); - register_fsa_input(C_IPC_MESSAGE, I_CIB_OP, stored_msg); + fsa_cib_conn->cmds->modify( + fsa_cib_conn, XML_CIB_TAG_STATUS, stored_msg, NULL, + cib_sync_call|cib_discard_reply); + return I_NULL; } 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, T_CRM); ha_msg_add(msg, F_COMMENT, "A CRM 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, crm_str(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; } else 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; fsa_data_t *fsa_data = NULL; 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_err(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 crm_malloc(fsa_data, sizeof(fsa_data_t)); fsa_data->fsa_input = I_MESSAGE; fsa_data->fsa_cause = C_IPC_MESSAGE; fsa_data->data = action; next_input = do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, fsa_data); crm_free(fsa_data); /* 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/pengine.c b/crm/crmd/pengine.c index 5442786d98..9c42233ff6 100644 --- a/crm/crmd/pengine.c +++ b/crm/crmd/pengine.c @@ -1,146 +1,146 @@ /* * 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 30 struct crm_subsystem_s *pe_subsystem = 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, fsa_data_t *msg_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) { crm_info("Stopping %s", this_subsys->name); 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) { sleep(1); if(! CL_PID_EXISTS(this_subsys->pid) || waitpid(this_subsys->pid, &pid_status, WNOHANG) > 0) { this_subsys->pid = -1; break; } } if(this_subsys->pid != -1) { crm_err("Proc %s is still active with pid=%d", this_subsys->name, this_subsys->pid); result = I_FAIL; } } cleanup_subsystem(this_subsys); } if(action & start_actions) { if(cur_state != S_STOPPING) { crm_info("Starting %s", this_subsys->name); 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->name); } } 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, fsa_data_t *msg_data) { xmlNodePtr local_cib = NULL; if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){ crm_info("Waiting for the PE to connect"); crmd_fsa_stall(); return I_NULL; } - local_cib = get_cib_copy(); + local_cib = get_cib_copy(fsa_cib_conn); 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; } diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c index 9400eb6136..6c5315a5c7 100644 --- a/crm/crmd/utils.c +++ b/crm/crmd/utils.c @@ -1,1148 +1,1155 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy); /* A_DC_TIMER_STOP, A_DC_TIMER_START, * A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START * A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START */ enum crmd_fsa_input do_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data) { gboolean timer_op_ok = TRUE; if(action & A_DC_TIMER_STOP) { timer_op_ok = stopTimer(election_trigger); } else if(action & A_FINALIZE_TIMER_STOP) { timer_op_ok = stopTimer(finalization_timer); } else if(action & A_INTEGRATE_TIMER_STOP) { timer_op_ok = stopTimer(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_STOP) { */ /* timer_op_ok = stopTimer(election_timeout); */ } /* dont start a timer that wasnt already running */ if(action & A_DC_TIMER_START && timer_op_ok) { startTimer(election_trigger); } else if(action & A_FINALIZE_TIMER_START) { startTimer(finalization_timer); } else if(action & A_INTEGRATE_TIMER_START) { startTimer(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_START) { */ /* startTimer(election_timeout); */ } return I_NULL; } 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); /* make it _not_ go off again */ if(timer->fsa_input != I_NULL) { register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL); } s_crmd_fsa(C_TIMER_POPPED); return TRUE; } gboolean startTimer(fsa_timer_t *timer) { if((timer->source_id == (guint)-1 || timer->source_id == (guint)-2) && timer->period_ms > 0) { timer->source_id = Gmain_timeout_add(timer->period_ms, timer->callback, (void*)timer); crm_debug("Started %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); } else if(timer->period_ms < 0) { crm_err("Tried to start timer %s with -ve period", fsa_input2string(timer->fsa_input)); } else { crm_debug("Timer %s already running (%d)", fsa_input2string(timer->fsa_input), timer->source_id); return FALSE; } return TRUE; } gboolean stopTimer(fsa_timer_t *timer) { - if(timer->source_id != (guint)-1 && timer->source_id != (guint)-2) { + if(timer == NULL) { + crm_err("Attempted to stop NULL timer"); + return FALSE; + + } else if(timer->source_id != (guint)-1 && timer->source_id != (guint)-2) { crm_devel("Stopping %s timer (%d)", fsa_input2string(timer->fsa_input), timer->source_id); g_source_remove(timer->source_id); timer->source_id = -2; } else { timer->source_id = -2; crm_debug("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("Setting bit\t%.16llx", action); action_list |= action; return action_list; } gboolean is_set(long long action_list, long long action) { /* crm_verbose("Checking bit\t%.16llx", action); */ return ((action_list & action) == action); } gboolean is_set_any(long long action_list, long long action) { /* crm_verbose("Checking bit\t%.16llx", action); */ return ((action_list & action) != 0); } 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_INTEGRATED: inputAsText = "I_INTEGRATED"; break; case I_FINALIZED: inputAsText = "I_FINALIZED"; break; case I_NODE_JOIN: inputAsText = "I_NODE_JOIN"; break; 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_PE_SUCCESS: inputAsText = "I_PE_SUCCESS"; break; case I_ROUTER: inputAsText = "I_ROUTER"; break; case I_SHUTDOWN: inputAsText = "I_SHUTDOWN"; break; case I_STARTUP: inputAsText = "I_STARTUP"; break; case I_TE_SUCCESS: inputAsText = "I_TE_SUCCESS"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; 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_PENDING: inputAsText = "I_PENDING"; 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_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_STARTING: stateAsText = "S_STARTING"; 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_FSA_INTERNAL: causeAsText = "C_FSA_INTERNAL"; 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_INTEGRATE_TIMER_START: actionAsText = "A_INTEGRATE_TIMER_START"; break; case A_INTEGRATE_TIMER_STOP: actionAsText = "A_INTEGRATE_TIMER_STOP"; break; case A_FINALIZE_TIMER_START: actionAsText = "A_FINALIZE_TIMER_START"; break; case A_FINALIZE_TIMER_STOP: actionAsText = "A_FINALIZE_TIMER_STOP"; break; case A_ELECTION_COUNT: actionAsText = "A_ELECTION_COUNT"; break; case A_ELECTION_VOTE: actionAsText = "A_ELECTION_VOTE"; break; 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_DC_JOIN_OFFER_ONE: actionAsText = "A_DC_JOIN_OFFER_ONE"; break; case A_DC_JOIN_PROCESS_REQ: actionAsText = "A_DC_JOIN_PROCESS_REQ"; break; case A_DC_JOIN_PROCESS_ACK: actionAsText = "A_DC_JOIN_PROCESS_ACK"; break; 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 fsa_dump_actions(long long action, const char *text) { if(is_set(action, A_READCONFIG)) { crm_debug("Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text); } if(is_set(action, A_STARTUP)) { crm_debug("Action %.16llx (A_STARTUP) %s", A_STARTUP, text); } if(is_set(action, A_STARTED)) { crm_debug("Action %.16llx (A_STARTED) %s", A_STARTED, text); } if(is_set(action, A_HA_CONNECT)) { crm_debug("Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text); } if(is_set(action, A_HA_DISCONNECT)) { crm_debug("Action %.16llx (A_DISCONNECT) %s", A_HA_DISCONNECT, text); } if(is_set(action, A_LRM_CONNECT)) { crm_debug("Action %.16llx (A_LRM_CONNECT) %s", A_LRM_CONNECT, text); } if(is_set(action, A_LRM_EVENT)) { crm_debug("Action %.16llx (A_LRM_EVENT) %s", A_LRM_EVENT, text); } if(is_set(action, A_LRM_INVOKE)) { crm_debug("Action %.16llx (A_LRM_INVOKE) %s", A_LRM_INVOKE, text); } if(is_set(action, A_LRM_DISCONNECT)) { crm_debug("Action %.16llx (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text); } if(is_set(action, A_DC_TIMER_STOP)) { crm_debug("Action %.16llx (A_DC_TIMER_STOP) %s", A_DC_TIMER_STOP, text); } if(is_set(action, A_DC_TIMER_START)) { crm_debug("Action %.16llx (A_DC_TIMER_START) %s", A_DC_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_START)) { crm_debug("Action %.16llx (A_INTEGRATE_TIMER_START) %s", A_INTEGRATE_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_STOP)) { crm_debug("Action %.16llx (A_INTEGRATE_TIMER_STOP) %s", A_INTEGRATE_TIMER_STOP, text); } if(is_set(action, A_FINALIZE_TIMER_START)) { crm_debug("Action %.16llx (A_FINALIZE_TIMER_START) %s", A_FINALIZE_TIMER_START, text); } if(is_set(action, A_FINALIZE_TIMER_STOP)) { crm_debug("Action %.16llx (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text); } if(is_set(action, A_ELECTION_COUNT)) { crm_debug("Action %.16llx (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text); } if(is_set(action, A_ELECTION_VOTE)) { crm_debug("Action %.16llx (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text); } if(is_set(action, A_CL_JOIN_ANNOUNCE)) { crm_debug("Action %.16llx (A_CL_JOIN_ANNOUNCE) %s", A_CL_JOIN_ANNOUNCE, text); } if(is_set(action, A_CL_JOIN_REQUEST)) { crm_debug("Action %.16llx (A_CL_JOIN_REQUEST) %s", A_CL_JOIN_REQUEST, text); } if(is_set(action, A_CL_JOIN_RESULT)) { crm_debug("Action %.16llx (A_CL_JOIN_RESULT) %s", A_CL_JOIN_RESULT, text); } if(is_set(action, A_DC_JOIN_OFFER_ALL)) { crm_debug("Action %.16llx (A_DC_JOIN_OFFER_ALL) %s", A_DC_JOIN_OFFER_ALL, text); } if(is_set(action, A_DC_JOIN_OFFER_ONE)) { crm_debug("Action %.16llx (A_DC_JOIN_OFFER_ONE) %s", A_DC_JOIN_OFFER_ONE, text); } if(is_set(action, A_DC_JOIN_PROCESS_REQ)) { crm_debug("Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s", A_DC_JOIN_PROCESS_REQ, text); } if(is_set(action, A_DC_JOIN_PROCESS_ACK)) { crm_debug("Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s", A_DC_JOIN_PROCESS_ACK, text); } if(is_set(action, A_DC_JOIN_FINALIZE)) { crm_debug("Action %.16llx (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text); } if(is_set(action, A_MSG_PROCESS)) { crm_debug("Action %.16llx (A_MSG_PROCESS) %s", A_MSG_PROCESS, text); } if(is_set(action, A_MSG_ROUTE)) { crm_debug("Action %.16llx (A_MSG_ROUTE) %s", A_MSG_ROUTE, text); } if(is_set(action, A_MSG_STORE)) { crm_debug("Action %.16llx (A_MSG_STORE) %s", A_MSG_STORE, text); } if(is_set(action, A_RECOVER)) { crm_debug("Action %.16llx (A_RECOVER) %s", A_RECOVER, text); } if(is_set(action, A_DC_RELEASE)) { crm_debug("Action %.16llx (A_DC_RELEASE) %s", A_DC_RELEASE, text); } if(is_set(action, A_DC_RELEASED)) { crm_debug("Action %.16llx (A_DC_RELEASED) %s", A_DC_RELEASED, text); } if(is_set(action, A_DC_TAKEOVER)) { crm_debug("Action %.16llx (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text); } if(is_set(action, A_SHUTDOWN)) { crm_debug("Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text); } if(is_set(action, A_SHUTDOWN_REQ)) { crm_debug("Action %.16llx (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text); } if(is_set(action, A_STOP)) { crm_debug("Action %.16llx (A_STOP ) %s", A_STOP , text); } if(is_set(action, A_EXIT_0)) { crm_debug("Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text); } if(is_set(action, A_EXIT_1)) { crm_debug("Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text); } if(is_set(action, A_CCM_CONNECT)) { crm_debug("Action %.16llx (A_CCM_CONNECT) %s", A_CCM_CONNECT, text); } if(is_set(action, A_CCM_DISCONNECT)) { crm_debug("Action %.16llx (A_CCM_DISCONNECT) %s", A_CCM_DISCONNECT, text); } if(is_set(action, A_CCM_EVENT)) { crm_debug("Action %.16llx (A_CCM_EVENT) %s", A_CCM_EVENT, text); } if(is_set(action, A_CCM_UPDATE_CACHE)) { crm_debug("Action %.16llx (A_CCM_UPDATE_CACHE) %s", A_CCM_UPDATE_CACHE, text); } if(is_set(action, A_CIB_BUMPGEN)) { crm_debug("Action %.16llx (A_CIB_BUMPGEN) %s", A_CIB_BUMPGEN, text); } if(is_set(action, A_CIB_INVOKE)) { crm_debug("Action %.16llx (A_CIB_INVOKE) %s", A_CIB_INVOKE, text); } if(is_set(action, A_CIB_START)) { crm_debug("Action %.16llx (A_CIB_START) %s", A_CIB_START, text); } if(is_set(action, A_CIB_STOP)) { crm_debug("Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text); } if(is_set(action, A_TE_INVOKE)) { crm_debug("Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text); } if(is_set(action, A_TE_START)) { crm_debug("Action %.16llx (A_TE_START) %s", A_TE_START, text); } if(is_set(action, A_TE_STOP)) { crm_debug("Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text); } if(is_set(action, A_TE_CANCEL)) { crm_debug("Action %.16llx (A_TE_CANCEL) %s", A_TE_CANCEL, text); } if(is_set(action, A_TE_COPYTO)) { crm_debug("Action %.16llx (A_TE_COPYTO) %s", A_TE_COPYTO, text); } if(is_set(action, A_PE_INVOKE)) { crm_debug("Action %.16llx (A_PE_INVOKE) %s", A_PE_INVOKE, text); } if(is_set(action, A_PE_START)) { crm_debug("Action %.16llx (A_PE_START) %s", A_PE_START, text); } if(is_set(action, A_PE_STOP)) { crm_debug("Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text); } if(is_set(action, A_NODE_BLOCK)) { crm_debug("Action %.16llx (A_NODE_BLOCK) %s", A_NODE_BLOCK, text); } if(is_set(action, A_UPDATE_NODESTATUS)) { crm_debug("Action %.16llx (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text); } if(is_set(action, A_LOG)) { crm_debug("Action %.16llx (A_LOG ) %s", A_LOG, text); } if(is_set(action, A_ERROR)) { crm_debug("Action %.16llx (A_ERROR ) %s", A_ERROR, text); } if(is_set(action, A_WARN)) { crm_debug("Action %.16llx (A_WARN ) %s", A_WARN, text); } } 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); + /* do not forward this to the TE - required still? */ +/* update_local_cib(tmp2, FALSE); */ + update_local_cib(tmp2, TRUE); free_xml(tmp2); free_xml(tmp1); } xmlNodePtr create_node_state(const char *uuid, const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_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); set_xml_property_copy( node_state, XML_CIB_ATTR_HASTATE, ha_state); set_xml_property_copy( node_state, XML_CIB_ATTR_INCCM, ccm_state); set_xml_property_copy( node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state); set_xml_property_copy( node_state, XML_CIB_ATTR_JOINSTATE, join_state); set_xml_property_copy( node_state, XML_CIB_ATTR_EXPSTATE, exp_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); }/*memory leak*/ /* BEAM BUG - this is not a memory leak */ struct crmd_ccm_data_s * copy_ccm_data(const struct crmd_ccm_data_s *ccm_input) { const oc_ev_membership_t *oc_in = (const oc_ev_membership_t *)ccm_input->oc; struct crmd_ccm_data_s *ccm_input_copy = NULL; crm_malloc(ccm_input_copy, sizeof(struct crmd_ccm_data_s)); ccm_input_copy->oc = copy_ccm_oc_data(oc_in); ccm_input_copy->event = ccm_input->event; return ccm_input_copy; } oc_ev_membership_t * copy_ccm_oc_data(const oc_ev_membership_t *oc_in) { int lpc = 0; int size = 0; int offset = 0; int num_nodes = 0; oc_ev_membership_t *oc_copy = NULL; if(oc_in->m_n_member > 0 && num_nodes < oc_in->m_n_member + oc_in->m_memb_idx) { num_nodes = oc_in->m_n_member + oc_in->m_memb_idx; crm_devel("Updated ccm nodes to %d - 1", num_nodes); } if(oc_in->m_n_in > 0 && num_nodes < oc_in->m_n_in + oc_in->m_in_idx) { num_nodes = oc_in->m_n_in + oc_in->m_in_idx; crm_devel("Updated ccm nodes to %d - 2", num_nodes); } if(oc_in->m_n_out > 0 && num_nodes < oc_in->m_n_out + oc_in->m_out_idx) { num_nodes = oc_in->m_n_out + oc_in->m_out_idx; crm_devel("Updated ccm nodes to %d - 3", num_nodes); } /* why 2*?? * ccm code does it like this so i guess its right... */ size = sizeof(oc_ev_membership_t) + sizeof(int) + 2*num_nodes*sizeof(oc_node_t); crm_devel("Copying %d ccm nodes", num_nodes); crm_malloc(oc_copy, size); oc_copy->m_instance = oc_in->m_instance; oc_copy->m_n_member = oc_in->m_n_member; oc_copy->m_memb_idx = oc_in->m_memb_idx; oc_copy->m_n_out = oc_in->m_n_out; oc_copy->m_out_idx = oc_in->m_out_idx; oc_copy->m_n_in = oc_in->m_n_in; oc_copy->m_in_idx = oc_in->m_in_idx; crm_debug("instance=%d, nodes=%d (idx=%d), new=%d (idx=%d), lost=%d (idx=%d)", oc_in->m_instance, oc_in->m_n_member, oc_in->m_memb_idx, oc_in->m_n_in, oc_in->m_in_idx, oc_in->m_n_out, oc_in->m_out_idx); offset = oc_in->m_memb_idx; for(lpc = 0; lpc < oc_in->m_n_member; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_devel("Copying ccm member node %d", lpc); copy_ccm_node(a_node, a_node_copy); } offset = oc_in->m_in_idx; for(lpc = 0; lpc < oc_in->m_n_in; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_devel("Copying ccm new node %d", lpc); copy_ccm_node(a_node, a_node_copy); } offset = oc_in->m_out_idx; for(lpc = 0; lpc < oc_in->m_n_out; lpc++) { oc_node_t a_node = oc_in->m_array[lpc+offset]; oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]); crm_devel("Copying ccm lost node %d", lpc); copy_ccm_node(a_node, a_node_copy); } return oc_copy; } void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy) { crm_devel("Copying ccm node: id=%d, born=%d, uname=%s", a_node.node_id, a_node.node_born_on, a_node.node_uname); a_node_copy->node_id = a_node.node_id; a_node_copy->node_born_on = a_node.node_born_on; a_node_copy->node_uname = NULL; if(a_node.node_uname != NULL) { a_node_copy->node_uname = crm_strdup(a_node.node_uname); } else { crm_err("Node Id %d had a NULL uname!", a_node.node_id); } crm_devel("Copied ccm node: id=%d, born=%d, uname=%s", a_node_copy->node_id, a_node_copy->node_born_on, a_node_copy->node_uname); } lrm_op_t * copy_lrm_op(const lrm_op_t *op) { lrm_op_t *op_copy = NULL; crm_malloc(op_copy, sizeof(lrm_op_t)); op_copy->op_type = crm_strdup(op->op_type); /* input fields */ /* GHashTable* params; */ op_copy->params = NULL; op_copy->timeout = op->timeout; op_copy->interval = op->interval; op_copy->target_rc = op->target_rc; /* in the CRM, this is always an int */ - op_copy->user_data = op->user_data; - + if(op->user_data != NULL) { + op_copy->user_data = crm_strdup(op->user_data); + } + /* output fields */ op_copy->op_status = op->op_status; op_copy->rc = op->rc; op_copy->call_id = op->call_id; op_copy->output = NULL; if(op->output!= NULL) { op_copy->output = crm_strdup(op->output); } op_copy->rsc_id = crm_strdup(op->rsc_id); op_copy->app_name = crm_strdup(op->app_name); /*please notice the client needs release the memory of rsc.*/ op_copy->rsc = copy_lrm_rsc(op->rsc); if(op_copy->rsc == NULL) { crm_err("Op callback for %s did not contain a resource", op_copy->rsc_id); } return op_copy; } lrm_rsc_t * copy_lrm_rsc(const lrm_rsc_t *rsc) { lrm_rsc_t *rsc_copy = NULL; if(rsc == NULL) { return NULL; } crm_malloc(rsc_copy, sizeof(lrm_rsc_t)); rsc_copy->id = crm_strdup(rsc->id); rsc_copy->type = crm_strdup(rsc->type); rsc_copy->class = NULL; rsc_copy->provider = NULL; if(rsc->class != NULL) { rsc_copy->class = crm_strdup(rsc->class); } if(rsc->provider != NULL) { rsc_copy->provider = crm_strdup(rsc->provider); } /* GHashTable* params; */ rsc_copy->params = NULL; rsc_copy->ops = NULL; return rsc_copy; }