diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c index 1cd4c5144d..8d26ad83cc 100644 --- a/crm/tengine/tengine.c +++ b/crm/tengine/tengine.c @@ -1,458 +1,458 @@ -/* $Id: tengine.c,v 1.31 2004/09/15 20:24:03 andrew Exp $ */ +/* $Id: tengine.c,v 1.32 2004/09/17 13:00:50 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 GListPtr graph = NULL; IPC_Channel *crm_ch = NULL; uint default_transition_timeout = 60*1000; /* 60 seconds */ gboolean initiate_action(action_t *action); gboolean in_transition = FALSE; int global_transition_timer = 0; gboolean initialize_graph(void) { 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_id > 0) { crm_debug("Removing timer for action: %d", action->id); g_source_remove(action->timer_id); } free_xml(action->xml); 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, xmlNodePtr 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 = xmlGetProp(event, XML_LRM_ATTR_TARGET); event_action = xmlGetProp(event, XML_LRM_ATTR_LASTOP); event_rsc = xmlGetProp(event, XML_ATTR_ID); event_rc = xmlGetProp(event, XML_LRM_ATTR_RC); rsc_state = xmlGetProp(event, XML_LRM_ATTR_RSCSTATE); op_status = xmlGetProp(event, XML_LRM_ATTR_OPSTATUS); if(op_status != NULL) { op_status_i = atoi(op_status); } this_action = xmlGetProp(action->xml, XML_LRM_ATTR_TASK); this_node = xmlGetProp(action->xml, XML_LRM_ATTR_TARGET); this_rsc = xmlGetProp(action->xml, XML_LRM_ATTR_RSCID); crm_devel("matching against: <%s task=%s node=%s rsc_id=%s/>", action->xml->name, this_action, this_node, this_rsc); if(safe_str_neq(this_node, event_node)) { crm_devel("node mismatch: %s", event_node); } else if(safe_str_neq(this_action, event_action)) { crm_devel("action mismatch: %s", event_action); } else if(safe_str_eq(action->xml->name, "rsc_op")) { crm_devel("rsc_op"); if(safe_str_eq(this_rsc, event_rsc)) { match = action; } else { crm_devel("bad rsc (%s) != (%s)", this_rsc, event_rsc); } } else if(safe_str_eq(action->xml->name, "crm_event")) { crm_devel("crm_event"); match = action; } else { crm_devel("no match"); } if(match == NULL) { crm_debug("didnt match current action"); return -1; } crm_debug("matched"); /* stop this event's timer if it had one */ if(match->timer_id) { g_source_remove(match->timer_id); } /* Process OP status */ allow_fail = xmlGetProp(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(safe_str_neq(allow_fail, XML_BOOLEAN_TRUE)) { crm_err("Action %s to %s on %s resulted in" " failure... aborting transition.", event_action, event_rsc, event_node); send_abort("Action failed", match->xml); 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); return -2; } crm_devel("Action %d was successful, looking for next action", match->id); match->complete = TRUE; return match->id; } gboolean process_graph_event(xmlNodePtr event) { int lpc = 0, lpc2 = 0; int transition_timeout = default_transition_timeout; int action_id = -1; int op_status_i = 0; gboolean complete = TRUE; const char *op_status = xmlGetProp(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_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(action_id > -1) { crm_xml_devel(event, "Event found"); } else if(action_id == -2) { crm_xml_info(event, "Event found but failed"); } else if(event != NULL) { /* unexpected event, trigger a pe-recompute */ /* possibly do this only for certain types of actions */ crm_err("Action not matched, aborting transition"); send_abort("Event not matched", event); return FALSE; /* } else { we dont care, a transition is starting */ } /* something happened, stop the timer and start it again at the end */ if(global_transition_timer > 0) { crm_devel("Stopping transition timeout"); g_source_remove(global_transition_timer); } slist_iter( synapse, synapse_t, graph, lpc, gboolean prereqs_complete = TRUE; if(synapse->complete) { continue; } else { /* indicate that the transition is not yet complete */ complete = FALSE; } /* lookup prereqs */ slist_iter( prereq, action_t, synapse->inputs, lpc2, crm_devel("Processing input %d", prereq->id); if(prereq->id == action_id) { crm_devel("Marking input %d complete", action_id); prereq->complete = TRUE; - } else { + } else if(prereq->complete == FALSE) { crm_devel("Inputs for synapse %d not satisfied", synapse->id); prereqs_complete = FALSE; } ); if(prereqs_complete) { crm_devel("All inputs for synapse %d satisfied..." " invoking actions", synapse->id); slist_iter( action, action_t, synapse->actions, lpc2, /* Invoke the action and start the timer */ action->invoked = TRUE; gboolean passed = initiate_action(action); if(passed == FALSE) { crm_err("Failed initiating " "<%s id=%d> in synapse %d", action->xml->name, action->id, synapse->id); send_abort("Action init failed", action->xml); break; } if(action->timeout > transition_timeout) { transition_timeout = action->timeout; } ); synapse->complete = TRUE; crm_debug("Synapse %d complete", synapse->id); } ); /* restart the transition timer again */ global_transition_timer = Gmain_timeout_add( transition_timeout, timer_callback, NULL); if(complete) { send_success("complete"); } return TRUE; } gboolean initiate_action(action_t *action) { const char *on_node = NULL; const char *id = NULL; const char *runnable = NULL; const char *optional = NULL; const char *task = NULL; const char *discard = NULL; const char *timeout = NULL; #ifndef TESTING xmlNodePtr options = NULL; xmlNodePtr data = NULL; xmlNodePtr rsc_op = NULL; #endif discard = xmlGetProp(action->xml, XML_LRM_ATTR_DISCARD); on_node = xmlGetProp(action->xml, XML_LRM_ATTR_TARGET); id = xmlGetProp(action->xml, XML_ATTR_ID); runnable = xmlGetProp(action->xml, XML_LRM_ATTR_RUNNABLE); optional = xmlGetProp(action->xml, XML_LRM_ATTR_OPTIONAL); task = xmlGetProp(action->xml, XML_LRM_ATTR_TASK); timeout = xmlGetProp(action->xml, "timeout"); if(id == NULL || strlen(id) == 0 || on_node == NULL || strlen(on_node) == 0 || task == NULL || strlen(task) == 0) { /* error */ crm_err("Failed on corrupted command: %s (id=%s) on %s", - task, id, on_node); + crm_str(task), crm_str(id), crm_str(on_node)); return FALSE; } else if(safe_str_eq(action->xml->name, "pseduo_event")){ if(safe_str_eq(task, "stonith")){ crm_info("Executing %s (%s) of node %s", task, id, on_node); /* translate this into a stonith op by deisgnated node may need the CIB to determine who is running the stonith resource for this node more liekly, have the pengine find and supply that info */ } else { crm_err("Failed on unsupported %s: " "%s (id=%s) on %s", action->xml->name, task, id, on_node); return FALSE; } } else if(safe_str_eq(action->xml->name, "crm_event")){ /* */ crm_info("Executing crm-event (%s): %s on %s", id, task, on_node); #ifndef TESTING options = create_xml_node( NULL, XML_TAG_OPTIONS); set_xml_property_copy(options, XML_ATTR_OP, task); send_ipc_request( crm_ch, options, NULL, on_node, CRM_SYSTEM_CRMD,CRM_SYSTEM_TENGINE,NULL,NULL); if(action->timeout > 0) { crm_debug("Setting timer for action %d",action->id); action->timer_id = Gmain_timeout_add( action->timeout, timer_callback, action); } free_xml(options); #endif return TRUE; } else if(safe_str_eq(action->xml->name, "rsc_op")){ crm_info("Executing rsc-op (%s): %s %s on %s", id, task, xmlGetProp(action->xml->children, XML_ATTR_ID), on_node); /* let everyone know this was invoked */ do_update_cib(action->xml, -1); #ifndef TESTING /* ... */ data = create_xml_node(NULL, "msg_data"); rsc_op = create_xml_node(data, "rsc_op"); options = create_xml_node(NULL, XML_TAG_OPTIONS); set_xml_property_copy(options, XML_ATTR_OP, "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, action->xml->children); send_ipc_request(crm_ch, options, data, on_node, "lrmd", CRM_SYSTEM_TENGINE, NULL, NULL); if(action->timeout > 0) { crm_debug("Setting timer for action %d",action->id); action->timer_id = Gmain_timeout_add( action->timeout, timer_callback, action); } free_xml(options); free_xml(data); #endif return TRUE; } else { crm_err("Failed on unsupported command type: " "%s, %s (id=%s) on %s", action->xml->name, task, id, on_node); return FALSE; } return FALSE; } gboolean initiate_transition(void) { crm_info("Initating transition"); process_graph_event(NULL); return TRUE; }