diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c index 3f54dcb2ec..45c858087b 100644 --- a/crm/crmd/callbacks.c +++ b/crm/crmd/callbacks.c @@ -1,553 +1,551 @@ /* * 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"); 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"); 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) { ll_lrm_t *lrm = (ll_lrm_t*)user_data; crm_debug("received callback"); 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; #if 1 while(hb_cluster->llc_ops->msgready(hb_cluster)) { lpc++; /* invoke the callbacks but dont block */ hb_cluster->llc_ops->rcvmsg(hb_cluster, 0); /* empty_callbacks = 0; */ } #else while(hb_cluster->llc_ops->rcvmsg(hb_cluster, 0)) { lpc++; } #endif crm_trace("%d HA messages dispatched", lpc); if (channel && (channel->ch_status == IPC_DISCONNECT)) { crm_crit("Lost connection to heartbeat service."); return FALSE; } #if 0 if(lpc == 0) { /* hey what happened?? */ crm_warn("We were called but no message was ready." " Likely the connection to Heartbeat failed," " check the logs."); if(empty_callbacks++ > MAX_EMPTY_CALLBACKS) { crm_err("%d empty callbacks received..." " considering heartbeat dead", MAX_EMPTY_CALLBACKS); return FALSE; } } #endif 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) { oc_ev_t *ccm_token = (oc_ev_t*)user_data; crm_debug("received callback"); oc_ev_handle_event(ccm_token); return TRUE; } 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) { - set_bit_inplace(fsa_input_register, R_CCM_DATA); - 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); 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 3f09880820..391edc7f0a 100644 --- a/crm/crmd/ccm.c +++ b/crm/crmd/ccm.c @@ -1,652 +1,653 @@ -/* $Id: ccm.c,v 1.41 2004/10/21 18:25:42 andrew Exp $ */ +/* $Id: ccm.c,v 1.42 2004/11/12 16:24:45 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; if(action & A_CCM_DISCONNECT){ oc_ev_unregister(fsa_ev_token); } if(action & A_CCM_CONNECT) { crm_info("Registering with CCM"); oc_ev_register(&fsa_ev_token); crm_info("Setting up CCM callbacks"); oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS, crmd_ccm_msg_callback, NULL); oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/); crm_info("Activating CCM token"); ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd); if (ret){ oc_ev_unregister(fsa_ev_token); if(++num_ccm_register_fails < max_ccm_register_fails) { crm_warn("CCM Activation failed %d (%d max) times", 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); 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); 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; }