diff --git a/crm/tengine/callbacks.c b/crm/tengine/callbacks.c index e1ae1e9cbd..edabfce086 100644 --- a/crm/tengine/callbacks.c +++ b/crm/tengine/callbacks.c @@ -1,353 +1,353 @@ -/* $Id: callbacks.c,v 1.32 2005/05/27 15:06:40 andrew Exp $ */ +/* $Id: callbacks.c,v 1.33 2005/06/13 12:24:37 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 void te_update_confirm(const char *event, HA_Message *msg); void te_update_confirm(const char *event, HA_Message *msg) { int rc = -1; gboolean done = FALSE; const char *op = cl_get_string(msg, F_CIB_OPERATION); const char *type = cl_get_string(msg, F_CIB_OBJTYPE); crm_data_t *update = get_message_xml(msg, F_CIB_UPDATE); ha_msg_value_int(msg, F_CIB_RC, &rc); crm_debug("Processing %s...", event); crm_log_xml_debug_2(update, "Processing update"); if(op == NULL) { crm_err("Illegal CIB update, the operation must be specified"); send_complete("Illegal update", update, te_update, i_cancel); done = TRUE; } else if(te_fsa_state == s_abort_pending) { /* take no further actions if an abort is pending */ crm_debug("Ignoring CIB update while waiting for an abort"); done = TRUE; - } else if(strcmp(op, CRM_OP_CIB_ERASE) == 0) { + } else if(strcmp(op, CIB_OP_ERASE) == 0) { /* these are always unexpected, trigger the PE */ crm_err("Need to trigger an election here so that" " the current state of all nodes is obtained"); send_complete("Erase event", update, te_update, i_cancel); done = TRUE; - } else if(strcmp(op, CRM_OP_CIB_CREATE) == 0 - || strcmp(op, CRM_OP_CIB_DELETE) == 0 - || strcmp(op, CRM_OP_CIB_REPLACE) == 0 + } else if(strcmp(op, CIB_OP_CREATE) == 0 + || strcmp(op, CIB_OP_DELETE) == 0 + || strcmp(op, CIB_OP_REPLACE) == 0 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { /* these are always unexpected, trigger the PE */ send_complete("Non-update change", update, te_update, i_cancel); done = TRUE; - } else if(strcmp(op, CRM_OP_CIB_UPDATE) != 0) { + } else if(strcmp(op, CIB_OP_UPDATE) != 0) { crm_debug_2("Ignoring %s op confirmation", op); done = TRUE; } if(done) { free_xml(update); return; } if(safe_str_eq(type, XML_CIB_TAG_CRMCONFIG)) { /* ignore - for the moment */ crm_debug("Ignoring changes to the %s section", type); } else if(safe_str_eq(type, XML_CIB_TAG_NODES)) { /* ignore new nodes until they sign up */ crm_debug("Ignoring changes to the %s section", type); } else if(safe_str_eq(type, XML_CIB_TAG_STATUS)) { /* this _may_ not be un-expected */ if(extract_event(update) == FALSE) { send_complete("Unexpected status update", update, te_update, i_cancel); } } else if(safe_str_eq(type, XML_CIB_TAG_NODES) || safe_str_eq(type, XML_CIB_TAG_RESOURCES) || safe_str_eq(type, XML_CIB_TAG_CONSTRAINTS)) { /* these are never expected */ crm_debug("Aborting on changes to the %s section", type); send_complete("Non-status update", update, te_update, i_cancel); } else if(safe_str_eq(type, XML_TAG_CIB)) { crm_data_t *section_xml = NULL; const char *section = NULL; gboolean abort = FALSE; section = XML_CIB_TAG_NODES; if(abort == FALSE) { section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, NULL, abort = TRUE; break; ); } section = XML_CIB_TAG_RESOURCES; if(abort == FALSE) { section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, NULL, abort = TRUE; break; ); } section = XML_CIB_TAG_CONSTRAINTS; if(abort == FALSE) { section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, NULL, abort = TRUE; break; ); } section = XML_CIB_TAG_CRMCONFIG; if(abort == FALSE) { section_xml = get_object_root(section, update); xml_child_iter(section_xml, child, NULL, abort = TRUE; break; ); } if(abort) { send_complete("Non-status update", update, te_update, i_cancel); } section = XML_CIB_TAG_STATUS; if(abort == FALSE) { section_xml = get_object_root(section, update); if(extract_event(section_xml) == FALSE) { send_complete("Unexpected global status update", section_xml, te_update, i_cancel); } } } else { crm_err("Ignoring update confirmation for %s object", type); crm_log_xml_debug(update, "Ignored update"); } free_xml(update); } gboolean process_te_message(HA_Message *msg, crm_data_t *xml_data, IPC_Channel *sender) { const char *sys_to = cl_get_string(msg, F_CRM_SYS_TO); const char *ref = cl_get_string(msg, XML_ATTR_REFERENCE); const char *op = cl_get_string(msg, F_CRM_TASK); crm_log_message(LOG_DEBUG_3, msg); if(safe_str_eq(cl_get_string(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE) && safe_str_neq(op, CRM_OP_EVENTCC)) { crm_info("Message was a response not a request. Discarding"); return TRUE; } crm_debug("Processing %s (%s) message", op, ref); if(op == NULL){ /* error */ } else if(strcmp(op, CRM_OP_HELLO) == 0) { /* ignore */ } else if(sys_to == NULL || strcmp(sys_to, CRM_SYSTEM_TENGINE) != 0) { crm_debug_2("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(strcmp(op, CRM_OP_TRANSITION) == 0) { if(te_fsa_state != s_idle) { crm_debug("Attempt to start another transition"); send_complete(CRM_OP_TE_HALT, NULL, te_halt, i_cancel); } else { te_fsa_state = te_state_matrix[i_transition][te_fsa_state]; initialize_graph(); unpack_graph(xml_data); crm_debug("Initiating transition..."); if(initiate_transition() == FALSE) { /* nothing to be done.. means we're done. */ crm_info("No actions to be taken..." " transition compelte."); } } } else if(strcmp(op, CRM_OP_TE_HALT) == 0) { send_complete(CRM_OP_TE_HALT, NULL, te_halt, i_cancel); } else if(strcmp(op, CRM_OP_TEABORT) == 0) { send_complete(CRM_OP_TEABORTED, NULL, te_abort_confirmed, i_cancel); } else if(strcmp(op, CRM_OP_QUIT) == 0) { crm_info("Received quit message, terminating"); exit(0); #ifdef TESTING } else if(strcmp(op, CRM_OP_EVENTCC) == 0) { crm_debug_4("Processing %s...", CRM_OP_EVENTCC); if(extract_event(msg) == FALSE) { send_complete("ttest loopback", msg, te_failed, i_complete); } #endif } else { crm_err("Unknown command: %s", op); } crm_debug_3("finished processing message"); return TRUE; } void tengine_stonith_callback(stonith_ops_t * op, void * private_data) { int action_id = -1; if(op == NULL) { crm_err("Called with a NULL op!"); return; } crm_info("optype=%d, node_name=%s, result=%d, node_list=%s", op->optype, op->node_name, op->op_result, (char *)op->node_list); if(te_fsa_state == s_abort_pending) { /* take no further actions if an abort is pending */ crm_debug("Ignoring Stonith result while waiting for an abort"); return; } /* this will mark the event complete if a match is found */ action_id = match_down_event( op->node_name, CRM_OP_FENCE, op->op_result); if(op->op_result == STONITH_SUCCEEDED) { 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 *update = NULL; crm_data_t *node_state = create_xml_node( NULL, XML_CIB_TAG_STATE); CRM_DEV_ASSERT(op->node_name != NULL); CRM_DEV_ASSERT(op->node_uuid != NULL); set_xml_property_copy(node_state, XML_ATTR_UUID, uuid); set_xml_property_copy(node_state, XML_ATTR_UNAME, target); set_xml_property_copy( node_state, XML_CIB_ATTR_HASTATE, DEADSTATUS); set_xml_property_copy( node_state, XML_CIB_ATTR_INCCM, XML_BOOLEAN_NO); set_xml_property_copy( node_state, XML_CIB_ATTR_CRMDSTATE, OFFLINESTATUS); set_xml_property_copy( node_state, XML_CIB_ATTR_JOINSTATE,CRMD_JOINSTATE_DOWN); set_xml_property_copy( node_state, XML_CIB_ATTR_EXPSTATE, CRMD_JOINSTATE_DOWN); set_xml_property_copy( node_state, XML_CIB_ATTR_REPLACE, XML_CIB_TAG_LRM); create_xml_node(node_state, XML_CIB_TAG_LRM); update = create_cib_fragment(node_state, NULL); free_xml(node_state); rc = te_cib_conn->cmds->modify( te_cib_conn, XML_CIB_TAG_STATUS, update, NULL, cib_quorum_override); if(action_id < 0) { send_complete("Stonith not matched", update, te_update, i_cancel); } else if(rc != cib_ok) { send_complete("Couldnt update CIB after stonith", update, te_failed, i_cancel); } else { process_trigger(action_id); check_for_completion(); } free_xml(update); } else { send_complete("Fencing op failed", NULL, te_failed, i_cancel); } } void tengine_stonith_connection_destroy(gpointer user_data) { #if 0 crm_err("Fencing daemon has left us: Shutting down...NOW"); /* shutdown properly later */ CRM_DEV_ASSERT(FALSE/* fencing daemon died */); #else crm_err("Fencing daemon has left us"); #endif return; } gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; while(stonithd_op_result_ready()) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if(ST_FAIL == stonithd_receive_ops_result(FALSE)) { crm_err("stonithd_receive_ops_result() failed"); } else { lpc++; } } crm_debug_2("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { return FALSE; } return TRUE; } diff --git a/crm/tengine/fsa_data.c b/crm/tengine/fsa_data.c index 92ac9578a3..ae97b90cba 100644 --- a/crm/tengine/fsa_data.c +++ b/crm/tengine/fsa_data.c @@ -1,328 +1,328 @@ -/* $Id: fsa_data.c,v 1.1 2005/05/30 15:09:36 andrew Exp $ */ +/* $Id: fsa_data.c,v 1.2 2005/06/13 12:24:37 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 extern void te_input_free(te_input_t *fsa_data); extern te_input_t* te_input_copy(te_input_t *fsa_data); extern te_input_t* te_input_new(enum te_data_type type, void *data); extern te_input_t *new_input_command(HA_Message *msg, crm_data_t *xml); extern te_input_t *new_input_complete(const char *text, crm_data_t *xml, te_reason_t reason, te_fsa_input_t input); extern te_input_t *new_input_cib(HA_Message *msg, crm_data_t *xml, int call_id, int rc, void *user_data); extern te_input_t *new_input_null(void); const char* te_data_null_type(void); const char* te_data_null_name(void); void te_data_null_free(te_input_t *fsa_data); void te_data_null_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_command_type(void); const char* te_data_command_name(void); void te_data_command_free(te_input_t *fsa_data); void te_data_command_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_cib_type(void); const char* te_data_cib_name(void); void te_data_cib_free(te_input_t *fsa_data); void te_data_cib_copy(te_input_t *a_copy, te_input_t *fsa_data); const char* te_data_complete_type(void); const char* te_data_complete_name(void); void te_data_complete_free(te_input_t *fsa_data); void te_data_complete_copy(te_input_t *a_copy, te_input_t *fsa_data); GListPtr input_queue = NULL; te_data_op_t te_ops_null = { te_data_null_type, te_data_null_name, te_data_null_free, te_data_null_copy }; te_data_op_t te_ops_cib = { te_data_cib_type, te_data_cib_name, te_data_cib_free, te_data_cib_copy }; te_data_op_t te_ops_complete = { te_data_complete_type, te_data_complete_name, te_data_complete_free, te_data_complete_copy }; te_data_op_t te_ops_command = { te_data_command_type, te_data_command_name, te_data_command_free, te_data_command_copy }; void te_input_free(te_input_t *fsa_data) { if(fsa_data == NULL) { return; } fsa_data->ops->free(fsa_data); crm_free(fsa_data); } te_input_t* te_input_copy(te_input_t *fsa_data) { te_input_t *a_copy = NULL; CRM_DEV_ASSERT(fsa_data != NULL); if(crm_assert_failed) {return NULL;} crm_malloc0(a_copy, sizeof(te_input_t)); *a_copy = *fsa_data; a_copy->data = NULL; a_copy->ops->copy(fsa_data); } te_input_t* te_input_new( te_fsa_input_t input, enum te_data_type type, void *data) { static int input_id = 0; te_input_t *a_copy = NULL; crm_malloc0(a_copy, sizeof(te_input_t)); a_copy->id = input_id++; a_copy->origin = origin; a_copy->input = input; a_copy->data = data; switch(type) { case te_data_cib: a_copy->ops = &te_ops_cib; break; case te_data_complete: a_copy->ops = &te_ops_complete; break; case te_data_command: a_copy->ops = &te_ops_command; break; case te_data_null: a_copy->ops = &te_ops_null; break; } } const char* te_data_null_type(void) { return te_data_null; } const char* te_data_null_name(void) { return "Null"; } void te_data_null_free(te_input_t *fsa_data) { } void te_data_null_copy(te_input_t *a_copy, te_input_t *fsa_data) { a_copy->data = NULL; } const char* te_data_command_type(void) { return te_data_command; } const char* te_data_command_name(void) { return "DC Command"; } void te_data_command_free(te_input_t *fsa_data) { struct te_data_command_s *data = fsa_data->data; CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_command); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_command_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_command_s *data = fsa_data->data; struct te_data_command_s *copy_data = NULL; CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_command); crm_malloc0(a_copy->data, sizeof(struct te_data_command_s)); copy_data = a_copy->data; copy_data->msg = ha_msg_copy(data->msg); - copy_data->xml = copy_xml_node_recursive(data->xml); + copy_data->xml = copy_xml(data->xml); } const char* te_data_cib_type(void) { return te_data_cib; } const char* te_data_cib_name(void) { return "CIB Callback"; } void te_data_cib_free(te_input_t *fsa_data) { struct te_data_cib_s *data = fsa_data->data; CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_cib); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_cib_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_cib_s *data = fsa_data->data; struct te_data_cib_s *copy_data = NULL; CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_cib); crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; *copy_data = *data; copy_data->msg = ha_msg_copy(data->msg); - copy_data->xml = copy_xml_node_recursive(data->xml); + copy_data->xml = copy_xml(data->xml); } const char* te_data_complete_type(void) { return te_data_complete; } const char* te_data_complete_name(void) { return "Transition Complete"; } void te_data_complete_free(te_input_t *fsa_data) { struct te_data_complete_s *data = fsa_data->data; CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_complete); ha_msg_del(data->msg); free_xml(data->xml); crm_free(data); } void te_data_complete_copy(te_input_t *a_copy, te_input_t *fsa_data) { struct te_data_complete_s *data = fsa_data->data; struct te_data_complete_s *copy_data = NULL; CRM_DEV_ASSERT(fsa_data->ops->type() == te_data_complete); crm_malloc0(a_copy->data, sizeof(struct te_data_complete_s)); copy_data = a_copy->data; *copy_data = *data; - copy_data->xml = copy_xml_node_recursive(data->xml); + copy_data->xml = copy_xml(data->xml); } te_input_t * new_input_command(HA_Message *msg, crm_data_t *xml) { struct te_data_cib_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; - copy_data->xml = copy_xml_node_recursive(xml); + copy_data->xml = copy_xml(xml); copy_data->msg = ha_msg_copy(msg); return te_input_new(te_data_command, copy_data); } te_input_t * new_input_complete(const char *text, crm_data_t *xml, te_reason_t reason) { struct te_data_complete_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_complete_s)); copy_data = a_copy->data; copy_data->text = text; copy_data->reason = reason; - copy_data->xml = copy_xml_node_recursive(xml); + copy_data->xml = copy_xml(xml); return te_input_new(te_data_complete, copy_data); } te_input_t * new_input_cib(HA_Message *msg, crm_data_t *xml, int call_id, int rc, void *user_data) { struct te_data_cib_s *copy_data = NULL; crm_malloc0(a_copy->data, sizeof(struct te_data_cib_s)); copy_data = a_copy->data; copy_data->rc = rc; copy_data->call_id = call_id; copy_data->user_data = user_data; copy_data->msg = ha_msg_copy(msg); - copy_data->xml = copy_xml_node_recursive(xml); + copy_data->xml = copy_xml(xml); return te_input_new(te_data_cib, copy_data); } te_input_t * new_input_null(const char *origin) { return te_input_new(te_data_null, NULL, origin); } void register_input(te_fsa_input_t input, te_input_t *input_data, gboolean prepend, const char *origin) { input_data->origin = origin; input_data->input = input; crm_debug("%s raised FSA input %d (%s)", origin, input_data->id, input_data->ops->name()); if(prepend) { crm_debug_2("Prepending input"); input_queue = g_list_prepend(input_queue, input_data); } else { input_queue = g_list_append(input_queue, input_data); } G_main_set_trigger(fsa_source); } void register_input_copy(te_fsa_input_t input, te_input_t *input_data, gboolean prepend, const char *origin) { te_input_t *a_copy = input_data->ops->copy(input); crm_debug("%s re-registering FSA input %d (%s/%s)", origin, input_data->id, input_data->ops->name(), input_data->origin); register_input(a_copy, prepend, origin); } te_input_t * get_input(void) { te_input_t* message = g_list_nth_data(input_queue, 0); input_queue = g_list_remove(input_queue, message); return message; } diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c index 7c748de211..389632aae2 100644 --- a/crm/tengine/tengine.c +++ b/crm/tengine/tengine.c @@ -1,951 +1,951 @@ -/* $Id: tengine.c,v 1.77 2005/06/06 09:18:37 zhenh Exp $ */ +/* $Id: tengine.c,v 1.78 2005/06/13 12:24:37 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 gboolean graph_complete = FALSE; GListPtr graph = NULL; IPC_Channel *crm_ch = NULL; uint transition_timeout = 30*1000; /* 30 seconds */ uint default_transition_timeout = 30*1000; /* 30 seconds */ uint next_transition_timeout = 30*1000; /* 30 seconds */ void fire_synapse(synapse_t *synapse); gboolean initiate_action(action_t *action); gboolean confirm_synapse(synapse_t *synapse, int action_id); void check_synapse_triggers(synapse_t *synapse, int action_id); void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data); te_timer_t *transition_timer = NULL; int transition_counter = 1; const te_fsa_state_t te_state_matrix[i_invalid][s_invalid] = { /* s_idle, s_in_transition, s_abort_pending */ /* Got an i_transition */{ s_in_transition, s_abort_pending, s_abort_pending }, /* Got an i_cancel */{ s_idle, s_abort_pending, s_abort_pending }, /* Got an i_complete */{ s_idle, s_idle, s_abort_pending }, /* Got an i_cib_complete*/{ s_idle, s_in_transition, s_idle }, /* Got an i_cib_confirm */{ s_idle, s_in_transition, s_abort_pending }, /* Got an i_cib_notify */{ s_idle, s_in_transition, s_abort_pending } }; te_fsa_state_t te_fsa_state = s_idle; gboolean initialize_graph(void) { remove_cib_op_callback(-1, TRUE); if(transition_timer == NULL) { crm_malloc0(transition_timer, sizeof(te_timer_t)); transition_timer->timeout = 10; transition_timer->source_id = -1; transition_timer->reason = timeout_timeout; transition_timer->action = NULL; } else { stop_te_timer(transition_timer); } while(g_list_length(graph) > 0) { synapse_t *synapse = g_list_nth_data(graph, 0); while(g_list_length(synapse->actions) > 0) { action_t *action = g_list_nth_data(synapse->actions,0); synapse->actions = g_list_remove( synapse->actions, action); if(action->timer->source_id > 0) { crm_debug_3("Removing timer for action: %d", action->id); g_source_remove(action->timer->source_id); } free_xml(action->xml); crm_free(action->timer); crm_free(action); } while(g_list_length(synapse->inputs) > 0) { action_t *action = g_list_nth_data(synapse->inputs, 0); synapse->inputs = g_list_remove(synapse->inputs, action); free_xml(action->xml); crm_free(action); } graph = g_list_remove(graph, synapse); crm_free(synapse); } graph = NULL; return TRUE; } /* * 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(action_t *action, crm_data_t *event, const char *event_node) { const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; const char *this_rsc = NULL; const char *event_rsc; const char *rsc_state; const char *event_action; const char *event_rc; const char *op_status; action_t *match = NULL; int op_status_i = -3; if(event == NULL) { crm_debug_4("Ignoring NULL event"); return -1; } event_action = crm_element_value(event, XML_LRM_ATTR_LASTOP); event_rsc = crm_element_value(event, XML_ATTR_ID); event_rc = crm_element_value(event, XML_LRM_ATTR_RC); rsc_state = crm_element_value(event, XML_LRM_ATTR_RSCSTATE); op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS); if(op_status != NULL) { op_status_i = atoi(op_status); } this_action = crm_element_value(action->xml, XML_LRM_ATTR_TASK); this_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); this_rsc = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); crm_debug_2("matching against: <%s task=%s node=%s rsc_id=%s/>", crm_element_name(action->xml), this_action, this_node, this_rsc); if(safe_str_neq(this_action, event_action)) { crm_debug_2("Action %d : Action mismatch %s", action->id, event_action); } else if(safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_CRM_EVENT)) { if(safe_str_eq(this_action, CRM_OP_FENCE)) { } else if(safe_str_neq(this_node, event_node)) { crm_debug_2("node mismatch: %s", event_node); } else { crm_debug_3(XML_GRAPH_TAG_CRM_EVENT); match = action; } crm_debug_3(XML_GRAPH_TAG_CRM_EVENT); match = action; } else if(safe_str_neq(this_node, event_node)) { crm_debug_2("Action %d : Node mismatch %s", action->id, event_node); } else if(safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_RSC_OP)) { crm_debug_3(XML_GRAPH_TAG_RSC_OP); if(safe_str_eq(this_rsc, event_rsc)) { match = action; } else { crm_debug_2("Action %d : bad rsc (%s) != (%s)", action->id, this_rsc, event_rsc); } } if(match == NULL) { crm_debug_2("didnt match current action"); return -1; } crm_debug_2("matched"); /* stop this event's timer if it had one */ stop_te_timer(match->timer); /* Process OP status */ allow_fail = crm_element_value(match->xml, "allow_fail"); switch(op_status_i) { case LRM_OP_PENDING: /* should never happen */ CRM_DEV_ASSERT(op_status_i != LRM_OP_PENDING); break; case LRM_OP_DONE: break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: crm_warn("Action %s for \"%s\" on %s failed: %s", event_action, event_rsc, event_node, op_status2text(op_status_i)); if(FALSE == crm_is_true(allow_fail)) { send_complete("Action failed", event, te_failed, i_cancel); return -2; } break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_err("Dont know what to do for cancelled ops yet"); break; default: crm_err("Unsupported action result: %d", op_status_i); send_complete("Unsupport action result", event, te_failed, i_cancel); return -2; } te_log_action(LOG_DEBUG, "Action %d confirmed", match->id); match->complete = TRUE; return match->id; } int match_down_event(const char *target, const char *filter, int rc) { const char *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; action_t *match = NULL; slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, crm_data_t *action_args = NULL; if(action->type != action_type_crm) { continue; } this_action = crm_element_value( action->xml, XML_LRM_ATTR_TASK); if(filter != NULL && safe_str_neq(this_action, filter)) { continue; } if(safe_str_eq(this_action, CRM_OP_FENCE)) { action_args = find_xml_node( action->xml, XML_TAG_ATTRS, TRUE); this_node = crm_element_value( action_args, XML_LRM_ATTR_TARGET); } else if(safe_str_eq(this_action, CRM_OP_SHUTDOWN)) { crm_element_value( action->xml, XML_LRM_ATTR_TASK); this_node = crm_element_value( action->xml, XML_LRM_ATTR_TARGET); } else { crm_info("Action %d : Bad action %s", action->id, this_action); continue; } if(safe_str_neq(this_node, target)) { crm_info("Action %d : Node mismatch: %s", action->id, this_node); continue; } match = action; ); if(match != NULL) { break; } ); if(match == NULL) { crm_debug_3("didnt match current action"); return -1; } crm_debug_3("matched"); /* stop this event's timer if it had one */ stop_te_timer(match->timer); /* Process OP status */ switch(rc) { case STONITH_SUCCEEDED: break; case STONITH_CANNOT: case STONITH_TIMEOUT: case STONITH_GENERIC: allow_fail = crm_element_value(match->xml, "allow_fail"); if(FALSE == crm_is_true(allow_fail)) { crm_err("Stonith of %s failed (%d)..." " aborting transition.", target, rc); send_complete("Stonith failed", match->xml, te_failed, i_cancel); return -2; } break; default: crm_err("Unsupported action result: %d", rc); send_complete("Unsupport Stonith result", match->xml, te_failed, i_cancel); return -2; } crm_debug_3("Action %d was successful, looking for next action", match->id); match->complete = TRUE; return match->id; } gboolean process_graph_event(crm_data_t *event, const char *event_node) { int rc = -1; int action_id = -1; int op_status_i = 0; const char *task = NULL; const char *rsc_id = NULL; const char *op_status = NULL; if(event == NULL) { crm_debug("a transition is starting"); process_trigger(action_id); check_for_completion(); return TRUE; } task = crm_element_value(event, XML_LRM_ATTR_LASTOP); rsc_id = crm_element_value(event, XML_ATTR_ID); op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS); if(op_status != NULL) { op_status_i = atoi(op_status); if(op_status_i == -1) { /* just information that the action was sent */ crm_debug("Ignoring TE initiated updates"); return TRUE; } } crm_debug("Processing CIB update: %s %s on %s: %s", task, rsc_id, event_node, op_status2text(op_status_i)); next_transition_timeout = transition_timeout; slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, rc = match_graph_event(action, event ,event_node); if(action_id >= 0 && rc >= 0) { crm_err("Additional match found: %d [%d]", rc, action_id); } else if(rc != -1) { action_id = rc; } ); if(action_id != -1) { break; } ); if(action_id == -1) { /* didnt find a match... * now try any dangling inputs */ slist_iter( synapse, synapse_t, graph, lpc, slist_iter( action, action_t, synapse->inputs, lpc2, rc = match_graph_event(action,event,event_node); if(action_id >=0 && rc >=0 && rc != action_id) { crm_err("Additional match found:" " %d [%d]", rc, action_id); } else if(rc != -1) { action_id = rc; } ); if(action_id != -1) { break; } ); } if(action_id > -1) { crm_log_xml_debug_3(event, "Event found"); } else if(action_id == -2) { crm_log_xml_info(event, "Event failed"); } else { /* unexpected event, trigger a pe-recompute */ /* possibly do this only for certain types of actions */ send_complete("Event not matched", event, te_update, i_cancel); return FALSE; } process_trigger(action_id); check_for_completion(); return TRUE; } void check_for_completion(void) { if(graph_complete) { /* allow some slack until we are pretty sure nothing * else is happening */ crm_info("Transition complete"); send_complete("complete", NULL, te_done, i_complete); } else { /* restart the transition timer again */ crm_debug_3("Transition not yet complete"); transition_timer->timeout = next_transition_timeout; start_te_timer(transition_timer); } } gboolean initiate_action(action_t *action) { gboolean ret = FALSE; gboolean send_command = FALSE; const char *on_node = NULL; const char *id = NULL; const char *task = NULL; const char *timeout = NULL; const char *msg_task = XML_GRAPH_TAG_RSC_OP; on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); id = crm_element_value(action->xml, XML_ATTR_ID); task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); timeout = crm_element_value(action->xml, XML_ATTR_TIMEOUT); if(id == NULL || strlen(id) == 0 || task == NULL || strlen(task) == 0) { /* error */ te_log_action(LOG_ERR, "Failed on corrupted command: %s (id=%s) %s", crm_element_name(action->xml), crm_str(id), crm_str(task)); } else if(action->type == action_type_pseudo){ te_log_action(LOG_INFO, "Executing pseudo-event (%d): " "%s on %s", action->id, task, on_node); action->complete = TRUE; process_trigger(action->id); ret = TRUE; } else if(action->type == action_type_crm && safe_str_eq(task, CRM_OP_FENCE)){ crm_data_t *action_args = find_xml_node( action->xml, XML_TAG_ATTRS, TRUE); const char *uuid = NULL; const char *target = NULL; const char *name = NULL; stonith_ops_t * st_op = NULL; xml_child_iter( action_args, nvpair, XML_CIB_TAG_NVPAIR, name = crm_element_value(nvpair, XML_NVPAIR_ATTR_NAME); if(safe_str_eq(name, XML_LRM_ATTR_TARGET)) { target = crm_element_value( nvpair, XML_NVPAIR_ATTR_VALUE); } else if(safe_str_eq(name, XML_LRM_ATTR_TARGET_UUID)) { uuid = crm_element_value( nvpair, XML_NVPAIR_ATTR_VALUE); } ); CRM_DEV_ASSERT(target != NULL); CRM_DEV_ASSERT(uuid != NULL); te_log_action(LOG_INFO,"Executing fencing operation (%s) on %s", id, target); #ifdef TESTING ret = TRUE; action->complete = TRUE; process_trigger(action->id); return TRUE; #endif crm_malloc0(st_op, sizeof(stonith_ops_t)); st_op->optype = RESET; st_op->timeout = crm_atoi(timeout, "10000"); /* ten seconds */ st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); if(stonithd_input_IPC_channel() == NULL) { crm_err("Cannot fence %s - stonith not available", target); } else if (ST_OK == stonithd_node_fence( st_op )) { ret = TRUE; } } else if(on_node == NULL || strlen(on_node) == 0) { /* error */ te_log_action(LOG_ERR, "Failed on corrupted command: %s (id=%s) %s on %s", crm_element_name(action->xml), crm_str(id), crm_str(task), crm_str(on_node)); } else if(action->type == action_type_crm){ te_log_action(LOG_INFO, "Executing crm-event (%s): %s on %s", id, task, on_node); #ifdef TESTING action->complete = TRUE; process_trigger(action->id); return TRUE; #endif /* action->complete = TRUE; */ msg_task = task; send_command = TRUE; } else if(action->type == action_type_rsc){ /* 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 */ #ifdef TESTING cib_action_update(action, LRM_OP_PENDING); return TRUE; #endif if(safe_str_neq(task, CRMD_ACTION_STOP)) { cib_action_update(action, LRM_OP_PENDING); } else { cib_action_updated(NULL, 0, cib_ok, NULL, action); } ret = TRUE; } else { te_log_action(LOG_ERR, "Failed on unsupported command type: " "%s, %s (id=%s) on %s", crm_element_name(action->xml), task, id, on_node); } if(send_command) { HA_Message *cmd = NULL; char *counter = crm_itoa(transition_counter); cmd = create_request(msg_task, NULL, on_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL); ha_msg_add(cmd, "transition_id", crm_str(counter)); ret = send_ipc_message(crm_ch, cmd); crm_free(counter); if(ret && action->timeout > 0) { crm_debug_3("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } } return ret; } gboolean cib_action_update(action_t *action, int status) { char *code = NULL; crm_data_t *fragment = NULL; crm_data_t *state = NULL; crm_data_t *rsc = NULL; crm_data_t *xml_op = NULL; enum cib_errors rc = cib_ok; const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK); const char *rsc_id = crm_element_value(action->xml, XML_LRM_ATTR_RSCID); const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID); - int call_options = cib_inhibit_notify|cib_quorum_override; + int call_options = cib_quorum_override; if(status == LRM_OP_TIMEOUT) { if(crm_element_value(action->xml, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", crm_element_name(action->xml), task, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", crm_element_name(action->xml), task, target); } #ifdef TESTING /* turn the "pending" notification into a "op completed" notification * when testing... exercises more code this way. */ } else if(status == LRM_OP_PENDING) { status = LRM_OP_DONE; #endif } code = crm_itoa(status); /* update the CIB */ fragment = NULL; state = create_xml_node(NULL, XML_CIB_TAG_STATE); set_xml_property_copy(state, XML_ATTR_UUID, target_uuid); set_xml_property_copy(state, XML_ATTR_UNAME, target); rsc = create_xml_node(state, XML_CIB_TAG_LRM); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES); rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE); xml_op = create_xml_node(rsc,XML_LRM_TAG_RSC_OP); set_xml_property_copy(rsc, XML_ATTR_ID, rsc_id); set_xml_property_copy(xml_op, XML_ATTR_ID, task); if(action->interval > 0) { char *op_id = generate_op_key(rsc_id, task, action->interval); set_xml_property_copy(xml_op, XML_ATTR_ID, op_id); crm_free(op_id); } set_xml_property_copy(xml_op, XML_LRM_ATTR_TASK, task); set_xml_property_copy(rsc, XML_LRM_ATTR_RSCSTATE, get_rsc_state(task, status)); set_xml_property_copy(rsc, XML_LRM_ATTR_OPSTATUS, code); set_xml_property_copy(rsc, XML_LRM_ATTR_RC, code); set_xml_property_copy(rsc, XML_LRM_ATTR_LASTOP, task); set_xml_property_copy(xml_op, XML_LRM_ATTR_OPSTATUS, code); set_xml_property_copy(xml_op, XML_LRM_ATTR_RC, code); set_xml_property_copy(xml_op, "origin", __FUNCTION__); set_node_tstamp(xml_op); crm_free(code); fragment = create_cib_fragment(state, NULL); 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); #ifndef TESTING rc = te_cib_conn->cmds->modify( te_cib_conn, XML_CIB_TAG_STATUS, fragment, NULL, call_options); crm_debug("Updating CIB with %s action %d: %s %s on %s (call_id=%d)", op_status2text(status), action->id, task, rsc_id, target, rc); if(status == LRM_OP_PENDING) { crm_debug_2("Waiting for callback id: %d", rc); add_cib_op_callback(rc, FALSE, action, cib_action_updated); } #else fprintf(stderr, "Initiating action %d: %s %s on %s\n", action->id, task, rsc_id, target); call_options = 0; { HA_Message *cmd = ha_msg_new(11); ha_msg_add(cmd, F_TYPE, T_CRM); ha_msg_add(cmd, F_CRM_VERSION, CRM_VERSION); ha_msg_add(cmd, F_CRM_MSG_TYPE, XML_ATTR_REQUEST); ha_msg_add(cmd, F_CRM_TASK, CRM_OP_EVENTCC); ha_msg_add(cmd, F_CRM_SYS_TO, CRM_SYSTEM_TENGINE); ha_msg_add(cmd, F_CRM_SYS_FROM, CRM_SYSTEM_TENGINE); ha_msg_addstruct(cmd, crm_element_name(state), state); send_ipc_message(crm_ch, cmd); } #endif free_xml(fragment); free_xml(state); if(rc < cib_ok) { return FALSE; } return TRUE; } void cib_action_updated( const HA_Message *msg, int call_id, int rc, crm_data_t *output, void *user_data) { HA_Message *cmd = NULL; crm_data_t *rsc_op = NULL; const char *task = NULL; const char *rsc_id = NULL; const char *on_node = NULL; action_t *action = user_data; char *counter = crm_itoa(transition_counter); CRM_DEV_ASSERT(action != NULL); if(crm_assert_failed) { return; } CRM_DEV_ASSERT(action->xml != NULL); if(crm_assert_failed) { return; } rsc_op = action->xml; task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK); rsc_id = crm_element_value(rsc_op, XML_LRM_ATTR_RSCID); on_node = crm_element_value(rsc_op, XML_LRM_ATTR_TARGET); if(rc < cib_ok) { crm_err("Update for action %d: %s %s on %s FAILED", action->id, task, rsc_id, on_node); send_complete(cib_error2string(rc), output, te_failed, i_cancel); return; } if(te_fsa_state != s_in_transition) { int pending_updates = num_cib_op_callbacks(); if(pending_updates == 0) { send_complete("CIB update queue empty", output, te_done, i_cib_complete); } else { crm_debug("Still waiting on %d callbacks", pending_updates); } crm_debug("Not executing action: Not in a transition: %d", te_fsa_state); return; } crm_info("Initiating action %d: %s %s on %s", action->id, task, rsc_id, on_node); if(rsc_op != NULL) { crm_log_xml_debug_2(rsc_op, "Performing"); } cmd = create_request( task, rsc_op, on_node, CRM_SYSTEM_LRMD,CRM_SYSTEM_TENGINE,NULL); ha_msg_add(cmd, "transition_id", counter); crm_free(counter); #ifndef TESTING send_ipc_message(crm_ch, cmd); #else crm_log_message(LOG_INFO, cmd); #endif if(action->timeout > 0) { crm_debug_3("Setting timer for action %d",action->id); action->timer->reason = timeout_action_warn; start_te_timer(action->timer); } } gboolean initiate_transition(void) { crm_info("Initating transition"); process_graph_event(NULL, NULL); return TRUE; } void check_synapse_triggers(synapse_t *synapse, int action_id) { synapse->triggers_complete = TRUE; if(synapse->confirmed) { crm_debug_3("Skipping confirmed synapse %d", synapse->id); return; } else if(synapse->complete == FALSE) { crm_debug_3("Checking pre-reqs for %d", synapse->id); /* lookup prereqs */ slist_iter( prereq, action_t, synapse->inputs, lpc, crm_debug_3("Processing input %d", prereq->id); if(prereq->id == action_id) { crm_debug_3("Marking input %d complete", action_id); prereq->complete = TRUE; } else if(prereq->complete == FALSE) { crm_debug_3("Inputs for synapse %d not satisfied", synapse->id); synapse->triggers_complete = FALSE; } ); } } void fire_synapse(synapse_t *synapse) { if(synapse == NULL) { crm_err("Synapse was NULL!"); return; } crm_debug_3("Checking if synapse %d needs to be fired", synapse->id); if(synapse->complete) { crm_debug_3("Skipping complete synapse %d", synapse->id); return; } else if(synapse->triggers_complete == FALSE) { crm_debug_3("Synapse %d not yet satisfied", synapse->id); return; } crm_debug("All inputs for synapse %d satisfied... invoking actions", synapse->id); synapse->complete = TRUE; slist_iter( action, action_t, synapse->actions, lpc, /* allow some leway */ unsigned tmp_time = 2 * action->timeout; gboolean passed = FALSE; action->invoked = TRUE; /* Invoke the action and start the timer */ passed = initiate_action(action); if(passed == FALSE) { crm_err("Failed initiating <%s id=%d> in synapse %d", crm_element_name(action->xml), action->id, synapse->id); send_complete("Action init failed", action->xml, te_failed, i_cancel); return; } if(tmp_time > next_transition_timeout) { next_transition_timeout = tmp_time; } ); crm_debug("Synapse %d complete", synapse->id); } gboolean confirm_synapse(synapse_t *synapse, int action_id) { gboolean complete = TRUE; synapse->confirmed = TRUE; slist_iter( action, action_t, synapse->actions, lpc, if(action->complete == FALSE) { complete = FALSE; synapse->confirmed = FALSE; crm_debug_3("Found an incomplete action" " - transition not complete"); break; } ); if(complete) { crm_debug("Synapse %d complete (action=%d)", synapse->id, action_id); } return complete; } void process_trigger(int action_id) { graph_complete = TRUE; crm_debug_3("Processing trigger from action %d", action_id); /* something happened, stop the timer and start it again at the end */ stop_te_timer(transition_timer); slist_iter( synapse, synapse_t, graph, lpc, if(synapse->confirmed) { crm_debug_3("Skipping confirmed synapse %d", synapse->id); continue; } check_synapse_triggers(synapse, action_id); fire_synapse(synapse); if(graph == NULL) { crm_err("Trigger processing aborted after failed synapse"); break; } crm_debug_3("Checking if %d is confirmed", synapse->id); if(synapse->complete == FALSE) { crm_debug_3("Found an incomplete synapse" " - transition not complete"); /* indicate that the transition is not yet complete */ graph_complete = FALSE; } else if(synapse->confirmed == FALSE) { gboolean confirmed = confirm_synapse(synapse,action_id); graph_complete = graph_complete && confirmed; } crm_debug_3("%d is %s", synapse->id, synapse->confirmed?"confirmed":synapse->complete?"complete":"pending"); ); } diff --git a/crm/tengine/unpack.c b/crm/tengine/unpack.c index fc45226bcb..f220169929 100644 --- a/crm/tengine/unpack.c +++ b/crm/tengine/unpack.c @@ -1,379 +1,379 @@ -/* $Id: unpack.c,v 1.35 2005/05/27 15:06:40 andrew Exp $ */ +/* $Id: unpack.c,v 1.36 2005/06/13 12:24:37 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 cib_t *te_cib_conn = NULL; action_t* unpack_action(crm_data_t *xml_action); crm_data_t *create_shutdown_event(const char *node, int op_status); void set_timer_value(te_timer_t *timer, const char *time, int time_default); extern int transition_counter; void set_timer_value(te_timer_t *timer, const char *time, int time_default) { int tmp_time; if(timer == NULL) { return; } timer->timeout = time_default; tmp_time = crm_get_msec(time); if(tmp_time > 0) { timer->timeout = tmp_time; } } gboolean unpack_graph(crm_data_t *xml_graph) { /* timeout = crm_get_msec(time); transition_timeout = transition_timer->timeout; time = crm_element_value(xml_graph, "transition_fuzz"); transition_counter = crm_atoi(t_id, "-1"); crm_info("Beginning transition %d : timeout set to %dms", transition_counter, transition_timer->timeout); xml_child_iter( xml_graph, synapse, "synapse", synapse_t *new_synapse = NULL; crm_debug_3("looking in synapse %s", crm_element_value(synapse, XML_ATTR_ID)); crm_malloc0(new_synapse, sizeof(synapse_t)); new_synapse->id = num_synapses++; new_synapse->complete = FALSE; new_synapse->confirmed = FALSE; new_synapse->actions = NULL; new_synapse->inputs = NULL; graph = g_list_append(graph, new_synapse); crm_debug_3("look for actions in synapse %s", crm_element_value(synapse, XML_ATTR_ID)); xml_child_iter( synapse, actions, "action_set", xml_child_iter( actions, action, NULL, action_t *new_action = unpack_action(action); num_actions++; if(new_action == NULL) { continue; } crm_debug_3("Adding action %d to synapse %d", new_action->id, new_synapse->id); new_synapse->actions = g_list_append( new_synapse->actions, new_action); ); ); crm_debug_3("look for inputs in synapse %s", crm_element_value(synapse, XML_ATTR_ID)); xml_child_iter( synapse, inputs, "inputs", xml_child_iter( inputs, trigger, NULL, xml_child_iter( trigger, input, NULL, action_t *new_input = unpack_action(input); if(new_input == NULL) { continue; } crm_debug_3("Adding input %d to synapse %d", new_input->id, new_synapse->id); new_synapse->inputs = g_list_append( new_synapse->inputs, new_input); ); ); ); ); crm_info("Unpacked %d actions in %d synapses", num_actions, num_synapses); if(num_actions > 0) { return TRUE; } else { /* indicate to caller that there's nothing to do */ return FALSE; } } action_t* unpack_action(crm_data_t *xml_action) { const char *tmp = crm_element_value(xml_action, XML_ATTR_ID); action_t *action = NULL; crm_data_t *action_copy = NULL; crm_data_t *nvpair_list = NULL; if(tmp == NULL) { crm_err("Actions must have an id!"); crm_log_xml_debug_3(xml_action, "Action with missing id"); return NULL; } - action_copy = copy_xml_node_recursive(xml_action); + action_copy = copy_xml(xml_action); crm_malloc0(action, sizeof(action_t)); if(action == NULL) { return NULL; } action->id = atoi(tmp); action->timeout = 0; action->interval = 0; action->timer = NULL; action->invoked = FALSE; action->complete = FALSE; action->can_fail = FALSE; action->type = action_type_rsc; action->xml = action_copy; if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_RSC_OP)) { action->type = action_type_rsc; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_PSEUDO_EVENT)) { action->type = action_type_pseudo; } else if(safe_str_eq(crm_element_name(action_copy), XML_GRAPH_TAG_CRM_EVENT)) { action->type = action_type_crm; } nvpair_list = find_xml_node(action_copy, XML_TAG_ATTRS, FALSE); if(nvpair_list == NULL) { crm_debug_2("No attributes in %s", crm_element_name(action_copy)); } xml_child_iter( nvpair_list, node_iter, XML_CIB_TAG_NVPAIR, const char *key = crm_element_value( node_iter, XML_NVPAIR_ATTR_NAME); const char *value = crm_element_value( node_iter, XML_NVPAIR_ATTR_VALUE); if(safe_str_eq(key, "timeout")) { action->timeout = crm_get_msec(value); } else if(safe_str_eq(key, "interval")) { action->interval = crm_get_msec(value); } ); crm_debug_3("Action %d has timer set to %dms", action->id, action->timeout); crm_malloc0(action->timer, sizeof(te_timer_t)); action->timer->timeout = 2 * action->timeout; action->timer->source_id = -1; action->timer->reason = timeout_action; action->timer->action = action; tmp = crm_element_value(action_copy, "can_fail"); crm_str_to_boolean(tmp, &(action->can_fail)); return action; } gboolean extract_event(crm_data_t *msg) { const char *event_node = NULL; struct abort_blob_s { const char *text; crm_data_t *update; te_reason_t reason; }; struct abort_blob_s blob = { NULL, NULL, 0 }; blob.reason = te_update; /* [cib fragment] ... */ crm_debug_4("Extracting event from %s", crm_element_name(msg)); xml_child_iter( msg, node_state, XML_CIB_TAG_STATE, 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); blob.update = node_state; event_node = crm_element_value(node_state, XML_ATTR_UNAME); crm_log_xml_debug_3(node_state,"Processing"); if(crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN) != NULL) { blob.text = "Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute"; break; /* is this still required??? */ } else if(crm_element_value(node_state, CRM_OP_FENCE) != NULL) { /* node marked for STONITH * possibly by us when a shutdown timed out */ int action_id = -1; crm_debug_3("Checking for STONITH"); event_node = crm_element_value(node_state, XML_ATTR_UNAME); action_id = match_down_event( event_node, CRM_OP_SHUTDOWN, LRM_OP_DONE); if(action_id < 0) { blob.text="Stonith/shutdown event not matched"; break; } else { process_trigger(action_id); check_for_completion(); } /* END: is this still required??? */ } resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); resources = find_xml_node( resources, XML_LRM_TAG_RESOURCES, FALSE); /* * node state update... possibly from a shutdown we requested */ crm_debug_3("Processing state update"); if(safe_str_eq(ccm_state, XML_BOOLEAN_FALSE) || safe_str_eq(crmd_state, CRMD_JOINSTATE_DOWN)) { int action_id = -1; crm_debug_3("A shutdown we requested?"); action_id = match_down_event( event_node, NULL, LRM_OP_DONE); if(action_id >= 0) { process_trigger(action_id); check_for_completion(); } else { blob.text="Stonith/shutdown event not matched"; break; } } if(resources != NULL) { /* LRM resource update... */ xml_child_iter( resources, child, NULL, crm_log_xml_debug_3( child,"Processing LRM resource update"); if(!process_graph_event(child, event_node)) { /* the transition has already been * aborted and with better details */ return TRUE; } ); } ); if(blob.text != NULL) { send_complete(blob.text, blob.update, blob.reason, i_cancel); } return TRUE; } crm_data_t* create_shutdown_event(const char *node, int op_status) { crm_data_t *event = create_xml_node(NULL, XML_CIB_TAG_STATE); char *code = crm_itoa(op_status); set_xml_property_copy(event, XML_LRM_ATTR_TARGET, node); /* event_rsc = set_xml_property_copy(event, XML_ATTR_ID); */ set_xml_property_copy(event, XML_LRM_ATTR_RC, "0"); set_xml_property_copy( event, XML_LRM_ATTR_LASTOP, XML_CIB_ATTR_SHUTDOWN); set_xml_property_copy( event, XML_LRM_ATTR_RSCSTATE, CRMD_ACTION_GENERIC_OK); set_xml_property_copy(event, XML_LRM_ATTR_OPSTATUS, code); crm_free(code); return event; } diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c index af6256f06c..5af400a597 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,434 +1,434 @@ -/* $Id: utils.c,v 1.32 2005/06/03 14:05:41 andrew Exp $ */ +/* $Id: utils.c,v 1.33 2005/06/13 12:24:37 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 extern cib_t *te_cib_conn; extern int global_transition_timer; void print_input(const char *prefix, action_t *input, gboolean to_file); void print_action(const char *prefix, action_t *action, gboolean to_file); gboolean timer_callback(gpointer data); void send_complete(const char *text, crm_data_t *msg, te_reason_t reason, te_fsa_input_t input) { HA_Message *cmd = NULL; const char *op = CRM_OP_TEABORT; static te_reason_t last_reason = te_done; static crm_data_t *last_msg = NULL; static const char *last_text = NULL; te_fsa_state_t last_state = te_fsa_state; te_fsa_state = te_state_matrix[input][te_fsa_state]; if(te_fsa_state == s_abort_pending && num_cib_op_callbacks() == 0) { te_fsa_state = te_state_matrix[i_cib_complete][te_fsa_state]; } if(te_fsa_state != s_idle && input != i_cib_complete) { if(last_msg) { free_xml(last_msg); } last_msg = NULL; if(msg != NULL) { - last_msg = copy_xml_node_recursive(msg); + last_msg = copy_xml(msg); } last_text = text; last_reason = reason; crm_info("CIB updates are pending. Delay until they complete."); return; } else if(te_fsa_state != s_idle) { crm_err("Delaying \"%s\" notification until we are idle.",text); return; } else if(input == i_cib_complete) { msg = last_msg; text = last_text; reason = last_reason; } CRM_DEV_ASSERT(num_cib_op_callbacks() == 0); switch(reason) { case te_update: te_log_action(LOG_DEBUG, "Transition status: %s by CIB update: %s", last_state!=s_idle?"Aborted":"Triggered", text); if(msg != NULL) { if(safe_str_eq(crm_element_name(msg), XML_TAG_CIB)) { crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, msg); crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB); crm_debug("Cause:" " full CIB replace/update"); copy_in_properties(generation, msg); crm_log_xml_debug(generation, "[generation]"); crm_log_xml_debug(status, "[in ]"); free_xml(generation); } else { crm_log_xml_debug(msg, "Cause"); } } print_state(LOG_DEBUG); break; case te_halt: te_log_action(LOG_INFO,"Transition status: Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TECOMPLETE; break; case te_abort_confirmed: te_log_action(LOG_INFO, "Transition status: Confirmed Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TEABORTED; break; case te_abort: te_log_action(LOG_INFO,"Transition status: Stopped%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); break; case te_done: te_log_action(LOG_INFO, "Transition status: Complete%s%s", text?": ":"", text?text:""); print_state(LOG_DEBUG); op = CRM_OP_TECOMPLETE; break; case te_timeout: te_log_action(LOG_ERR, "Transition status: Timed out after %dms", transition_timer->timeout); print_state(LOG_WARNING); op = CRM_OP_TETIMEOUT; break; case te_failed: te_log_action(LOG_ERR, "Transition status: Aborted by failed action: %s", text); crm_log_xml_debug(msg, "Cause"); print_state(LOG_WARNING); break; } initialize_graph(); cmd = create_request( op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); if(text != NULL) { ha_msg_add(cmd, "message", text); } free_xml(last_msg); #ifdef TESTING if(reason == te_done) { crm_log_message(LOG_INFO, cmd); } else { crm_log_message(LOG_ERR, cmd); } g_main_quit(mainloop); return; #else send_ipc_message(crm_ch, cmd); #endif #if 0 if(is_ipc_empty(crm_ch) && is_ipc_empty(te_cib_conn->cmds->channel(te_cib_conn)) ) { static gboolean mem_needs_init = TRUE; if(mem_needs_init) { crm_debug("Reached a stable point:" " reseting memory usage stats to zero"); crm_zero_mem_stats(NULL); mem_needs_init = FALSE; } else { crm_err("Reached a stable point:" " checking memory usage"); crm_mem_stats(NULL); } } #endif } void print_state(int log_level) { if(graph == NULL && log_level > LOG_DEBUG) { do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "###########"); do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "\tEmpty transition graph"); do_crm_log(LOG_DEBUG, __FILE__, __FUNCTION__, "###########"); return; } do_crm_log(log_level, __FILE__, __FUNCTION__, "###########"); slist_iter( synapse, synapse_t, graph, lpc, do_crm_log(log_level, __FILE__, __FUNCTION__, "Synapse %d %s", synapse->id, synapse->confirmed?"was confirmed":synapse->complete?"was executed":"is pending"); if(synapse->confirmed == FALSE) { slist_iter( action, action_t, synapse->actions, lpc2, print_action("\t", action, log_level); ); } if(synapse->complete == FALSE) { slist_iter( input, action_t, synapse->inputs, lpc2, print_input("\t", input, log_level); ); } ); do_crm_log(log_level, __FILE__, __FUNCTION__, "###########"); } void print_input(const char *prefix, action_t *input, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Input %d] %s (%s)", prefix, input->id, input->complete?"Satisfied":"Pending", actiontype2text(input->type)); if(input->complete == FALSE) { crm_log_xml((unsigned)log_level, "\t Raw input", input->xml); } } void print_action(const char *prefix, action_t *action, int log_level) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Action %d] %s (%s fail)", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight":"Pending", action->can_fail?"can":"cannot"); switch(action->type) { case action_type_pseudo: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tPseudo Op: %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK)); break; case action_type_rsc: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tResource Op: %s/%s on %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_RSCID), crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET)); break; case action_type_crm: do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\tCRM Op: %s on %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK), crm_element_value( action->xml, XML_LRM_ATTR_TARGET)); break; } if(action->timeout > 0 || action->timer->source_id > 0) { do_crm_log(log_level, __FILE__, __FUNCTION__, "%s\ttimeout=%d, timer=%d", prefix, action->timeout, action->timer->source_id); } if(action->complete == FALSE) { crm_log_xml(LOG_DEBUG_2, "\tRaw action", action->xml); } } gboolean timer_callback(gpointer data) { te_timer_t *timer = NULL; if(data == NULL) { crm_err("Timer popped with no data"); return FALSE; } timer = (te_timer_t*)data; if(timer->source_id > 0) { g_source_remove(timer->source_id); } timer->source_id = -1; crm_err("Timer popped in state=%d", te_fsa_state); if(te_fsa_state != s_in_transition) { crm_debug("Ignoring timeout while not in transition"); return TRUE; } else if(timer->reason == timeout_timeout) { /* global timeout - abort the transition */ crm_warn("Transition timeout reached..." " marking transition complete."); crm_warn("Some actions may not have been executed."); send_complete(XML_ATTR_TIMEOUT, NULL, te_timeout, i_cancel); return TRUE; } else if(timer->action == NULL) { crm_err("Action not present!"); return FALSE; } else if(timer->reason == timeout_action_warn) { crm_warn("Action %d is taking more than 2x its timeout (%d)", timer->action->id, timer->action->timeout); crm_log_xml_debug(timer->action->xml, "Slow action"); return TRUE; } else { /* fail the action * - which may or may not abort the transition */ /* TODO: send a cancel notice to the LRM */ /* TODO: use the ack from above to update the CIB */ return cib_action_update(timer->action, LRM_OP_TIMEOUT); } } gboolean start_te_timer(te_timer_t *timer) { if(((int)timer->source_id) < 0 && timer->timeout > 0) { timer->source_id = Gmain_timeout_add( timer->timeout, timer_callback, (void*)timer); return TRUE; } else if(timer->timeout < 0) { crm_err("Tried to start timer with -ve period"); } else { crm_debug_3("#!!#!!# Timer already running (%d)", timer->source_id); } return FALSE; } gboolean stop_te_timer(te_timer_t *timer) { if(timer == NULL) { return FALSE; } if(((int)timer->source_id) > 0) { g_source_remove(timer->source_id); timer->source_id = -2; } else { return FALSE; } return TRUE; } const char * actiontype2text(action_type_e type) { switch(type) { case action_type_pseudo: return "pseduo"; case action_type_rsc: return "rsc"; case action_type_crm: return "crm"; } return ""; } const char * get_rsc_state(const char *task, op_status_t status) { if(safe_str_eq(CRMD_ACTION_START, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_START_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STARTED; } else { return CRMD_ACTION_START_FAIL; } } else if(safe_str_eq(CRMD_ACTION_STOP, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_STOP_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_STOPPED; } else { return CRMD_ACTION_STOP_FAIL; } } else { if(safe_str_eq(CRMD_ACTION_MON, task)) { if(status == LRM_OP_PENDING) { return CRMD_ACTION_MON_PENDING; } else if(status == LRM_OP_DONE) { return CRMD_ACTION_MON_OK; } else { return CRMD_ACTION_MON_FAIL; } } else { const char *rsc_state = NULL; if(status == LRM_OP_PENDING) { rsc_state = CRMD_ACTION_GENERIC_PENDING; } else if(status == LRM_OP_DONE) { rsc_state = CRMD_ACTION_GENERIC_OK; } else { rsc_state = CRMD_ACTION_GENERIC_FAIL; } crm_warn("Using status \"%s\" for op \"%s\"..." " this is still in the experimental stage.", rsc_state, task); return rsc_state; } } }