diff --git a/crm/tengine/callbacks.c b/crm/tengine/callbacks.c index 02c4b6b472..77a2994fd6 100644 --- a/crm/tengine/callbacks.c +++ b/crm/tengine/callbacks.c @@ -1,292 +1,293 @@ -/* $Id: callbacks.c,v 1.21 2005/04/06 14:38:14 andrew Exp $ */ +/* $Id: callbacks.c,v 1.22 2005/04/07 14:00:04 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_xml_verbose(update, "Processing update"); if (MSG_LOG) { struct stat buf; if(stat(DEVEL_DIR, &buf) != 0) { cl_perror("Stat of %s failed... exiting", DEVEL_DIR); exit(100); } } if(op == NULL) { crm_err( "Illegal CIB update, the operation must be specified"); - send_abort("Illegal update", update); + send_complete("Illegal update", update, te_update); done = TRUE; } else if(strcmp(op, CRM_OP_CIB_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_abort("Erase event", update); + send_complete("Erase event", update, te_update); 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 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) { /* these are always unexpected, trigger the PE */ - send_abort("Non-update change", update); + send_complete("Non-update change", update, te_update); done = TRUE; } else if(strcmp(op, CRM_OP_CIB_UPDATE) != 0) { crm_verbose("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_abort("Unexpected status update", update); + send_complete("Unexpected status update", update, te_update); } } 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_abort("Non-status update", update); + send_complete("Non-status update", update, te_update); } else { crm_warn("Ignoring update confirmation for %s object", type); } 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_DEV, 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_devel("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_verbose("Bad sys-to %s", crm_str(sys_to)); return FALSE; } else if(strcmp(op, CRM_OP_TRANSITION) == 0) { crm_trace("Initializing graph..."); initialize_graph(); crm_trace("Unpacking graph..."); unpack_graph(xml_data); crm_debug("Initiating transition..."); in_transition = TRUE; if(initiate_transition() == FALSE) { /* nothing to be done.. means we're done. */ crm_info("No actions to be taken..." " transition compelte."); } crm_trace("Processing complete..."); } else if(strcmp(op, CRM_OP_TEABORT) == 0) { initialize_graph(); } else if(strcmp(op, CRM_OP_QUIT) == 0) { crm_info("Received quit message, terminating"); exit(0); } else if(in_transition == FALSE) { crm_info("Received event_cc while not in a transition..." " Poking the Policy Engine"); - send_abort("Initiate a transition", NULL); + send_complete("Initiate a transition", NULL, te_update); #ifdef TESTING } else if(strcmp(op, CRM_OP_EVENTCC) == 0) { crm_trace("Processing %s...", CRM_OP_EVENTCC); if(extract_event(msg) == FALSE) { - send_abort("ttest loopback", msg); + send_complete("ttest loopback", msg, te_failed); } #endif } crm_devel("finished processing message"); print_state(LOG_DEV); 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); /* this will mark the event complete if a match is found */ action_id = match_down_event(op->node_name, XML_CIB_ATTR_STONITH, 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_none); if(action_id < 0) { - send_abort("Stonith not matched", update); + send_complete("Stonith not matched", update, te_update); } else if(rc != cib_ok) { - send_abort("Couldnt update CIB after stonith", update); + send_complete("Couldnt update CIB after stonith", + update, te_failed); } else { process_trigger(action_id); check_for_completion(); } free_xml(update); } else { - send_abort("Fencing op failed", NULL); + send_complete("Fencing op failed", NULL, te_failed); } } 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_verbose("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { return FALSE; } return TRUE; } diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c index 7a5e0a8655..a83cbfec28 100644 --- a/crm/tengine/tengine.c +++ b/crm/tengine/tengine.c @@ -1,771 +1,776 @@ -/* $Id: tengine.c,v 1.57 2005/04/05 15:02:49 andrew Exp $ */ +/* $Id: tengine.c,v 1.58 2005/04/07 14:00:05 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 transition_fuzz_timeout = 0; 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); gboolean in_transition = FALSE; te_timer_t *transition_timer = NULL; te_timer_t *transition_fuzz_timer = NULL; int transition_counter = 1; gboolean initialize_graph(void) { if(transition_timer == NULL) { crm_malloc(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); } if(transition_fuzz_timer == NULL) { crm_malloc(transition_fuzz_timer, sizeof(te_timer_t)); transition_fuzz_timer->timeout = 10; transition_fuzz_timer->source_id = -1; transition_fuzz_timer->reason = timeout_fuzz; transition_fuzz_timer->action = NULL; } else { stop_te_timer(transition_fuzz_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_devel("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 *allow_fail = NULL; const char *this_action = NULL; const char *this_node = NULL; const char *this_rsc = NULL; const char *event_node; 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_trace("Ignoring NULL event"); return -1; } event_node = crm_element_value(event, XML_LRM_ATTR_TARGET); 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_devel("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_info("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, XML_CIB_ATTR_STONITH)) { } else if(safe_str_neq(this_node, event_node)) { crm_devel("node mismatch: %s", event_node); } else { crm_devel(XML_GRAPH_TAG_CRM_EVENT); match = action; } crm_devel(XML_GRAPH_TAG_CRM_EVENT); match = action; } else if(safe_str_neq(this_node, event_node)) { crm_info("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_devel(XML_GRAPH_TAG_RSC_OP); if(safe_str_eq(this_rsc, event_rsc)) { match = action; } else { crm_info("Action %d : bad rsc (%s) != (%s)", action->id, this_rsc, event_rsc); } } else { crm_devel("no match"); } if(match == NULL) { crm_devel("didnt match current action"); return -1; } crm_devel("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_DONE: break; case LRM_OP_ERROR: case LRM_OP_TIMEOUT: case LRM_OP_NOTSUPPORTED: if(FALSE == crm_is_true(allow_fail)) { crm_err("Action %s for \"%s\" on %s resulted in" " failure (%d)... aborting transition.", event_action, event_rsc, event_node, op_status_i); - send_abort("Action failed", match->xml); + send_complete( + "Action failed", match->xml, te_failed); return -2; } break; case LRM_OP_CANCELLED: /* do nothing?? */ crm_warn("Dont know what to do for cancelled ops yet"); break; default: crm_err("Unsupported action result: %d", op_status_i); - send_abort("Unsupport action result", match->xml); + send_complete("Unsupport action result", + match->xml, te_failed); return -2; } crm_devel("Action %d was successful, looking for next action", 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, XML_CIB_ATTR_STONITH)) { 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_devel("didnt match current action"); return -1; } crm_devel("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_abort("Action failed", match->xml); + send_complete("Stonith failed", + match->xml, te_failed); return -2; } break; default: crm_err("Unsupported action result: %d", rc); - send_abort("Unsupport action result", match->xml); + send_complete("Unsupport Stonith result", + match->xml, te_failed); return -2; } crm_devel("Action %d was successful, looking for next action", match->id); match->complete = TRUE; return match->id; } gboolean process_graph_event(crm_data_t *event) { int action_id = -1; int op_status_i = 0; const char *op_status = NULL; if(event != NULL) { op_status = crm_element_value(event, XML_LRM_ATTR_OPSTATUS); } next_transition_timeout = transition_timeout; if(op_status != NULL) { op_status_i = atoi(op_status); } if(op_status_i == -1) { /* just information that the action was sent */ crm_trace("Ignoring TE initiated updates"); return TRUE; } slist_iter( synapse, synapse_t, graph, lpc, /* lookup event */ slist_iter( action, action_t, synapse->actions, lpc2, action_id = match_graph_event(action, event); if(action_id != -1) { break; } ); if(action_id != -1) { break; } ); if(event == NULL) { crm_debug("a transition is starting"); } else if(action_id > -1) { crm_xml_devel(event, "Event found"); } else if(action_id == -2) { crm_xml_info(event, "Event found but failed"); } else { /* unexpected event, trigger a pe-recompute */ /* possibly do this only for certain types of actions */ - send_abort("Event not matched", event); + send_complete("Event not matched", event, te_update); 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"); if(transition_fuzz_timer->timeout > 0) { crm_info("Allowing the system to stabilize for %d ms" " before S_IDLE transition", transition_fuzz_timer->timeout); start_te_timer(transition_fuzz_timer); } else { - send_success("complete"); + send_complete("complete", NULL, te_done); } } else { /* restart the transition timer again */ crm_devel("Transition not yet complete"); print_state(LOG_DEV); transition_timer->timeout = next_transition_timeout; start_te_timer(transition_timer); } } gboolean initiate_action(action_t *action) { gboolean ret = FALSE; const char *on_node = NULL; const char *id = NULL; const char *task = NULL; const char *timeout = NULL; const char *destination = NULL; const char *msg_task = XML_GRAPH_TAG_RSC_OP; crm_data_t *rsc_op = NULL; 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 */ #ifdef TESTING fprintf(stderr,"Failed on corrupted command: %s (id=%s) %s", crm_element_name(action->xml), crm_str(id), crm_str(task)); #endif crm_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){ #ifdef TESTING fprintf(stderr,"Executing pseudo-event (%d): %s on %s", action->id, task, on_node); #endif crm_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, XML_CIB_ATTR_STONITH)){ /* */ 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; 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); #ifdef TESTING crm_info("Executing fencing operation (%s) on %s", id, target); fprintf(stderr, "Executing fencing operation (%s) on %s\n", id, target); ret = TRUE; action->complete = TRUE; #else stonith_ops_t * st_op = NULL; crm_malloc(st_op, sizeof(stonith_ops_t)); st_op->optype = RESET; st_op->timeout = crm_atoi(timeout, "100"); /* ten seconds */ st_op->node_name = crm_strdup(target); st_op->node_uuid = crm_strdup(uuid); crm_info("Executing fencing operation (%s) on %s", id, target); 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; } return ret; #endif } else if(on_node == NULL || strlen(on_node) == 0) { /* error */ #ifdef TESTING fprintf(stderr, "Failed on corrupted command: %s (id=%s) %s on %s\n", crm_element_name(action->xml), crm_str(id), crm_str(task), crm_str(on_node)); #endif crm_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){ #ifdef TESTING fprintf(stderr, "Executing crm-event (%s): %s on %s\n", id, task, on_node); #endif crm_info("Executing crm-event (%s): %s on %s",id,task,on_node); action->complete = TRUE; destination = CRM_SYSTEM_CRMD; msg_task = task; ret = TRUE; } else if(action->type == action_type_rsc){ crm_data_t *rsc = find_xml_node( action->xml, XML_CIB_TAG_RESOURCE, TRUE); #ifdef TESTING fprintf(stderr, "Executing rsc-op (%s): %s %s on %s\n", id, task, crm_element_value(rsc, XML_ATTR_ID), on_node); #endif crm_info("Executing rsc-op (%s): %s %s on %s", id, task, crm_element_value(rsc,XML_ATTR_ID), on_node); /* let everyone know this was invoked */ if(safe_str_eq(CRMD_RSCSTATE_MON, task)) { /* no update required for monitor ops */ action->complete = TRUE; } else { do_update_cib(action->xml, -1); } /* ... */ #if 1 rsc_op = copy_xml_node_recursive(action->xml); #else rsc_op = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP); set_xml_property_copy(rsc_op, XML_ATTR_ID, id); set_xml_property_copy(rsc_op, XML_LRM_ATTR_TASK, task); set_xml_property_copy(rsc_op, XML_LRM_ATTR_TARGET, on_node); add_node_copy(rsc_op, rsc); #endif destination = CRM_SYSTEM_LRMD; ret = TRUE; } else { #ifdef TESTING fprintf(stderr, "Failed on unsupported command type: " "%s, %s (id=%s) on %s", crm_element_name(action->xml), task, id, on_node); #endif crm_err("Failed on unsupported command type: " "%s, %s (id=%s) on %s", crm_element_name(action->xml), task, id, on_node); } if(ret) { HA_Message *cmd = NULL; char *counter = crm_itoa(transition_counter); if(rsc_op != NULL) { crm_xml_debug(rsc_op, "Performing"); } cmd = create_request(msg_task, rsc_op, on_node, destination, CRM_SYSTEM_TENGINE, NULL); ha_msg_add(cmd, "transition_id", crm_str(counter)); #ifndef TESTING send_ipc_message(crm_ch, cmd); #else crm_log_message(LOG_INFO, cmd); #endif crm_free(counter); if(action->timeout > 0) { crm_devel("Setting timer for action %d",action->id); start_te_timer(action->timer); } } free_xml(rsc_op); return ret; } gboolean initiate_transition(void) { crm_info("Initating transition"); process_graph_event(NULL); return TRUE; } void check_synapse_triggers(synapse_t *synapse, int action_id) { synapse->triggers_complete = TRUE; if(synapse->confirmed) { crm_devel("Skipping confirmed synapse %d", synapse->id); return; } else if(synapse->complete == FALSE) { crm_devel("Checking pre-reqs for %d", synapse->id); /* lookup prereqs */ slist_iter( prereq, action_t, synapse->inputs, lpc, crm_devel("Processing input %d", prereq->id); if(prereq->id == action_id) { crm_devel("Marking input %d complete", action_id); prereq->complete = TRUE; } else if(prereq->complete == FALSE) { crm_devel("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_devel("Checking if synapse %d needs to be fired", synapse->id); if(synapse->complete) { crm_devel("Skipping complete synapse %d", synapse->id); return; } else if(synapse->triggers_complete == FALSE) { crm_devel("Synapse %d not yet satisfied", synapse->id); return; } crm_devel("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_abort("Action init failed", action->xml); + send_complete( + "Action init failed", action->xml, te_failed); 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->type == action_type_rsc && action->complete == FALSE) { complete = FALSE; synapse->confirmed = FALSE; crm_devel("Found an incomplete action" " - transition not complete"); break; } ); return complete; } void process_trigger(int action_id) { graph_complete = TRUE; crm_devel("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_devel("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_devel("Checking if %d is confirmed", synapse->id); if(synapse->complete == FALSE) { crm_devel("Found an incomplete synapse" " - transition not complete"); /* indicate that the transition is not yet complete */ graph_complete = FALSE; } else if(synapse->confirmed == FALSE) { graph_complete = graph_complete && confirm_synapse(synapse, action_id); } crm_devel("%d is %s", synapse->id, synapse->confirmed?"confirmed":synapse->complete?"complete":"pending"); ); } diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h index 4631932163..770c8f9be6 100644 --- a/crm/tengine/tengine.h +++ b/crm/tengine/tengine.h @@ -1,121 +1,127 @@ -/* $Id: tengine.h,v 1.17 2005/03/11 14:25:07 andrew Exp $ */ +/* $Id: tengine.h,v 1.18 2005/04/07 14:00:05 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef TENGINE__H #define TENGINE__H #include #include extern IPC_Channel *crm_ch; extern GListPtr graph; extern GMainLoop* mainloop; extern gboolean in_transition; typedef enum { action_type_pseudo, action_type_rsc, action_type_crm } action_type_e; +typedef enum te_reason_e { + te_update, + te_done, + te_failed, + te_timeout, + +} te_reason_t; + typedef struct synapse_s { int id; gboolean triggers_complete; gboolean complete; gboolean confirmed; GListPtr actions; /* action_t* */ GListPtr inputs; /* action_t* */ } synapse_t; typedef struct te_timer_s te_timer_t; typedef struct action_s { int id; int timeout; te_timer_t *timer; action_type_e type; gboolean invoked; gboolean complete; gboolean can_fail; crm_data_t *xml; } action_t; enum timer_reason { timeout_action, timeout_timeout, timeout_fuzz }; struct te_timer_s { int source_id; int timeout; enum timer_reason reason; action_t *action; }; /* tengine */ extern gboolean initialize_graph(void); extern gboolean process_graph_event(crm_data_t *event); /* const char *event_node, const char *event_rsc, const char *rsc_state, * const char *event_action, const char *event_rc, const char *op_status); */ extern int match_graph_event(action_t *action, crm_data_t *event); extern int match_down_event(const char *target, const char *filter, int rc); extern gboolean initiate_transition(void); /* utils */ extern void print_state(int log_level); -extern void send_success(const char *text); -/*extern void send_abort(const char *text, HA_Message *msg); */ -extern void send_abort(const char *text, crm_data_t *msg); +extern void send_complete(const char *text,crm_data_t *msg,te_reason_t reason); extern gboolean stop_te_timer(te_timer_t *timer); extern gboolean start_te_timer(te_timer_t *timer); extern gboolean do_update_cib(crm_data_t *xml_action, int status); /* unpack */ extern gboolean unpack_graph(crm_data_t *xml_graph); extern gboolean extract_event(crm_data_t *msg); extern gboolean process_te_message( HA_Message * msg, crm_data_t *xml_data, IPC_Channel *sender); extern uint transition_timeout; extern uint transition_fuzz_timeout; extern uint default_transition_timeout; extern te_timer_t *transition_timer; extern te_timer_t *transition_fuzz_timer; extern cib_t *te_cib_conn; extern const char *actiontype2text(action_type_e type); extern void tengine_stonith_callback(stonith_ops_t * op, void * private_data); extern void tengine_stonith_connection_destroy(gpointer user_data); extern gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data); extern void check_for_completion(void); void process_trigger(int action_id); #endif diff --git a/crm/tengine/unpack.c b/crm/tengine/unpack.c index 395d89e3d4..9a97ad35b0 100644 --- a/crm/tengine/unpack.c +++ b/crm/tengine/unpack.c @@ -1,361 +1,362 @@ -/* $Id: unpack.c,v 1.25 2005/03/16 19:53:02 andrew Exp $ */ +/* $Id: unpack.c,v 1.26 2005/04/07 14:00:05 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) { if(timer == NULL) { return; } timer->timeout = time_default; - if(time != NULL) { - int tmp_time = atoi(time); - if(tmp_time > 0) { - timer->timeout = tmp_time; - } + int tmp_time = crm_get_msec(time); + if(tmp_time > 0) { + timer->timeout = tmp_time; } } gboolean unpack_graph(crm_data_t *xml_graph) { /* timeout; time = crm_element_value(xml_graph, "transition_fuzz"); set_timer_value(transition_fuzz_timer, time, transition_fuzz_timeout); transition_counter++; crm_info("Beginning transition %d - timeout set to %d", transition_counter, transition_timer->timeout); xml_child_iter( xml_graph, synapse, "synapse", synapse_t *new_synapse = NULL; crm_devel("looking in synapse %s", crm_element_value(synapse, XML_ATTR_ID)); crm_malloc(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_devel("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_devel("Adding action %d to synapse %d", new_action->id, new_synapse->id); new_synapse->actions = g_list_append( new_synapse->actions, new_action); ); ); crm_devel("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_devel("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; if(tmp == NULL) { crm_err("Actions must have an id!"); crm_xml_devel(xml_action, "Action with missing id"); return NULL; } action_copy = copy_xml_node_recursive(xml_action); crm_malloc(action, sizeof(action_t)); if(action == NULL) { return NULL; } action->id = atoi(tmp); action->timeout = 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; } - tmp = crm_element_value(action_copy, XML_ATTR_TIMEOUT); - if(tmp != NULL) { - action->timeout = atoi(tmp); - } - crm_devel("Action %d has timer set to %d", + action->timeout = crm_get_msec( + crm_element_value(action_copy, XML_ATTR_TIMEOUT)); + + crm_devel("Action %d has timer set to %dms", action->id, action->timeout); crm_malloc(action->timer, sizeof(te_timer_t)); action->timer->timeout = 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) { gboolean abort = FALSE; const char *event_node = NULL; /* [cib fragment] ... */ crm_trace("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); const char *join_state = crm_element_value( node_state, XML_CIB_ATTR_JOINSTATE); crm_xml_devel(node_state,"Processing"); if(crm_element_value(node_state, XML_CIB_ATTR_SHUTDOWN) != NULL) { - send_abort("Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute", node_state); + send_complete( + "Aborting on "XML_CIB_ATTR_SHUTDOWN" attribute", + node_state, te_update); break; } else if(crm_element_value(node_state, XML_CIB_ATTR_STONITH) != NULL) { /* node marked for STONITH * possibly by us when a shutdown timmed out */ int action_id = -1; crm_devel("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) { - send_abort("Stonith/shutdown event not matched", node_state); + send_complete( + "Stonith/shutdown event not matched", + node_state, te_update); break; } else { process_trigger(action_id); check_for_completion(); } continue; } resources = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE); resources = find_xml_node( resources, XML_LRM_TAG_RESOURCES, FALSE); if(crmd_state != NULL || ccm_state != NULL || join_state != NULL) { /* simple node state update... * possibly from a shutdown we requested */ crm_devel("Processing state update"); if(crmd_state != NULL && safe_str_neq(crmd_state, OFFLINESTATUS)) { /* the node is comming up, * only recompute after the join completes, * we dont need to check for this */ continue; } else if(join_state != NULL && safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)) { /* the node is comming up, * only recompute after the join completes, * we dont need to check for this */ continue; } else { /* this may be called more than once per shutdown * ie. once per update of each field */ int action_id = -1; crm_devel("Checking if this was a known shutdown"); event_node = crm_element_value(node_state, XML_ATTR_UNAME); action_id = match_down_event( event_node, NULL, LRM_OP_DONE); if(action_id < 0) { - send_abort("Stonith/shutdown event not matched", node_state); + send_complete("Stonith/shutdown event not matched", node_state, te_update); break; } else { process_trigger(action_id); check_for_completion(); } } if(ccm_state != NULL && crm_is_true(ccm_state)) { crm_devel("Ignore - new CCM node"); } } if(resources != NULL) { /* LRM resource update... */ xml_child_iter( resources, child, NULL, crm_xml_devel(child, "Processing LRM resource update"); abort = !process_graph_event(child); if(abort) { break; } ); if(abort) { break; } } ); return !abort; } 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_RSCSTATE_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 bf7e14f13b..b4e243c1b6 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,441 +1,447 @@ -/* $Id: utils.c,v 1.21 2005/04/06 14:33:31 andrew Exp $ */ +/* $Id: utils.c,v 1.22 2005/04/07 14:00:05 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_abort(const char *text, HA_Message *msg) */ -send_abort(const char *text, crm_data_t *msg) +send_complete(const char *text, crm_data_t *msg, te_reason_t reason) { HA_Message *cmd = NULL; + const char *op = CRM_OP_TEABORT; - if(msg != NULL) { - crm_info("Sending \"abort\" message... details follow"); - if(safe_str_eq(crm_element_name(msg), XML_TAG_CIB)) { - crm_info("%s... full CIB replace/update", text); - - } else { - crm_xml_info(msg, text); + if(reason == te_done || reason == te_timeout) { + op = CRM_OP_TECOMPLETE; + if(in_transition == FALSE) { + crm_warn("Not in transition, not sending message"); + return; } - - } else { - crm_info("Sending \"abort\" message... %s", text); } - - print_state(LOG_WARNING); - initialize_graph(); - - cmd = create_request(CRM_OP_TEABORT, NULL, NULL, - CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); - ha_msg_add(cmd, "message", text); - -#ifdef TESTING - crm_log_message(LOG_ERR, cmd); - g_main_quit(mainloop); - return; -#else - send_ipc_message(crm_ch, cmd); -#endif - -} -void -send_success(const char *text) -{ - HA_Message *cmd = NULL; - if(in_transition == FALSE) { - crm_warn("Not in transition, not sending message"); - return; + switch(reason) { + case te_update: + crm_debug("Transition status: %s by CIB update: %s", + in_transition?"Aborted":"Triggered", text); + if(msg != NULL) { + if(safe_str_eq(crm_element_name(msg), + XML_TAG_CIB)) { + crm_info("Cause:" + " full CIB replace/update"); + } else { + crm_xml_info(msg, "Cause"); + } + } + print_state(LOG_DEBUG); + break; + case te_done: + crm_info("Transition status: Complete%s%s", + text?": ":"", text?text:""); + print_state(LOG_DEBUG); + break; + case te_timeout: + crm_err("Transition status: Timed out after %dms", + transition_timer->timeout); + print_state(LOG_WARNING); + break; + case te_failed: + crm_err("Transition status: Aborted by failed action: %s", + text); + print_state(LOG_WARNING); + break; } + in_transition = FALSE; - - crm_info("Transition \"complete\": %s", text); - - print_state(LOG_INFO); initialize_graph(); - cmd = create_request(CRM_OP_TECOMPLETE, NULL, NULL, - CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); - ha_msg_add(cmd, "message", text); + cmd = create_request( + op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL); + if(text != NULL) { + ha_msg_add(cmd, "message", text); + } + #ifdef TESTING - crm_log_message(LOG_INFO, cmd); + 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 } void print_state(int log_level) { if(graph == NULL) { do_crm_log(LOG_DEBUG, __FUNCTION__, NULL, "###########"); do_crm_log(LOG_DEBUG, __FUNCTION__, NULL, "\tEmpty transition graph"); do_crm_log(LOG_DEBUG, __FUNCTION__, NULL, "###########"); return; } do_crm_log(log_level, __FUNCTION__, NULL, "###########"); slist_iter( synapse, synapse_t, graph, lpc, do_crm_log(log_level, __FUNCTION__, NULL, "Synapse %d %s", synapse->id, synapse->complete?"has completed":"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, __FUNCTION__, NULL, "###########"); } void print_input(const char *prefix, action_t *input, int log_level) { do_crm_log(log_level, __FUNCTION__, NULL, "%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, __FUNCTION__, NULL, "%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, __FUNCTION__, NULL, "%s\tPseudo Op: %s", prefix, crm_element_value( action->xml, XML_LRM_ATTR_TASK)); break; case action_type_rsc: do_crm_log(log_level, __FUNCTION__, NULL, "%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, __FUNCTION__, NULL, "%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, __FUNCTION__, NULL, "%s\ttimeout=%d, timer=%d", prefix, action->timeout, action->timer->source_id); } if(action->complete == FALSE) { crm_log_xml(LOG_VERBOSE, "\tRaw action", action->xml); } } #if 0 void send_cib_updates(void) { } #endif gboolean do_update_cib(crm_data_t *xml_action, int status) { char *code; char since_epoch[64]; crm_data_t *fragment = NULL; crm_data_t *state = NULL; crm_data_t *rsc = NULL; enum cib_errors rc = cib_ok; const char *task = crm_element_value(xml_action, XML_LRM_ATTR_TASK); const char *rsc_id = crm_element_value(xml_action, XML_LRM_ATTR_RSCID); const char *target = crm_element_value(xml_action, XML_LRM_ATTR_TARGET); const char *target_uuid = crm_element_value(xml_action, XML_LRM_ATTR_TARGET_UUID); int call_options = cib_scope_local|cib_discard_reply|cib_inhibit_notify; if(safe_str_neq(CRMD_RSCSTATE_START, task)) { /* no update required for non-start ops */ return TRUE; } if(status == LRM_OP_TIMEOUT) { if(crm_element_value(xml_action, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", crm_element_name(xml_action), task, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", crm_element_name(xml_action), task, target); } } /* update the CIB */ fragment = NULL; state = create_xml_node(NULL, XML_CIB_TAG_STATE); #ifdef TESTING /* turn the "pending" notification into a "op completed" notification * when testing... exercises more code this way. */ if(status == -1) { status = 0; } #endif set_xml_property_copy(state, XML_ATTR_UUID, target_uuid); set_xml_property_copy(state, XML_ATTR_UNAME, target); if(status != -1 && (safe_str_eq(task, CRM_OP_SHUTDOWN))) { sprintf(since_epoch, "%ld", (unsigned long)time(NULL)); set_xml_property_copy(rsc, XML_CIB_ATTR_STONITH, since_epoch); } else { code = crm_itoa(status); 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); set_xml_property_copy(rsc, XML_ATTR_ID, rsc_id); set_xml_property_copy(rsc, XML_LRM_ATTR_TARGET, target); set_xml_property_copy( rsc, XML_LRM_ATTR_TARGET_UUID, target_uuid); if(safe_str_eq(CRMD_RSCSTATE_START, task)) { set_xml_property_copy( rsc, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_START_PENDING); } else if(safe_str_eq(CRMD_RSCSTATE_STOP, task)) { set_xml_property_copy( rsc, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_STOP_PENDING); } else { crm_warn("Using status \"pending\" for op \"%s\"..." " this is still in the experimental stage.", crm_str(task)); set_xml_property_copy( rsc, XML_LRM_ATTR_RSCSTATE, CRMD_RSCSTATE_GENERIC_PENDING); } 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); crm_free(code); } fragment = create_cib_fragment(state, NULL); do_crm_log(LOG_DEV, __FUNCTION__, NULL, "Updating CIB with \"%s\" (%s): %s %s on %s", status<0?"new action":XML_ATTR_TIMEOUT, crm_element_name(xml_action), 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); #else 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; } 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; if(timer->reason == timeout_fuzz) { crm_warn("Transition timeout reached..." " marking transition complete."); - send_success("success"); + send_complete("success", NULL, te_done); 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_success(XML_ATTR_TIMEOUT); + send_complete(XML_ATTR_TIMEOUT, NULL, te_timeout); return TRUE; } else if(timer->action == NULL) { crm_err("Action not present!"); return FALSE; } 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 do_update_cib(timer->action->xml, 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_devel("#!!#!!# 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 ""; }