diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c index f344b219c5..116b0ed989 100644 --- a/crm/crmd/callbacks.c +++ b/crm/crmd/callbacks.c @@ -1,656 +1,664 @@ /* * 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 GHashTable *crmd_peer_state = NULL; crm_data_t *find_xml_in_hamessage(const HA_Message * msg); void crmd_ha_connection_destroy(gpointer user_data); /* From join_dc... */ extern gboolean check_join_state( enum crmd_fsa_state cur_state, const char *source); /* #define MAX_EMPTY_CALLBACKS 20 */ /* int empty_callbacks = 0; */ #define trigger_fsa(source) crm_debug_3("Triggering FSA: %s", __FUNCTION__); \ G_main_set_trigger(source); gboolean crmd_ha_msg_dispatch(ll_cluster_t *cluster_conn, gpointer user_data) { IPC_Channel *channel = NULL; gboolean stay_connected = TRUE; crm_debug_3("Invoked"); if(cluster_conn != NULL) { channel = cluster_conn->llc_ops->ipcchan(cluster_conn); } CRM_CHECK(cluster_conn != NULL, ;); CRM_CHECK(channel != NULL, ;); if(channel != NULL && IPC_ISRCONN(channel)) { if(cluster_conn->llc_ops->msgready(cluster_conn) == 0) { crm_debug_2("no message ready yet"); } /* invoke the callbacks but dont block */ cluster_conn->llc_ops->rcvmsg(cluster_conn, 0); } if (channel == NULL || channel->ch_status != IPC_CONNECT) { if(is_set(fsa_input_register, R_HA_DISCONNECTED) == FALSE) { crm_crit("Lost connection to heartbeat service."); } else { crm_info("Lost connection to heartbeat service."); } trigger_fsa(fsa_source); stay_connected = FALSE; } return stay_connected; } void crmd_ha_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); if(is_set(fsa_input_register, R_HA_DISCONNECTED)) { /* we signed out, so this is expected */ crm_info("Heartbeat disconnection complete"); return; } crm_crit("Lost connection to heartbeat service!"); register_fsa_input(C_HA_DISCONNECT, I_ERROR, NULL); trigger_fsa(fsa_source); } void crmd_ha_msg_callback(HA_Message * msg, void* private_data) { int level = LOG_DEBUG; ha_msg_input_t *new_input = NULL; oc_node_t *from_node = NULL; const char *from = ha_msg_value(msg, F_ORIG); const char *seq = ha_msg_value(msg, F_SEQ); const char *op = ha_msg_value(msg, F_CRM_TASK); const char *sys_to = ha_msg_value(msg, F_CRM_SYS_TO); const char *sys_from = ha_msg_value(msg, F_CRM_SYS_FROM); CRM_DEV_ASSERT(from != NULL); crm_debug_2("HA[inbound]: %s from %s", op, from); if(fsa_membership_copy == NULL) { crm_debug("Ignoring HA messages until we are" " connected to the CCM (%s op from %s)", op, from); crm_log_message_adv( LOG_MSG, "HA[inbound]: Ignore (No CCM)", msg); return; } from_node = g_hash_table_lookup(fsa_membership_copy->members, from); if(from_node == NULL) { if(safe_str_eq(op, CRM_OP_VOTE)) { level = LOG_WARNING; } else if(AM_I_DC && safe_str_eq(op, CRM_OP_JOIN_ANNOUNCE)) { level = LOG_WARNING; } else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) { level = LOG_WARNING; } crm_log_maybe(level, "Ignoring HA message (op=%s) from %s: not in our" " membership list (size=%d)", op, from, g_hash_table_size(fsa_membership_copy->members)); crm_log_message_adv(LOG_MSG, "HA[inbound]: CCM Discard", msg); } else if(safe_str_eq(sys_to, CRM_SYSTEM_DC) && AM_I_DC == FALSE) { crm_debug_2("Ignoring message for the DC [F_SEQ=%s]", seq); return; } else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) { if(AM_I_DC && safe_str_neq(from, fsa_our_uname)) { crm_err("Another DC detected: %s (op=%s)", from, op); /* make sure the election happens NOW */ level = LOG_WARNING; if(fsa_state != S_ELECTION) { new_input = new_ha_msg_input(msg); register_fsa_error_adv( C_FSA_INTERNAL, I_ELECTION, NULL, new_input, __FUNCTION__); } #if 0 /* still thinking about this one... * could create a timing issue if we dont notice the * election before a new DC is elected. */ } else if(fsa_our_dc != NULL && safe_str_neq(from,fsa_our_dc)){ crm_warn("Ignoring message from wrong DC: %s vs. %s ", from, fsa_our_dc); return; #endif } else { crm_debug_2("Processing DC message from %s [F_SEQ=%s]", from, seq); } } if(new_input == NULL) { crm_log_message_adv(LOG_MSG, "HA[inbound]", msg); new_input = new_ha_msg_input(msg); route_message(C_HA_MESSAGE, new_input); } delete_ha_msg_input(new_input); trigger_fsa(fsa_source); 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; HA_Message *msg = NULL; ha_msg_input_t *new_input = NULL; crmd_client_t *curr_client = (crmd_client_t*)user_data; gboolean stay_connected = TRUE; crm_debug_2("Invoked: %s", curr_client->table_key); while(IPC_ISRCONN(client)) { if(client->ops->is_message_pending(client) == 0) { break; } msg = msgfromIPC_noauth(client); if (msg == NULL) { crm_info("%s: no message this time", curr_client->table_key); continue; } lpc++; new_input = new_ha_msg_input(msg); crm_msg_del(msg); crm_debug_2("Processing msg from %s", curr_client->table_key); crm_log_message_adv(LOG_DEBUG_2, "CRMd[inbound]", new_input->msg); if(crmd_authorize_message(new_input, curr_client)) { route_message(C_IPC_MESSAGE, new_input); } delete_ha_msg_input(new_input); msg = NULL; new_input = NULL; if(client->ch_status != IPC_CONNECT) { break; } } crm_debug_2("Processed %d messages", lpc); if (client->ch_status != IPC_CONNECT) { stay_connected = FALSE; process_client_disconnect(curr_client); } trigger_fsa(fsa_source); return stay_connected; } extern GCHSource *lrm_source; gboolean lrm_dispatch(IPC_Channel *src_not_used, gpointer user_data) { /* ?? src == lrm_channel ?? */ ll_lrm_t *lrm = (ll_lrm_t*)user_data; IPC_Channel *lrm_channel = lrm->lrm_ops->ipcchan(lrm); crm_debug_3("Invoked"); lrm->lrm_ops->rcvmsg(lrm, FALSE); if(lrm_channel->ch_status != IPC_CONNECT) { if(is_set(fsa_input_register, R_LRM_CONNECTED)) { crm_crit("LRM Connection failed"); register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL); clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED); } else { crm_info("LRM Connection disconnected"); } lrm_source = NULL; return FALSE; } return TRUE; } extern gboolean process_lrm_event(lrm_op_t *op); void lrm_op_callback(lrm_op_t* op) { CRM_CHECK(op != NULL, return); process_lrm_event(op); } void crmd_ha_status_callback( const char *node, const char * status, void* private_data) { crm_data_t *update = NULL; crm_notice("Status update: Node %s now has status [%s]",node,status); if(safe_str_eq(status, DEADSTATUS)) { /* this node is taost */ update = create_node_state( node, status, XML_BOOLEAN_NO, OFFLINESTATUS, CRMD_STATE_INACTIVE, NULL, TRUE, __FUNCTION__); - crm_xml_add(update, XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS); - + if(update) { + crm_xml_add(update, XML_CIB_ATTR_REPLACE, + XML_TAG_TRANSIENT_NODEATTRS); + } + } else if(safe_str_eq(status, ACTIVESTATUS)) { update = create_node_state( - node, status, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__); + node, status, NULL, NULL, NULL, NULL, + FALSE, __FUNCTION__); } if(update != NULL) { /* this change should not be broadcast */ fsa_cib_anon_update( XML_CIB_TAG_STATUS, update, cib_inhibit_bcast|cib_scope_local|cib_quorum_override); trigger_fsa(fsa_source); free_xml(update); + + } else { + crm_info("Ping node %s is %s", node, status); } + } void crmd_client_status_callback(const char * node, const char * client, - const char * status, void * private) + const char * status, void * private) { const char *join = NULL; crm_data_t *update = NULL; gboolean clear_shutdown = FALSE; crm_debug_3("Invoked"); if(safe_str_neq(client, CRM_SYSTEM_CRMD)) { return; } if(safe_str_eq(status, JOINSTATUS)){ status = ONLINESTATUS; clear_shutdown = TRUE; } else if(safe_str_eq(status, LEAVESTATUS)){ status = OFFLINESTATUS; join = CRMD_STATE_INACTIVE; /* clear_shutdown = TRUE; */ } set_bit_inplace(fsa_input_register, R_PEER_DATA); g_hash_table_replace( crmd_peer_state, crm_strdup(node), crm_strdup(status)); if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { return; } else if(fsa_state == S_STOPPING) { return; } crm_notice("Status update: Client %s/%s now has status [%s]", node, client, status); if(safe_str_eq(status, ONLINESTATUS)) { /* remove the cached value in case it changed */ crm_info("Uncaching UUID for %s", node); unget_uuid(node); } if(safe_str_eq(node, fsa_our_dc) && safe_str_eq(status, OFFLINESTATUS)){ /* did our DC leave us */ crm_info("Got client status callback - our DC is dead"); register_fsa_input(C_CRMD_STATUS_CALLBACK, I_ELECTION, NULL); } else { crm_debug_3("Got client status callback"); update = create_node_state( node, NULL, NULL, status, join, NULL, clear_shutdown, __FUNCTION__); if(clear_shutdown) { crm_xml_add(update, XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS); } /* it is safe to keep these updates on the local node * each node updates their own CIB */ fsa_cib_anon_update( XML_CIB_TAG_STATUS, update, cib_inhibit_bcast|cib_scope_local|cib_quorum_override); free_xml(update); if(AM_I_DC && safe_str_eq(status, OFFLINESTATUS)) { g_hash_table_remove(confirmed_nodes, node); g_hash_table_remove(finalized_nodes, node); g_hash_table_remove(integrated_nodes, node); g_hash_table_remove(welcomed_nodes, node); check_join_state(fsa_state, __FUNCTION__); } } trigger_fsa(fsa_source); } static void crmd_ipc_connection_destroy(gpointer user_data) { crmd_client_t *client = user_data; if(client == NULL) { crm_debug_4("No client to delete"); return; } if(client->client_source != NULL) { crm_debug_4("Deleting %s (%p) from mainloop", client->uuid, client->client_source); G_main_del_IPC_Channel(client->client_source); client->client_source = NULL; } crm_debug_3("Freeing %s client", client->uuid); crm_free(client->table_key); crm_free(client->sub_sys); crm_free(client->uuid); crm_free(client); return; } gboolean crmd_client_connect(IPC_Channel *client_channel, gpointer user_data) { crm_debug_3("Invoked"); 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_3("Channel connected"); crm_malloc0(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, crmd_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; gboolean was_error = FALSE; crm_debug_3("Invoked"); rc = oc_ev_handle_event(ccm_token); if(rc != 0) { if(is_set(fsa_input_register, R_CCM_DISCONNECTED) == FALSE) { /* we signed out, so this is expected */ register_fsa_input(C_CCM_CALLBACK, I_ERROR, NULL); crm_err("CCM connection appears to have failed: rc=%d.", rc); } was_error = TRUE; } trigger_fsa(fsa_source); return !was_error; } static gboolean fsa_have_quorum = FALSE; void crmd_ccm_msg_callback( oc_ed_t event, void *cookie, size_t size, const void *data) { int instance = -1; gboolean update_cache = FALSE; struct crmd_ccm_data_s *event_data = NULL; const oc_ev_membership_t *membership = data; gboolean update_quorum = FALSE; gboolean trigger_transition = FALSE; crm_debug_3("Invoked"); if(data != NULL) { instance = membership->m_instance; } crm_info("Quorum %s after event=%s (id=%d)", ccm_have_quorum(event)?"(re)attained":"lost", ccm_event_name(event), instance); switch(event) { case OC_EV_MS_NEW_MEMBERSHIP: case OC_EV_MS_INVALID:/* fall through */ update_cache = TRUE; update_quorum = TRUE; break; case OC_EV_MS_NOT_PRIMARY: #if UNTESTED if(AM_I_DC == FALSE) { break; } /* tell the TE to pretend it had completed and stop */ /* side effect: we'll end up in S_IDLE */ register_fsa_action(A_TE_HALT, TRUE); #endif break; case OC_EV_MS_PRIMARY_RESTORED: fsa_membership_copy->id = instance; if(AM_I_DC && need_transition(fsa_state)) { trigger_transition = TRUE; } break; case OC_EV_MS_EVICTED: update_quorum = TRUE; register_fsa_input(C_FSA_INTERNAL, I_STOP, NULL); crm_err("Shutting down after CCM event: %s", ccm_event_name(event)); break; default: crm_err("Unknown CCM event: %d", event); } if(update_quorum && ccm_have_quorum(event) == FALSE) { /* did we just loose quorum? */ if(fsa_have_quorum && need_transition(fsa_state)) { crm_info("Quorum lost: triggering transition (%s)", ccm_event_name(event)); trigger_transition = TRUE; } fsa_have_quorum = FALSE; } else if(update_quorum) { crm_debug_2("Updating quorum after event %s", ccm_event_name(event)); fsa_have_quorum = TRUE; } if(trigger_transition) { crm_debug_2("Scheduling transition after event %s", ccm_event_name(event)); /* make sure that when we query the CIB that it has * the changes that triggered the transition */ switch(event) { case OC_EV_MS_NEW_MEMBERSHIP: case OC_EV_MS_INVALID: case OC_EV_MS_PRIMARY_RESTORED: fsa_membership_copy->id = instance; break; default: break; } if(update_cache == FALSE) { /* a stand-alone transition */ register_fsa_action(A_TE_CANCEL); } } if(update_cache) { crm_debug_2("Updating cache after event %s", ccm_event_name(event)); crm_malloc0(event_data, sizeof(struct crmd_ccm_data_s)); if(event_data == NULL) { return; } event_data->event = event; if(data != NULL) { event_data->oc = copy_ccm_oc_data(data); } register_fsa_input_adv( C_CCM_CALLBACK, I_CCM_EVENT, event_data, trigger_transition?A_TE_CANCEL:A_NOTHING, FALSE, __FUNCTION__); if (event_data->oc) { crm_free(event_data->oc); event_data->oc = NULL; } crm_free(event_data); } oc_ev_callback_done(cookie); return; } void crmd_cib_connection_destroy(gpointer user_data) { crm_debug_3("Invoked"); trigger_fsa(fsa_source); if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) { crm_info("Connection to the CIB terminated..."); return; } /* eventually this will trigger a reconnect, not a shutdown */ crm_err("Connection to the CIB terminated..."); register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL); clear_bit_inplace(fsa_input_register, R_CIB_CONNECTED); return; } longclock_t fsa_start = 0; longclock_t fsa_stop = 0; longclock_t fsa_diff = 0; gboolean crm_fsa_trigger(gpointer user_data) { unsigned int fsa_diff_ms = 0; if(fsa_diff_max_ms > 0) { fsa_start = time_longclock(); } crm_debug_2("Invoked (queue len: %d)", g_list_length(fsa_message_queue)); s_crmd_fsa(C_FSA_INTERNAL); crm_debug_2("Exited (queue len: %d)", g_list_length(fsa_message_queue)); if(fsa_diff_max_ms > 0) { fsa_stop = time_longclock(); fsa_diff = sub_longclock(fsa_stop, fsa_start); fsa_diff_ms = longclockto_ms(fsa_diff); if(fsa_diff_ms > fsa_diff_max_ms) { crm_err("FSA took %dms to complete", fsa_diff_ms); } else if(fsa_diff_ms > fsa_diff_warn_ms) { crm_warn("FSA took %dms to complete", fsa_diff_ms); } } return TRUE; } diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c index 13d6290261..46c3c3496b 100644 --- a/crm/crmd/utils.c +++ b/crm/crmd/utils.c @@ -1,1389 +1,1395 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; enum crmd_fsa_input result = I_NULL; if(action & A_DC_TIMER_STOP) { timer_op_ok = crm_timer_stop(election_trigger); } else if(action & A_FINALIZE_TIMER_STOP) { timer_op_ok = crm_timer_stop(finalization_timer); } else if(action & A_INTEGRATE_TIMER_STOP) { timer_op_ok = crm_timer_stop(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_STOP) { */ /* timer_op_ok = crm_timer_stop(election_timeout); */ } /* dont start a timer that wasnt already running */ if(action & A_DC_TIMER_START && timer_op_ok) { crm_timer_start(election_trigger); if(AM_I_DC) { /* there can be only one */ result = I_ELECTION; } } else if(action & A_FINALIZE_TIMER_START) { crm_timer_start(finalization_timer); } else if(action & A_INTEGRATE_TIMER_START) { crm_timer_start(integration_timer); /* } else if(action & A_ELECTION_TIMEOUT_START) { */ /* crm_timer_start(election_timeout); */ } return I_NULL; } static const char * get_timer_desc(fsa_timer_t *timer) { if(timer == election_trigger) { return "Election Trigger"; } else if(timer == election_timeout) { return "Election Timeout"; } else if(timer == shutdown_escalation_timer) { return "Shutdown Escalation"; } else if(timer == integration_timer) { return "Integration Timer"; } else if(timer == finalization_timer) { return "Finalization Timer"; } else if(timer == wait_timer) { return "Wait Timer"; } else if(timer == recheck_timer) { return "PEngine Recheck Timer"; } return "Unknown Timer"; } gboolean crm_timer_popped(gpointer data) { fsa_timer_t *timer = (fsa_timer_t *)data; if(timer == wait_timer || timer == recheck_timer || timer == finalization_timer || timer == election_trigger) { crm_info("%s (%s) just popped!", get_timer_desc(timer), fsa_input2string(timer->fsa_input)); } else { crm_err("%s (%s) just popped!", get_timer_desc(timer), fsa_input2string(timer->fsa_input)); } if(timer->repeat == FALSE) { crm_timer_stop(timer); /* make it _not_ go off again */ } if(timer->fsa_input == I_INTEGRATED) { register_fsa_input_before( C_TIMER_POPPED, timer->fsa_input, NULL); } else if(timer->fsa_input == I_PE_CALC && fsa_state != S_IDLE) { crm_debug("Discarding %s event in state: %s", fsa_input2string(timer->fsa_input), fsa_state2string(fsa_state)); } else if(timer->fsa_input == I_FINALIZED && fsa_state != S_FINALIZE_JOIN) { crm_debug("Discarding %s event in state: %s", fsa_input2string(timer->fsa_input), fsa_state2string(fsa_state)); } else if(timer->fsa_input != I_NULL) { register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL); } crm_debug_3("Triggering FSA: %s", __FUNCTION__); G_main_set_trigger(fsa_source); return TRUE; } gboolean crm_timer_start(fsa_timer_t *timer) { const char *timer_desc = get_timer_desc(timer); if(timer->source_id == 0 && timer->period_ms > 0) { timer->source_id = Gmain_timeout_add( timer->period_ms, timer->callback, (void*)timer); CRM_ASSERT(timer->source_id != 0); crm_debug("Started %s (%s:%dms), src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); } else if(timer->period_ms < 0) { crm_err("Tried to start %s (%s:%dms) with a -ve period", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); } else { crm_debug("%s (%s:%dms) already running: src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); return FALSE; } return TRUE; } gboolean crm_timer_stop(fsa_timer_t *timer) { const char *timer_desc = get_timer_desc(timer); if(timer == NULL) { crm_err("Attempted to stop NULL timer"); return FALSE; } else if(timer->source_id != 0) { crm_debug("Stopping %s (%s:%dms), src=%d", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms, timer->source_id); Gmain_timeout_remove(timer->source_id); timer->source_id = 0; } else { crm_debug_2("%s (%s:%dms) already stopped", timer_desc, fsa_input2string(timer->fsa_input), timer->period_ms); return FALSE; } return TRUE; } long long toggle_bit(long long action_list, long long action) { crm_debug_5("Toggling bit %.16llx", action); action_list ^= action; crm_debug_5("Result %.16llx", action_list & action); return action_list; } long long clear_bit(long long action_list, long long action) { unsigned int level = LOG_DEBUG_5; crm_log_maybe(level, "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) { unsigned int level = LOG_DEBUG_5; crm_log_maybe(level, "Setting bit\t%.16llx", action); action_list |= action; return action_list; } gboolean is_set(long long action_list, long long action) { crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list); return ((action_list & action) == action); } gboolean is_set_any(long long action_list, long long action) { crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list); 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_STOP: inputAsText = "I_STOP"; 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_HALT: inputAsText = "I_HALT"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; 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_HALT: stateAsText = "S_HALT"; 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_ELECTION_START: actionAsText = "A_ELECTION_START"; break; case A_READCONFIG: actionAsText = "A_READCONFIG"; 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 A_CL_JOIN_QUERY: actionAsText = "A_CL_JOIN_QUERY"; 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_ELECTION_CHECK: actionAsText = "A_ELECTION_CHECK"; 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_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_HALT: actionAsText = "A_TE_HALT"; break; case A_TE_CANCEL: actionAsText = "A_TE_CANCEL"; 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_inputs(int log_level, const char *text, long long input_register) { if(input_register == A_NOTHING) { return; } if(text == NULL) { text = "Input register contents:"; } if(is_set(input_register, R_THE_DC)) { crm_log_maybe(log_level, "%s %.16llx (R_THE_DC)", text, R_THE_DC); } if(is_set(input_register, R_STARTING)) { crm_log_maybe(log_level, "%s %.16llx (R_STARTING)", text, R_STARTING); } if(is_set(input_register, R_SHUTDOWN)) { crm_log_maybe(log_level, "%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN); } if(is_set(input_register, R_STAYDOWN)) { crm_log_maybe(log_level, "%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN); } if(is_set(input_register, R_JOIN_OK)) { crm_log_maybe(log_level, "%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK); } if(is_set(input_register, R_READ_CONFIG)) { crm_log_maybe(log_level, "%s %.16llx (R_READ_CONFIG)", text, R_READ_CONFIG); } if(is_set(input_register, R_INVOKE_PE)) { crm_log_maybe(log_level, "%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE); } if(is_set(input_register, R_CIB_CONNECTED)) { crm_log_maybe(log_level, "%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED); } if(is_set(input_register, R_PE_CONNECTED)) { crm_log_maybe(log_level, "%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED); } if(is_set(input_register, R_TE_CONNECTED)) { crm_log_maybe(log_level, "%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED); } if(is_set(input_register, R_LRM_CONNECTED)) { crm_log_maybe(log_level, "%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED); } if(is_set(input_register, R_CIB_REQUIRED)) { crm_log_maybe(log_level, "%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED); } if(is_set(input_register, R_PE_REQUIRED)) { crm_log_maybe(log_level, "%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED); } if(is_set(input_register, R_TE_REQUIRED)) { crm_log_maybe(log_level, "%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED); } if(is_set(input_register, R_REQ_PEND)) { crm_log_maybe(log_level, "%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND); } if(is_set(input_register, R_PE_PEND)) { crm_log_maybe(log_level, "%s %.16llx (R_PE_PEND)", text, R_PE_PEND); } if(is_set(input_register, R_TE_PEND)) { crm_log_maybe(log_level, "%s %.16llx (R_TE_PEND)", text, R_TE_PEND); } if(is_set(input_register, R_RESP_PEND)) { crm_log_maybe(log_level, "%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND); } if(is_set(input_register, R_CIB_DONE)) { crm_log_maybe(log_level, "%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE); } if(is_set(input_register, R_HAVE_CIB)) { crm_log_maybe(log_level, "%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB); } if(is_set(input_register, R_CIB_ASKED)) { crm_log_maybe(log_level, "%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED); } if(is_set(input_register, R_CCM_DATA)) { crm_log_maybe(log_level, "%s %.16llx (R_CCM_DATA)", text, R_CCM_DATA); } if(is_set(input_register, R_PEER_DATA)) { crm_log_maybe(log_level, "%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA); } if(is_set(input_register, R_IN_RECOVERY)) { crm_log_maybe(log_level, "%s %.16llx (R_IN_RECOVERY)", text, R_IN_RECOVERY); } } void fsa_dump_actions(long long action, const char *text) { int log_level = LOG_DEBUG_3; if(is_set(action, A_READCONFIG)) { crm_log_maybe(log_level, "Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text); } if(is_set(action, A_STARTUP)) { crm_log_maybe(log_level, "Action %.16llx (A_STARTUP) %s", A_STARTUP, text); } if(is_set(action, A_STARTED)) { crm_log_maybe(log_level, "Action %.16llx (A_STARTED) %s", A_STARTED, text); } if(is_set(action, A_HA_CONNECT)) { crm_log_maybe(log_level, "Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text); } if(is_set(action, A_HA_DISCONNECT)) { crm_log_maybe(log_level, "Action %.16llx (A_DISCONNECT) %s", A_HA_DISCONNECT, text); } if(is_set(action, A_LRM_CONNECT)) { crm_log_maybe(log_level, "Action %.16llx (A_LRM_CONNECT) %s", A_LRM_CONNECT, text); } if(is_set(action, A_LRM_EVENT)) { crm_log_maybe(log_level, "Action %.16llx (A_LRM_EVENT) %s", A_LRM_EVENT, text); } if(is_set(action, A_LRM_INVOKE)) { crm_log_maybe(log_level, "Action %.16llx (A_LRM_INVOKE) %s", A_LRM_INVOKE, text); } if(is_set(action, A_LRM_DISCONNECT)) { crm_log_maybe(log_level, "Action %.16llx (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text); } if(is_set(action, A_DC_TIMER_STOP)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_TIMER_STOP) %s", A_DC_TIMER_STOP, text); } if(is_set(action, A_DC_TIMER_START)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_TIMER_START) %s", A_DC_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_START)) { crm_log_maybe(log_level, "Action %.16llx (A_INTEGRATE_TIMER_START) %s", A_INTEGRATE_TIMER_START, text); } if(is_set(action, A_INTEGRATE_TIMER_STOP)) { crm_log_maybe(log_level, "Action %.16llx (A_INTEGRATE_TIMER_STOP) %s", A_INTEGRATE_TIMER_STOP, text); } if(is_set(action, A_FINALIZE_TIMER_START)) { crm_log_maybe(log_level, "Action %.16llx (A_FINALIZE_TIMER_START) %s", A_FINALIZE_TIMER_START, text); } if(is_set(action, A_FINALIZE_TIMER_STOP)) { crm_log_maybe(log_level, "Action %.16llx (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text); } if(is_set(action, A_ELECTION_COUNT)) { crm_log_maybe(log_level, "Action %.16llx (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text); } if(is_set(action, A_ELECTION_VOTE)) { crm_log_maybe(log_level, "Action %.16llx (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text); } if(is_set(action, A_ELECTION_CHECK)) { crm_log_maybe(log_level, "Action %.16llx (A_ELECTION_CHECK) %s", A_ELECTION_CHECK, text); } if(is_set(action, A_CL_JOIN_ANNOUNCE)) { crm_log_maybe(log_level, "Action %.16llx (A_CL_JOIN_ANNOUNCE) %s", A_CL_JOIN_ANNOUNCE, text); } if(is_set(action, A_CL_JOIN_REQUEST)) { crm_log_maybe(log_level, "Action %.16llx (A_CL_JOIN_REQUEST) %s", A_CL_JOIN_REQUEST, text); } if(is_set(action, A_CL_JOIN_RESULT)) { crm_log_maybe(log_level, "Action %.16llx (A_CL_JOIN_RESULT) %s", A_CL_JOIN_RESULT, text); } if(is_set(action, A_DC_JOIN_OFFER_ALL)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_JOIN_OFFER_ALL) %s", A_DC_JOIN_OFFER_ALL, text); } if(is_set(action, A_DC_JOIN_OFFER_ONE)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_JOIN_OFFER_ONE) %s", A_DC_JOIN_OFFER_ONE, text); } if(is_set(action, A_DC_JOIN_PROCESS_REQ)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s", A_DC_JOIN_PROCESS_REQ, text); } if(is_set(action, A_DC_JOIN_PROCESS_ACK)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s", A_DC_JOIN_PROCESS_ACK, text); } if(is_set(action, A_DC_JOIN_FINALIZE)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text); } if(is_set(action, A_MSG_PROCESS)) { crm_log_maybe(log_level, "Action %.16llx (A_MSG_PROCESS) %s", A_MSG_PROCESS, text); } if(is_set(action, A_MSG_ROUTE)) { crm_log_maybe(log_level, "Action %.16llx (A_MSG_ROUTE) %s", A_MSG_ROUTE, text); } if(is_set(action, A_RECOVER)) { crm_log_maybe(log_level, "Action %.16llx (A_RECOVER) %s", A_RECOVER, text); } if(is_set(action, A_DC_RELEASE)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_RELEASE) %s", A_DC_RELEASE, text); } if(is_set(action, A_DC_RELEASED)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_RELEASED) %s", A_DC_RELEASED, text); } if(is_set(action, A_DC_TAKEOVER)) { crm_log_maybe(log_level, "Action %.16llx (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text); } if(is_set(action, A_SHUTDOWN)) { crm_log_maybe(log_level, "Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text); } if(is_set(action, A_SHUTDOWN_REQ)) { crm_log_maybe(log_level, "Action %.16llx (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text); } if(is_set(action, A_STOP)) { crm_log_maybe(log_level, "Action %.16llx (A_STOP ) %s", A_STOP , text); } if(is_set(action, A_EXIT_0)) { crm_log_maybe(log_level, "Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text); } if(is_set(action, A_EXIT_1)) { crm_log_maybe(log_level, "Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text); } if(is_set(action, A_CCM_CONNECT)) { crm_log_maybe(log_level, "Action %.16llx (A_CCM_CONNECT) %s", A_CCM_CONNECT, text); } if(is_set(action, A_CCM_DISCONNECT)) { crm_log_maybe(log_level, "Action %.16llx (A_CCM_DISCONNECT) %s", A_CCM_DISCONNECT, text); } if(is_set(action, A_CCM_EVENT)) { crm_log_maybe(log_level, "Action %.16llx (A_CCM_EVENT) %s", A_CCM_EVENT, text); } if(is_set(action, A_CCM_UPDATE_CACHE)) { crm_log_maybe(log_level, "Action %.16llx (A_CCM_UPDATE_CACHE) %s", A_CCM_UPDATE_CACHE, text); } if(is_set(action, A_CIB_BUMPGEN)) { crm_log_maybe(log_level, "Action %.16llx (A_CIB_BUMPGEN) %s", A_CIB_BUMPGEN, text); } if(is_set(action, A_CIB_INVOKE)) { crm_log_maybe(log_level, "Action %.16llx (A_CIB_INVOKE) %s", A_CIB_INVOKE, text); } if(is_set(action, A_CIB_START)) { crm_log_maybe(log_level, "Action %.16llx (A_CIB_START) %s", A_CIB_START, text); } if(is_set(action, A_CIB_STOP)) { crm_log_maybe(log_level, "Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text); } if(is_set(action, A_TE_INVOKE)) { crm_log_maybe(log_level, "Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text); } if(is_set(action, A_TE_START)) { crm_log_maybe(log_level, "Action %.16llx (A_TE_START) %s", A_TE_START, text); } if(is_set(action, A_TE_STOP)) { crm_log_maybe(log_level, "Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text); } if(is_set(action, A_TE_CANCEL)) { crm_log_maybe(log_level, "Action %.16llx (A_TE_CANCEL) %s", A_TE_CANCEL, text); } if(is_set(action, A_PE_INVOKE)) { crm_log_maybe(log_level, "Action %.16llx (A_PE_INVOKE) %s", A_PE_INVOKE, text); } if(is_set(action, A_PE_START)) { crm_log_maybe(log_level, "Action %.16llx (A_PE_START) %s", A_PE_START, text); } if(is_set(action, A_PE_STOP)) { crm_log_maybe(log_level, "Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text); } if(is_set(action, A_NODE_BLOCK)) { crm_log_maybe(log_level, "Action %.16llx (A_NODE_BLOCK) %s", A_NODE_BLOCK, text); } if(is_set(action, A_UPDATE_NODESTATUS)) { crm_log_maybe(log_level, "Action %.16llx (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text); } if(is_set(action, A_LOG)) { crm_log_maybe(log_level, "Action %.16llx (A_LOG ) %s", A_LOG, text); } if(is_set(action, A_ERROR)) { crm_log_maybe(log_level, "Action %.16llx (A_ERROR ) %s", A_ERROR, text); } if(is_set(action, A_WARN)) { crm_log_maybe(log_level, "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. */ crm_data_t *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE); crm_debug_3("Creating node entry for %s", uname); set_uuid(fsa_cluster_conn, tmp1, XML_ATTR_UUID, uname); crm_xml_add(tmp1, XML_ATTR_UNAME, uname); crm_xml_add(tmp1, XML_ATTR_TYPE, type); fsa_cib_anon_update(XML_CIB_TAG_NODES, tmp1, cib_scope_local|cib_quorum_override); free_xml(tmp1); } 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_malloc0(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) { unsigned lpc = 0; int size = 0; int offset = 0; unsigned 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_debug_3("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_debug_3("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_debug_3("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_debug_3("Copying %d ccm nodes", num_nodes); crm_malloc0(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_3("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_debug_3("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_debug_3("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_debug_3("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_debug_3("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_debug_3("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); } crm_data_t* create_node_state( const char *uname, const char *ha_state, const char *ccm_state, const char *crmd_state, const char *join_state, const char *exp_state, gboolean clear_shutdown, const char *src) { crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_debug_2("%s Creating node state entry for %s", src, uname); set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, uname); + if(ID(node_state) == NULL) { + crm_debug("Node %s is not a cluster member", uname); + free_xml(node_state); + return NULL; + } + crm_xml_add(node_state, XML_ATTR_UNAME, uname); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, ha_state); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, ccm_state); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, join_state); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, exp_state); crm_xml_add(node_state, XML_ATTR_ORIGIN, src); if(clear_shutdown) { crm_xml_add(node_state, XML_CIB_ATTR_SHUTDOWN, "0"); #if CRM_DEPRECATED_SINCE_2_0_3 crm_xml_add(node_state, "clear_shutdown", "true"); #endif /* crm_xml_add(node_state, */ /* XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS); */ } crm_log_xml_debug_3(node_state, "created"); return node_state; } gboolean need_transition(enum crmd_fsa_state state) { if(state == S_POLICY_ENGINE || state == S_TRANSITION_ENGINE || state == S_IDLE) { return TRUE; } return FALSE; } extern GHashTable *ipc_clients; void process_client_disconnect(crmd_client_t *curr_client) { struct crm_subsystem_s *the_subsystem = NULL; CRM_CHECK(curr_client != NULL, return); crm_debug_2("received HUP from %s", curr_client->table_key); if (curr_client->sub_sys == NULL) { crm_debug_2("Client hadn't registered with us yet"); } else if (strcasecmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) { the_subsystem = pe_subsystem; } else if (strcasecmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) { the_subsystem = te_subsystem; } else if (strcasecmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){ the_subsystem = cib_subsystem; } if(the_subsystem != NULL) { the_subsystem->ipc = NULL; crm_info("Received HUP from %s:[%d]", the_subsystem->name, the_subsystem->pid); } else { /* else that was a transient client */ crm_debug("Received HUP from 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); } } void update_dc(HA_Message *msg, gboolean assert_same) { const char *dc_version = NULL; const char *welcome_from = NULL; if(msg != NULL) { dc_version = cl_get_string(msg, F_CRM_VERSION); welcome_from = cl_get_string(msg, F_CRM_HOST_FROM); CRM_CHECK(dc_version != NULL, return); CRM_CHECK(welcome_from != NULL, return); if(AM_I_DC) { CRM_CHECK(safe_str_eq(welcome_from, fsa_our_uname), return); } if(assert_same) { CRM_CHECK(fsa_our_dc != NULL, ;); CRM_CHECK(safe_str_eq(fsa_our_dc, welcome_from), ;); } } crm_free(fsa_our_dc); crm_free(fsa_our_dc_version); fsa_our_dc = NULL; fsa_our_dc_version = NULL; if(welcome_from != NULL) { fsa_our_dc = crm_strdup(welcome_from); } if(dc_version != NULL) { fsa_our_dc_version = crm_strdup(dc_version); } crm_info("Set DC to %s (%s)", crm_str(fsa_our_dc), crm_str(fsa_our_dc_version)); } diff --git a/crm/tengine/actions.c b/crm/tengine/actions.c index 1fea291455..2a9b53cfcf 100644 --- a/crm/tengine/actions.c +++ b/crm/tengine/actions.c @@ -1,495 +1,495 @@ /* $Id: actions.c,v 1.37 2006/08/14 09:14: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 */ #include #include #include #include #include #include #include #include #include #include #include #include char *te_uuid = NULL; IPC_Channel *crm_ch = NULL; void send_rsc_command(crm_action_t *action); extern crm_action_timer_t *transition_timer; static void te_start_action_timer(crm_action_t *action) { crm_malloc0(action->timer, sizeof(crm_action_timer_t)); action->timer->timeout = action->timeout; action->timer->reason = timeout_action_warn; action->timer->action = action; action->timer->source_id = Gmain_timeout_add( action->timer->timeout, action_timer_callback, (void*)action->timer); CRM_ASSERT(action->timer->source_id != 0); } static gboolean te_pseudo_action(crm_graph_t *graph, crm_action_t *pseudo) { crm_info("Pseudo action %d fired and confirmed", pseudo->id); pseudo->confirmed = TRUE; update_graph(graph, pseudo); trigger_graph(); return TRUE; } void send_stonith_update(stonith_ops_t * op) { enum cib_errors rc = cib_ok; const char *target = op->node_name; const char *uuid = op->node_uuid; /* zero out the node-status & remove all LRM status info */ crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE); CRM_CHECK(op->node_name != NULL, return); CRM_CHECK(op->node_uuid != NULL, return); crm_xml_add(node_state, XML_ATTR_UUID, uuid); crm_xml_add(node_state, XML_ATTR_UNAME, target); crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS); crm_xml_add(node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); crm_xml_add(node_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); crm_xml_add(node_state, XML_ATTR_ORIGIN, __FUNCTION__); rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, node_state, NULL, cib_quorum_override|cib_scope_local); if(rc < cib_ok) { crm_err("CIB update failed: %s", cib_error2string(rc)); abort_transition( INFINITY, tg_shutdown, "CIB update failed", node_state); } else { /* delay processing the trigger until the update completes */ add_cib_op_callback(rc, FALSE, NULL, cib_fencing_updated); } free_xml(node_state); return; } static gboolean te_fence_node(crm_graph_t *graph, crm_action_t *action) { char *key = NULL; const char *id = NULL; const char *uuid = NULL; const char *target = NULL; const char *type = NULL; stonith_ops_t * st_op = NULL; id = ID(action->xml); target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); type = g_hash_table_lookup(action->params, crm_meta_name("stonith_action")); CRM_CHECK(id != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); CRM_CHECK(uuid != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); CRM_CHECK(type != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); CRM_CHECK(target != NULL, crm_log_xml_warn(action->xml, "BadAction"); return FALSE); te_log_action(LOG_INFO, "Executing %s fencing operation (%s) on %s (timeout=%d)", type, id, target, transition_graph->transition_timeout / 2); crm_malloc0(st_op, sizeof(stonith_ops_t)); if(safe_str_eq(type, "poweroff")) { st_op->optype = POWEROFF; } else { st_op->optype = RESET; } st_op->timeout = transition_graph->transition_timeout / 2; st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); key = generate_transition_key(transition_graph->id, te_uuid); st_op->private_data = crm_concat(id, key, ';'); crm_free(key); CRM_ASSERT(stonithd_input_IPC_channel() != NULL); if (ST_OK != stonithd_node_fence( st_op )) { crm_err("Cannot fence %s: stonithd_node_fence() call failed ", target); } return TRUE; } static gboolean te_crm_command(crm_graph_t *graph, crm_action_t *action) { char *value = NULL; char *counter = NULL; HA_Message *cmd = NULL; const char *id = NULL; const char *task = NULL; const char *on_node = NULL; gboolean ret = TRUE; id = ID(action->xml); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); CRM_CHECK(on_node != NULL && strlen(on_node) != 0, te_log_action(LOG_ERR, "Corrupted command (id=%s) %s: no node", crm_str(id), crm_str(task)); return FALSE); te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s", crm_str(id), crm_str(task), on_node); cmd = create_request(task, NULL, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); counter = generate_transition_key(transition_graph->id, te_uuid); crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter); ret = send_ipc_message(crm_ch, cmd); crm_free(counter); crm_msg_del(cmd); value = g_hash_table_lookup(action->params, crm_meta_name(XML_ATTR_TE_NOWAIT)); if(ret == FALSE) { crm_err("Action %d failed: send", action->id); return FALSE; } else if(crm_is_true(value)) { crm_info("Skipping wait for %d", action->id); action->confirmed = TRUE; update_graph(graph, action); trigger_graph(); } else if(ret && action->timeout > 0) { crm_debug("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; te_start_action_timer(action); } return TRUE; } static gboolean te_rsc_command(crm_graph_t *graph, crm_action_t *action) { /* never overwrite stop actions in the CIB with * anything other than completed results * * Writing pending stops makes it look like the * resource is running again */ const char *task = NULL; const char *on_node = NULL; action->executed = FALSE; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); CRM_CHECK(on_node != NULL && strlen(on_node) != 0, te_log_action(LOG_ERR, "Corrupted command(id=%s) %s: no node", ID(action->xml), crm_str(task)); return FALSE); send_rsc_command(action); return TRUE; } gboolean cib_action_update(crm_action_t *action, int status) { char *code = NULL; char *digest = NULL; crm_data_t *params = NULL; crm_data_t *state = NULL; crm_data_t *rsc = NULL; crm_data_t *xml_op = NULL; crm_data_t *action_rsc = NULL; char *op_id = NULL; enum cib_errors rc = cib_ok; const char *name = NULL; const char *value = NULL; const char *rsc_id = NULL; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *task_uuid = crm_element_value( action->xml, XML_LRM_ATTR_TASK_KEY); const char *target_uuid = crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_quorum_override|cib_scope_local; crm_warn("%s %d: %s on %s timed out", crm_element_name(action->xml), action->id, task_uuid, target); action_rsc = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, TRUE); if(action_rsc == NULL) { return FALSE; } rsc_id = ID(action_rsc); CRM_CHECK(rsc_id != NULL, crm_log_xml_err(action->xml, "Bad:action"); return FALSE); code = crm_itoa(status); /* update the CIB */ state = create_xml_node(NULL, XML_CIB_TAG_STATE); crm_xml_add(state, XML_ATTR_UUID, target_uuid); crm_xml_add(state, XML_ATTR_UNAME, target); rsc = create_xml_node(state, XML_CIB_TAG_LRM); crm_xml_add(rsc, XML_ATTR_ID, target_uuid); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); crm_xml_add(rsc, XML_ATTR_ID, rsc_id); name = XML_ATTR_TYPE; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); name = XML_AGENT_ATTR_CLASS; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); name = XML_AGENT_ATTR_PROVIDER; value = crm_element_value(action_rsc, name); crm_xml_add(rsc, name, value); xml_op = create_xml_node(rsc, XML_LRM_TAG_RSC_OP); crm_xml_add(xml_op, XML_ATTR_ID, task); op_id = generate_op_key(rsc_id, task, action->interval); crm_xml_add(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task); crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET); crm_xml_add(xml_op, XML_LRM_ATTR_OPSTATUS, code); crm_xml_add(xml_op, XML_LRM_ATTR_CALLID, "-1"); crm_xml_add_int(xml_op, XML_LRM_ATTR_INTERVAL, action->interval); crm_xml_add(xml_op, XML_LRM_ATTR_RC, code); crm_xml_add(xml_op, XML_ATTR_ORIGIN, __FUNCTION__); crm_free(code); code = generate_transition_key(transition_graph->id, te_uuid); crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, code); crm_free(code); code = generate_transition_magic( crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY), status, status); crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, code); crm_free(code); params = find_xml_node(action->xml, "attributes", TRUE); params = copy_xml(params); filter_action_parameters(params, CRM_FEATURE_SET); digest = calculate_xml_digest(params, TRUE); crm_xml_add(xml_op, XML_LRM_ATTR_OP_DIGEST, digest); crm_free(digest); free_xml(params); crm_debug_3("Updating CIB with \"%s\" (%s): %s %s on %s", status<0?"new action":XML_ATTR_TIMEOUT, crm_element_name(action->xml), crm_str(task), rsc_id, target); rc = te_cib_conn->cmds->update( te_cib_conn, XML_CIB_TAG_STATUS, state, NULL, call_options); crm_debug("Updating CIB with %s action %d: %s %s on %s (call_id=%d)", op_status2text(status), action->id, task_uuid, rsc_id, target, rc); add_cib_op_callback(rc, FALSE, NULL, cib_action_updated); free_xml(state); action->sent_update = TRUE; if(rc < cib_ok) { return FALSE; } return TRUE; } void send_rsc_command(crm_action_t *action) { HA_Message *cmd = NULL; crm_data_t *rsc_op = NULL; - char *counter = crm_itoa(transition_graph->id); + char *counter = NULL; const char *task = NULL; const char *value = NULL; const char *on_node = NULL; const char *task_uuid = NULL; CRM_ASSERT(action != NULL); CRM_ASSERT(action->xml != NULL); rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); counter = generate_transition_key(transition_graph->id, te_uuid); crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter); crm_info("Initiating action %d: %s on %s", action->id, task_uuid, on_node); crm_free(counter); if(rsc_op != NULL) { crm_log_xml_debug_2(rsc_op, "Performing"); } cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, on_node, CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL); #if 1 send_ipc_message(crm_ch, cmd); #else /* test the TE timer/recovery code */ if((action->id % 11) == 0) { crm_err("Faking lost action %d: %s", action->id, task_uuid); } else { send_ipc_message(crm_ch, cmd); } #endif crm_msg_del(cmd); action->executed = TRUE; value = g_hash_table_lookup(action->params, crm_meta_name(XML_ATTR_TE_NOWAIT)); if(crm_is_true(value)) { crm_debug("Skipping wait for %d", action->id); action->confirmed = TRUE; update_graph(transition_graph, action); trigger_graph(); } else if(action->timeout > 0) { int action_timeout = 2 * action->timeout + transition_graph->network_delay; crm_debug_3("Setting timer for action %s", task_uuid); if(transition_graph->transition_timeout < action_timeout) { crm_debug("Action %d:" " Increasing transition %d timeout to %d", action->id, transition_graph->id, transition_graph->transition_timeout); transition_graph->transition_timeout = action_timeout; } te_start_action_timer(action); } } crm_graph_functions_t te_graph_fns = { te_pseudo_action, te_rsc_command, te_crm_command, te_fence_node }; void notify_crmd(crm_graph_t *graph) { HA_Message *cmd = NULL; int log_level = LOG_DEBUG; const char *op = CRM_OP_TEABORT; int pending_callbacks = num_cib_op_callbacks(); stop_te_timer(transition_timer); if(pending_callbacks != 0) { crm_warn("Delaying completion until all CIB updates complete"); return; } CRM_CHECK(graph->complete, graph->complete = TRUE); switch(graph->completion_action) { case tg_stop: op = CRM_OP_TECOMPLETE; log_level = LOG_INFO; break; case tg_abort: case tg_restart: op = CRM_OP_TEABORT; break; case tg_shutdown: crm_info("Exiting after transition"); exit(LSB_EXIT_OK); } te_log_action(log_level, "Transition %d status: %s - %s", graph->id, op, crm_str(graph->abort_reason)); print_graph(LOG_DEBUG_3, graph); cmd = create_request( op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); if(graph->abort_reason != NULL) { ha_msg_add(cmd, "message", graph->abort_reason); } send_ipc_message(crm_ch, cmd); crm_msg_del(cmd); graph->abort_reason = NULL; graph->completion_action = tg_restart; } diff --git a/crm/tengine/events.c b/crm/tengine/events.c index 1341ac75c3..da847280e9 100644 --- a/crm/tengine/events.c +++ b/crm/tengine/events.c @@ -1,546 +1,551 @@ /* $Id: events.c,v 1.23 2006/08/14 09:14: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 */ #include #include #include #include #include #include #include #include #include #include #include crm_data_t *need_abort(crm_data_t *update); void process_graph_event(crm_data_t *event, const char *event_node); int match_graph_event( crm_action_t *action, crm_data_t *event, const char *event_node); crm_data_t * need_abort(crm_data_t *update) { crm_data_t *section_xml = NULL; const char *section = NULL; if(update == NULL) { return NULL; } section = XML_CIB_TAG_NODES; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_RESOURCES; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_CONSTRAINTS; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); section = XML_CIB_TAG_CRMCONFIG; section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, return section_xml; ); return NULL; } static gboolean fail_incompletable_actions(crm_graph_t *graph, const char *down_node) { const char *target = NULL; crm_data_t *last_action = NULL; slist_iter( synapse, synapse_t, graph->synapses, lpc, if (synapse->confirmed) { continue; } slist_iter( action, crm_action_t, synapse->actions, lpc, if(action->type == action_type_pseudo || action->confirmed) { continue; } target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); if(safe_str_eq(target, down_node)) { action->failed = TRUE; last_action = action->xml; update_graph(graph, action); crm_notice("Action %d (%s) is scheduled for %s (offline)", action->id, ID(action->xml), down_node); } ); ); if(last_action != NULL) { crm_warn("Node %s shutdown resulted in un-runnable actions", down_node); abort_transition(INFINITY, tg_restart, "Node failure", last_action); return TRUE; } return FALSE; } gboolean extract_event(crm_data_t *msg) { int shutdown = 0; const char *event_node = NULL; /* [cib fragment] ... */ crm_debug_4("Extracting event from %s", crm_element_name(msg)); xml_child_iter_filter( msg, node_state, XML_CIB_TAG_STATE, crm_data_t *attrs = NULL; crm_data_t *resources = NULL; const char *ccm_state = crm_element_value( node_state, XML_CIB_ATTR_INCCM); const char *crmd_state = crm_element_value( node_state, XML_CIB_ATTR_CRMDSTATE); /* Transient node attribute changes... */ event_node = crm_element_value(node_state, XML_ATTR_ID); crm_debug_2("Processing state update from %s", event_node); crm_log_xml_debug_3(node_state, "Processing"); attrs = find_xml_node( node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE); if(attrs != NULL) { crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" changes for %s", event_node); abort_transition(INFINITY, tg_restart, XML_TAG_TRANSIENT_NODEATTRS, attrs); } resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); resources = find_xml_node( resources, XML_LRM_TAG_RESOURCES, FALSE); /* LRM resource update... */ xml_child_iter( resources, rsc, xml_child_iter( rsc, rsc_op, crm_log_xml_debug_3(rsc_op, "Processing resource update"); process_graph_event(rsc_op, event_node); ); ); /* * node state update... possibly from a shutdown we requested */ if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE) || safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) { crm_action_t *shutdown = NULL; shutdown = match_down_event(0, event_node, NULL); if(shutdown != NULL) { update_graph(transition_graph, shutdown); trigger_graph(); } else { crm_info("Stonith/shutdown of %s not matched", event_node); abort_transition(INFINITY, tg_restart, "Node failure", node_state); } fail_incompletable_actions(transition_graph, event_node); } shutdown = 0; ha_msg_value_int(node_state, XML_CIB_ATTR_SHUTDOWN, &shutdown); if(shutdown != 0) { crm_info("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute for %s", event_node); abort_transition(INFINITY, tg_restart, "Shutdown request", node_state); } ); return TRUE; } static void update_failcount(crm_action_t *action, int rc) { crm_data_t *rsc = NULL; char *attr_name = NULL; const char *task = NULL; const char *rsc_id = NULL; const char *on_node = NULL; const char *on_uuid = NULL; const char *interval = NULL; if(rc == 99) { /* this is an internal code for "we're busy, try again" */ return; } interval = g_hash_table_lookup( action->params, crm_meta_name("interval")); if(interval == NULL) { return; } CRM_CHECK(action->xml != NULL, return); rsc = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, TRUE); CRM_CHECK(rsc != NULL, return); rsc_id = ID(rsc); CRM_CHECK(rsc_id != NULL, return); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); on_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); CRM_CHECK(task != NULL, return); CRM_CHECK(on_uuid != NULL, return); CRM_CHECK(on_node != NULL, return); attr_name = crm_concat("fail-count", rsc_id, '-'); crm_warn("Updating failcount for %s on %s after failed %s: rc=%d", rsc_id, on_node, task, rc); update_attr(te_cib_conn, cib_none, XML_CIB_TAG_STATUS, on_uuid, NULL,NULL, attr_name, XML_NVPAIR_ATTR_VALUE"++"); crm_free(attr_name); } /* * returns the ID of the action if a match is found * returns -1 if a match was not found * returns -2 if a match was found but the action failed (and was * not allowed to) */ int match_graph_event( crm_action_t *action, crm_data_t *event, const char *event_node) { int log_level_fail = LOG_ERR; int target_rc = 0; const char *target_rc_s = NULL; const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; const char *this_uname = NULL; const char *magic = NULL; const char *this_event; char *update_te_uuid = NULL; const char *update_event; int op_status_i = -3; int op_rc_i = -3; int transition_i = -1; CRM_CHECK(event != NULL, return -1); crm_debug_3("Processing \"%s\" change", crm_element_name(event)); update_event = crm_element_value(event, XML_ATTR_ID); magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); CRM_CHECK(magic != NULL, return -2); this_action = crm_element_value(action->xml, XML_LRM_ATTR_TASK); this_uname = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); this_event = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); this_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); CRM_CHECK(this_event != NULL, return -2); if(safe_str_neq(this_event, update_event)) { crm_debug_2("Action %d : Event mismatch %s vs. %s", action->id, this_event, update_event); return -1; } else if(safe_str_neq(this_node, event_node)) { crm_debug_2("Action %d : Node mismatch %s (%s) vs. %s", action->id, this_node, this_uname, event_node); return -1; } crm_debug_2("Matched action (%d) %s", action->id, this_event); CRM_CHECK(decode_transition_magic( magic, &update_te_uuid, &transition_i, &op_status_i, &op_rc_i), return -2); if(transition_i == -1) { /* we never expect these - recompute */ crm_err("Detected action %s initiated outside of a transition", this_event); crm_log_message(LOG_ERR, event); + crm_free(update_te_uuid); return -2; } else if(safe_str_neq(update_te_uuid, te_uuid)) { crm_info("Detected action %s from a different transitioner:" " %s vs. %s", this_event, update_te_uuid, te_uuid); crm_log_message(LOG_INFO, event); + crm_free(update_te_uuid); return -3; } else if(transition_graph->id != transition_i) { crm_warn("Detected an action %s from a different transition:" " %d vs. %d", this_event, transition_i, transition_graph->id); crm_log_message(LOG_INFO, event); + crm_free(update_te_uuid); return -4; } + + crm_free(update_te_uuid); /* stop this event's timer if it had one */ stop_te_timer(action->timer); action->confirmed = TRUE; target_rc_s = g_hash_table_lookup( action->params,crm_meta_name(XML_ATTR_TE_TARGET_RC)); if(target_rc_s != NULL) { crm_debug_2("Target rc: %s vs. %d", target_rc_s, op_rc_i); target_rc = crm_parse_int(target_rc_s, NULL); if(target_rc == op_rc_i) { crm_debug_2("Target rc: == %d", op_rc_i); if(op_status_i != LRM_OP_DONE) { crm_debug_2("Re-mapping op status to" " LRM_OP_DONE for %s",update_event); op_status_i = LRM_OP_DONE; } } else { crm_debug_2("Target rc: != %d", op_rc_i); if(op_status_i != LRM_OP_ERROR) { crm_info("Re-mapping op status to" " LRM_OP_ERROR for %s", update_event); op_status_i = LRM_OP_ERROR; } } } /* Process OP status */ switch(op_status_i) { case -3: crm_err("Action returned the same as last time..." " whatever that was!"); crm_log_message(LOG_ERR, event); break; case LRM_OP_PENDING: crm_debug("Ignoring pending operation"); return -5; break; case LRM_OP_DONE: break; case LRM_OP_ERROR: /* This is the code we use for direct nack's */ if(op_rc_i == 99) { log_level_fail = LOG_WARNING; } /* fall through */ case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: action->failed = TRUE; crm_log_maybe(log_level_fail, "Action %s on %s failed (target: %d vs. rc: %d): %s", update_event, this_uname, target_rc, op_rc_i, op_status2text(op_status_i)); break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_err("Dont know what to do for cancelled ops yet"); break; default: action->failed = TRUE; crm_err("Unsupported action result: %d", op_status_i); } update_graph(transition_graph, action); trigger_graph(); if(action->failed) { allow_fail = g_hash_table_lookup( action->params, crm_meta_name(XML_ATTR_TE_ALLOWFAIL)); if(crm_is_true(allow_fail)) { action->failed = FALSE; } } if(action->failed) { /* ignore probes */ if(target_rc != EXECRA_NOT_RUNNING) { update_failcount(action, op_rc_i); } abort_transition(action->synapse->priority+1, tg_restart, "Event failed", event); } else if(transition_graph->complete) { abort_transition(INFINITY, tg_restart,"No active graph", event); } te_log_action(LOG_INFO, "Action %s (%d) confirmed", this_event, action->id); return action->id; } crm_action_t * match_down_event(int id, const char *target, const char *filter) { const char *this_action = NULL; const char *this_node = NULL; crm_action_t *match = NULL; slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, if(id > 0 && action->id == id) { match = action; break; } this_action = crm_element_value( action->xml, XML_LRM_ATTR_TASK); if(action->type != action_type_crm) { continue; } else if(safe_str_eq(this_action, CRM_OP_LRM_REFRESH)){ continue; } else if(filter != NULL && safe_str_neq(this_action, filter)) { continue; } this_node = crm_element_value( action->xml, XML_LRM_ATTR_TARGET_UUID); if(this_node == NULL) { crm_log_xml_err(action->xml, "No node uuid"); } if(safe_str_neq(this_node, target)) { crm_debug("Action %d : Node mismatch: %s", action->id, this_node); continue; } match = action; break; ); if(match != NULL) { /* stop this event's timer if it had one */ break; } ); if(match != NULL) { /* stop this event's timer if it had one */ crm_debug("Match found for action %d: %s on %s", id, crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY), target); stop_te_timer(match->timer); match->confirmed = TRUE; } else if(id > 0) { crm_err("No match for action %d", id); } else { crm_warn("No match for shutdown action on %s", target); } return match; } void process_graph_event(crm_data_t *event, const char *event_node) { int rc = -1; const char *magic = NULL; const char *rsc_id = NULL; CRM_ASSERT(event != NULL); rsc_id = crm_element_value(event, XML_ATTR_ID); magic = crm_element_value(event, XML_ATTR_TRANSITION_MAGIC); if(magic == NULL) { crm_log_xml_debug_2(event, "Skipping \"non-change\""); return; } else { crm_debug_2("Processing CIB update: %s on %s: %s", rsc_id, event_node, magic); } slist_iter( synapse, synapse_t, transition_graph->synapses, lpc, /* lookup event */ slist_iter( action, crm_action_t, synapse->actions, lpc2, rc = match_graph_event(action, event, event_node); if(rc >= 0) { crm_log_xml_debug_2(event, "match:found"); } else if(rc == -5) { crm_log_xml_debug_2(event, "match:pending"); } else if(rc != -1) { crm_warn("Search for %s terminated: %d", ID(event), rc); abort_transition(INFINITY, tg_restart, "Unexpected event", event); } if(rc != -1) { return; } ); ); /* unexpected event, trigger a pe-recompute */ /* possibly do this only for certain types of actions */ crm_warn("Event not found."); crm_log_xml_info(event, "match:not-found"); abort_transition(INFINITY, tg_restart, "Unexpected event", event); return; }