diff --git a/crm/tengine/tengine.c b/crm/tengine/tengine.c index 8d26ad83cc..915e7e1792 100644 --- a/crm/tengine/tengine.c +++ b/crm/tengine/tengine.c @@ -1,458 +1,462 @@ -/* $Id: tengine.c,v 1.32 2004/09/17 13:00:50 andrew Exp $ */ +/* $Id: tengine.c,v 1.33 2004/09/21 19:22:00 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 */ +uint default_transition_timeout = 30*1000; /* 30 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 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 */ + /* allow some leway */ + int tmp_time = 2 * action->timeout; + gboolean passed = FALSE; action->invoked = TRUE; - gboolean passed = initiate_action(action); + + /* Invoke the action and start the timer */ + 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; + if(tmp_time > transition_timeout) { + transition_timeout = tmp_time; } ); 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", 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; } diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h index 6436353eed..fd159fc021 100644 --- a/crm/tengine/tengine.h +++ b/crm/tengine/tengine.h @@ -1,84 +1,85 @@ -/* $Id: tengine.h,v 1.5 2004/09/14 05:54:44 andrew Exp $ */ +/* $Id: tengine.h,v 1.6 2004/09/21 19:22:00 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 extern FILE *msg_te_strm; extern IPC_Channel *crm_ch; extern GListPtr graph; extern uint default_op_timeout; extern GMainLoop* mainloop; extern gboolean in_transition; typedef enum { action_type_pseudo, action_type_rsc, action_type_crm, } action_type_e; typedef struct synapse_s { int id; gboolean complete; GListPtr actions; /* action_t* */ GListPtr inputs; /* action_t* */ } synapse_t; typedef struct action_s { int id; int timeout; int timer_id; action_type_e type; gboolean invoked; gboolean complete; gboolean can_fail; xmlNodePtr xml; } action_t; /* tengine */ extern gboolean initialize_graph(void); extern gboolean process_graph_event(xmlNodePtr 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, xmlNodePtr event); extern gboolean initiate_transition(void); /* utils */ extern void print_state(gboolean to_file); extern void send_success(const char *text); extern void send_abort(const char *text, xmlNodePtr msg); extern gboolean timer_callback(gpointer data); extern gboolean do_update_cib(xmlNodePtr xml_action, int status); /* unpack */ extern gboolean unpack_graph(xmlNodePtr xml_graph); extern gboolean extract_event(xmlNodePtr msg); extern gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender); +extern uint default_transition_timeout; #endif diff --git a/crm/tengine/unpack.c b/crm/tengine/unpack.c index de8aa00a80..717d2a0caa 100644 --- a/crm/tengine/unpack.c +++ b/crm/tengine/unpack.c @@ -1,441 +1,451 @@ -/* $Id: unpack.c,v 1.3 2004/09/17 13:03:10 andrew Exp $ */ +/* $Id: unpack.c,v 1.4 2004/09/21 19:22:00 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 gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender); action_t* unpack_action(xmlNodePtr xml_action); xmlNodePtr create_shutdown_event(const char *node, int op_status); gboolean unpack_graph(xmlNodePtr xml_graph) { /* 0) { + default_transition_timeout = tmp_time; + } + } + + crm_info("Default transition timeout set to %d", + default_transition_timeout); + xml_child_iter( xml_graph, synapse, "synapse", synapse_t *new_synapse = NULL; crm_malloc(new_synapse, sizeof(synapse_t)); new_synapse->id = num_synapses++; new_synapse->complete = FALSE; new_synapse->actions = NULL; new_synapse->inputs = NULL; graph = g_list_append(graph, new_synapse); 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) { action = action->next; break; } new_synapse->actions = g_list_append( new_synapse->actions, new_action); ); ); 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) { input = input->next; break; } 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(xmlNodePtr xml_action) { const char *tmp = xmlGetProp(xml_action, "id"); action_t *action = NULL; xmlNodePtr 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_id = -1; action->invoked = FALSE; action->complete = FALSE; action->can_fail = FALSE; action->type = action_type_rsc; action->xml = action_copy; if(safe_str_eq(action_copy->name, "rsc_op")) { action->type = action_type_rsc; } else if(safe_str_eq(action_copy->name, "pseudo_event")) { action->type = action_type_pseudo; } else if(safe_str_eq(action_copy->name, "crm_event")) { action->type = action_type_crm; - } tmp = xmlGetProp(action_copy, "timeout"); if(tmp != NULL) { action->timeout = atoi(tmp); } tmp = xmlGetProp(action_copy, "can_fail"); if(safe_str_eq(tmp, "true")) { action->can_fail = TRUE; } return action; } gboolean extract_event(xmlNodePtr msg) { gboolean abort = FALSE; xmlNodePtr iter = NULL; xmlNodePtr cib = NULL; const char *section = NULL; const char *event_node = NULL; /* [cib fragment] ... */ crm_trace("Extracting event"); iter = find_xml_node(msg, XML_TAG_FRAGMENT); section = xmlGetProp(iter, XML_ATTR_SECTION); if(safe_str_eq(section, XML_CIB_TAG_CRMCONFIG)) { /* ignore - for the moment */ crm_debug("Ignoring changes to the %s section", XML_CIB_TAG_CRMCONFIG); return TRUE; } else if(safe_str_neq(section, XML_CIB_TAG_STATUS)) { /* these too are never expected */ crm_debug("Ignoring changes outside the %s section", XML_CIB_TAG_STATUS); return FALSE; } cib = find_xml_node(iter, XML_TAG_CIB); iter = get_object_root(XML_CIB_TAG_STATUS, cib); if(iter != NULL) { iter = iter->children; } else { crm_xml_warn(cib, XML_CIB_TAG_STATUS " section missing?"); } while(abort == FALSE && iter != NULL) { xmlNodePtr node_state = iter; xmlNodePtr child = iter->children; const char *state = xmlGetProp( node_state, XML_CIB_ATTR_CRMDSTATE); iter = iter->next; crm_xml_devel(node_state,"Processing"); if(xmlGetProp(node_state, XML_CIB_ATTR_SHUTDOWN) != NULL) { crm_trace("Aborting on %s attribute", XML_CIB_ATTR_SHUTDOWN); abort = TRUE; } else if(xmlGetProp(node_state, XML_CIB_ATTR_STONITH) != NULL) { /* node marked for STONITH * possibly by us when a shutdown timmed out */ crm_trace("Checking for STONITH"); event_node = xmlGetProp(node_state, XML_ATTR_UNAME); xmlNodePtr shutdown = create_shutdown_event( event_node, LRM_OP_TIMEOUT); process_graph_event(shutdown); free_xml(shutdown); } else if(state != NULL && child == NULL) { /* simple node state update... * possibly from a shutdown we requested */ crm_trace("Processing simple state update"); if(safe_str_neq(state, OFFLINESTATUS)) { /* always recompute */ abort = TRUE; continue; } event_node = xmlGetProp(node_state, XML_ATTR_UNAME); xmlNodePtr shutdown = create_shutdown_event( event_node, LRM_OP_DONE); process_graph_event(shutdown); free_xml(shutdown); } else if(state == NULL && child != NULL) { /* LRM resource update... */ crm_trace("Processing LRM resource update"); child = find_xml_node(node_state, XML_CIB_TAG_LRM); child = find_xml_node(child, XML_LRM_TAG_RESOURCES); if(child != NULL) { child = child->children; } else { abort = TRUE; } event_node = xmlGetProp(node_state, XML_ATTR_UNAME); while(abort == FALSE && child != NULL) { process_graph_event(child); child = child->next; } } else if(state != NULL && child != NULL) { /* this is a complex event and could not be completely * due to any request we made */ crm_trace("Aborting on complex update"); abort = TRUE; } else { /* ignore */ crm_err("Ignoring message"); } } return !abort; } gboolean process_te_message(xmlNodePtr msg, IPC_Channel *sender) { xmlNodePtr graph = NULL; const char *sys_to = xmlGetProp(msg, XML_ATTR_SYSTO); const char *ref = xmlGetProp(msg, XML_ATTR_REFERENCE); const char *op = get_xml_attr( msg, XML_TAG_OPTIONS, XML_ATTR_OP, FALSE); crm_debug("Recieved %s (%s) message", op, ref); #ifdef MSG_LOG struct stat buf; if(stat(DEVEL_DIR, &buf) != 0) { cl_perror("Stat of %s failed... exiting", DEVEL_DIR); exit(100); } if(msg_te_strm == NULL) { msg_te_strm = fopen(DEVEL_DIR"/te.log", "w"); } char *xml = dump_xml_formatted(msg); fprintf(msg_te_strm, "[Input %s]\t%s\n", op, xml); fflush(msg_te_strm); crm_free(xml); #endif if(safe_str_eq(xmlGetProp(msg, XML_ATTR_MSGTYPE), XML_ATTR_RESPONSE) && safe_str_neq(op, CRM_OP_EVENTCC)) { #ifdef MSG_LOG fprintf(msg_te_strm, "[Result ]\tDiscarded\n"); fflush(msg_te_strm); #endif 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_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(); graph = find_xml_node(msg, "transition_graph"); crm_trace("Unpacking graph..."); unpack_graph(graph); crm_trace("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_ABORT) == 0) { initialize_graph(); } else if(strcmp(op, CRM_OP_QUIT) == 0) { crm_err("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); } else if(strcmp(op, CRM_OP_EVENTCC) == 0) { const char *true_op = get_xml_attr (msg, XML_TAG_OPTIONS, XML_ATTR_TRUEOP, TRUE); crm_trace("Processing %s...", CRM_OP_EVENTCC); if(true_op == NULL) { crm_err( "Illegal update," " the original operation must be specified"); send_abort("Illegal update", msg); } else if(strcmp(true_op, CRM_OP_CREATE) == 0 || strcmp(true_op, CRM_OP_DELETE) == 0 || strcmp(true_op, CRM_OP_REPLACE) == 0 || strcmp(true_op, CRM_OP_WELCOME) == 0 || strcmp(true_op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(true_op, CRM_OP_ERASE) == 0) { /* these are always unexpected, trigger the PE */ send_abort("Config update", msg); } else if(strcmp(true_op, CRM_OP_UPDATE) == 0) { /* this may not be un-expected */ // if( extract_event(msg); //== FALSE){ // send_abort(msg); // } } else { crm_err( "Did not expect copy of action %s", op); } } crm_debug("finished processing message"); print_state(FALSE); return TRUE; } xmlNodePtr create_shutdown_event(const char *node, int op_status) { xmlNodePtr 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 6b7fd5e865..c228c9c6ad 100644 --- a/crm/tengine/utils.c +++ b/crm/tengine/utils.c @@ -1,373 +1,375 @@ -/* $Id: utils.c,v 1.3 2004/09/17 13:03:10 andrew Exp $ */ +/* $Id: utils.c,v 1.4 2004/09/21 19:22:00 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 int global_transition_timer; FILE *msg_te_strm = NULL; void print_input(const char *prefix, action_t *input, gboolean to_file); void print_action(const char *prefix, action_t *action, gboolean to_file); void send_abort(const char *text, xmlNodePtr msg) { xmlNodePtr options = create_xml_node(NULL, XML_TAG_OPTIONS); crm_info("Sending \"abort\" message... details follow"); crm_xml_info(msg, text); #ifdef MSG_LOG fprintf(msg_te_strm, "[Result ]\tTransition aborted\n"); fflush(msg_te_strm); #endif #ifdef TESTING print_state(TRUE); g_main_quit(mainloop); return; #endif set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_TEABORT); send_ipc_request(crm_ch, options, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL, NULL); free_xml(options); } void send_success(const char *text) { xmlNodePtr options = create_xml_node(NULL, XML_TAG_OPTIONS); if(in_transition == FALSE) { crm_warn("Not in transition, not sending message"); return; } in_transition = FALSE; crm_info("Sending \"complete\" message: %s", text); #ifdef MSG_LOG if(msg_te_strm != NULL) { fprintf(msg_te_strm, "[Result ]\tTransition complete\n"); fflush(msg_te_strm); } #endif #ifdef TESTING print_state(TRUE); g_main_quit(mainloop); return; #endif set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_TECOMPLETE); send_ipc_request(crm_ch, options, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL, NULL); free_xml(options); } void print_state(gboolean to_file) { int lpc = 0; int lpc2 = 0; FILE *output = msg_te_strm; #ifdef TESTING output = stderr; #endif if(to_file) { fprintf(output, "Start Transitioner state\n"); } crm_debug("#!!#!!# Start Transitioner state"); if(graph == NULL) { crm_debug("\tEmpty transition graph"); crm_debug("#!!#!!# End Transitioner state"); if(to_file) { fprintf(output, "\tEmpty transition graph\n" "End Transitioner state\n"); } return; } slist_iter( synapse, synapse_t, graph, lpc, crm_debug("Synapse %d %s", synapse->id, synapse->complete?"has completed":"is pending"); if(to_file) { fprintf(output, "Synapse %d %s\n", synapse->id, synapse->complete?"has completed":"is pending"); } if(synapse->complete == FALSE) { slist_iter( input, action_t, synapse->inputs, lpc2, print_input("\t", input, to_file); ); } slist_iter( action, action_t, synapse->actions, lpc2, print_action("\t", action, to_file); ); ); crm_debug("#!!#!!# End Transitioner state"); if(to_file) { fprintf(output, "End Transitioner state\n"); } } void print_input(const char *prefix, action_t *input, gboolean to_file) { FILE *output = msg_te_strm; #ifdef TESTING output = stderr; #endif crm_debug("%s[Input %d] %s (%d)", prefix, input->id, input->complete?"Satisfied":"Pending", input->type); crm_xml_trace(input->xml, "\t Raw input"); if(to_file) { fprintf(output, "%s[Input %d] %s (%d)\n", prefix, input->id, input->complete?"Satisfied":"Pending", input->type); fflush(msg_te_strm); } } void print_action(const char *prefix, action_t *action, gboolean to_file) { FILE *output = msg_te_strm; #ifdef TESTING output = stderr; #endif crm_debug("%s[Action %d] %s (%d - %s fail)", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight":"Pending", action->type, action->can_fail?"can":"cannot"); crm_debug("%s timeout=%d, timer=%d", prefix, action->timeout, action->timer_id); crm_xml_trace(action->xml, "\t Raw action"); if(to_file) { fprintf(output, "%s[Action %d] %s (%d - %s fail)\n", prefix, action->id, action->complete?"Completed": action->invoked?"In-flight":"Pending", action->type, action->can_fail?"can":"cannot"); fflush(msg_te_strm); } } gboolean timer_callback(gpointer data) { if(data == NULL) { /* global timeout - abort the transition */ crm_info("Transition timeout reached..." " marking transition complete."); crm_warn("Some actions may not have been executed."); if(global_transition_timer > 0) { crm_devel("Stopping transition timer"); g_source_remove(global_transition_timer); global_transition_timer = -1; } send_success("timeout"); return TRUE; } else { /* fail the action * - which may or may not abort the transition */ action_t *action = (action_t*)data; if(action->timer_id > 0) { g_source_remove(action->timer_id); } action->timer_id = -1; + /* TODO: send a cancel notice to the LRM */ + /* TODO: use the ack from above to update the CIB */ return do_update_cib(action->xml, LRM_OP_TIMEOUT); } } gboolean do_update_cib(xmlNodePtr xml_action, int status) { char *code; char since_epoch[64]; xmlNodePtr fragment = NULL; xmlNodePtr options = NULL; xmlNodePtr state = NULL; xmlNodePtr rsc = NULL; const char *sys_to = CRM_SYSTEM_DCIB; const char *task = xmlGetProp(xml_action, XML_LRM_ATTR_TASK); const char *rsc_id = xmlGetProp(xml_action, XML_LRM_ATTR_RSCID); const char *target = xmlGetProp(xml_action, XML_LRM_ATTR_TARGET); const char *target_uuid = xmlGetProp(xml_action, XML_LRM_ATTR_TARGET_UUID); if(status == LRM_OP_TIMEOUT) { if(xmlGetProp(xml_action, XML_LRM_ATTR_RSCID) != NULL) { crm_warn("%s: %s %s on %s timed out", xml_action->name, task, rsc_id, target); } else { crm_warn("%s: %s on %s timed out", xml_action->name, task, target); } } /* update the CIB */ fragment = NULL; options = create_xml_node(NULL, XML_TAG_OPTIONS); 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; } sys_to = CRM_SYSTEM_TENGINE; set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_EVENTCC); set_xml_property_copy(options, XML_ATTR_TRUEOP, CRM_OP_UPDATE); #else set_xml_property_copy(options, XML_ATTR_OP, CRM_OP_UPDATE); #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, "shutdown_crm"))) { sprintf(since_epoch, "%ld", (unsigned long)time(NULL)); set_xml_property_copy(rsc, "stonith", since_epoch); } else { code = crm_itoa(status); rsc = create_xml_node(state, "lrm"); rsc = create_xml_node(rsc, "lrm_resources"); rsc = create_xml_node(rsc, "lrm_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); #ifdef MSG_LOG fprintf(msg_te_strm, "[Result ]\tUpdate CIB with \"%s\" (%s): %s %s on %s\n", status<0?"new action":"timeout", xml_action->name, task, rsc_id, target); fprintf(msg_te_strm, "[Sent ]\t%s\n", dump_xml_formatted(fragment)); fflush(msg_te_strm); #endif send_ipc_request(crm_ch, options, fragment, NULL, sys_to, CRM_SYSTEM_TENGINE, NULL, NULL); free_xml(fragment); free_xml(options); free_xml(state); return TRUE; }