diff --git a/lib/pacemaker/pcmk_trans_utils.c b/lib/pacemaker/pcmk_trans_utils.c index 878ee82634..ec090e8146 100644 --- a/lib/pacemaker/pcmk_trans_utils.c +++ b/lib/pacemaker/pcmk_trans_utils.c @@ -1,279 +1,304 @@ /* * Copyright 2004-2019 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include extern crm_graph_functions_t *graph_fns; static gboolean pseudo_action_dummy(crm_graph_t * graph, crm_action_t * action) { static int fail = -1; if (fail < 0) { char *fail_s = getenv("PE_fail"); if (fail_s) { fail = crm_int_helper(fail_s, NULL); } else { fail = 0; } } crm_trace("Dummy event handler: action %d executed", action->id); if (action->id == fail) { crm_err("Dummy event handler: pretending action %d failed", action->id); action->failed = TRUE; graph->abort_priority = INFINITY; } action->confirmed = TRUE; update_graph(graph, action); return TRUE; } crm_graph_functions_t default_fns = { pseudo_action_dummy, pseudo_action_dummy, pseudo_action_dummy, pseudo_action_dummy }; void set_default_graph_functions(void) { graph_fns = &default_fns; } void set_graph_functions(crm_graph_functions_t * fns) { crm_info("Setting custom graph functions"); graph_fns = fns; CRM_ASSERT(graph_fns != NULL); CRM_ASSERT(graph_fns->rsc != NULL); CRM_ASSERT(graph_fns->crmd != NULL); CRM_ASSERT(graph_fns->pseudo != NULL); CRM_ASSERT(graph_fns->stonith != NULL); } const char * transition_status(enum transition_status state) { switch (state) { case transition_active: return "active"; case transition_pending: return "pending"; case transition_complete: return "complete"; case transition_stopped: return "stopped"; case transition_terminated: return "terminated"; case transition_action_failed: return "failed (action)"; case transition_failed: return "failed"; } return "unknown"; } const char * actiontype2text(action_type_e type) { switch (type) { case action_type_pseudo: return "pseudo"; case action_type_rsc: return "rsc"; case action_type_crm: return "crm"; } return ""; } static crm_action_t * find_action(crm_graph_t * graph, int id) { GListPtr sIter = NULL; if (graph == NULL) { return NULL; } for (sIter = graph->synapses; sIter != NULL; sIter = sIter->next) { GListPtr aIter = NULL; synapse_t *synapse = (synapse_t *) sIter->data; for (aIter = synapse->actions; aIter != NULL; aIter = aIter->next) { crm_action_t *action = (crm_action_t *) aIter->data; if (action->id == id) { return action; } } } return NULL; } -static void -print_synapse(unsigned int log_level, crm_graph_t * graph, synapse_t * synapse) +static const char * +synapse_state_str(synapse_t *synapse) { - GListPtr lpc = NULL; - char *pending = NULL; - const char *state = "Pending"; - if (synapse->failed) { - state = "Failed"; + return "Failed"; } else if (synapse->confirmed) { - state = "Completed"; + return "Completed"; } else if (synapse->executed) { - state = "In-flight"; + return "In-flight"; } else if (synapse->ready) { - state = "Ready"; + return "Ready"; } + return "Pending"; +} + +// List action IDs of inputs in graph that haven't completed successfully +static char * +synapse_pending_inputs(crm_graph_t *graph, synapse_t *synapse) +{ + char *pending = NULL; - if (synapse->executed == FALSE) { - for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { - crm_action_t *input = (crm_action_t *) lpc->data; - const char *id_string = crm_element_value(input->xml, XML_ATTR_ID); + for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { + crm_action_t *input = (crm_action_t *) lpc->data; - if (input->failed) { - pending = add_list_element(pending, id_string); + if (input->failed) { + pending = add_list_element(pending, ID(input->xml)); - } else if (input->confirmed) { - /* Confirmed, skip */ + } else if (input->confirmed) { + // Confirmed successful inputs are not pending - } else if (find_action(graph, input->id)) { - /* In-flight or pending */ - pending = add_list_element(pending, id_string); - } + } else if (find_action(graph, input->id) != NULL) { + // In-flight or pending + pending = add_list_element(pending, ID(input->xml)); } } - - for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) { - crm_action_t *action = (crm_action_t *) lpc->data; - const char *key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); - const char *host = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); - char *desc = crm_strdup_printf("%s %s op %s", state, actiontype2text(action->type), key); - - do_crm_log(log_level, - "[Action %4d]: %-50s on %s (priority: %d, waiting: %s)", - action->id, desc, host ? host : "N/A", - synapse->priority, pending ? pending : "none"); - - free(desc); + if (pending == NULL) { + pending = strdup("none"); } + return pending; +} - if (synapse->executed == FALSE) { - for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { - crm_action_t *input = (crm_action_t *) lpc->data; - const char *key = crm_element_value(input->xml, XML_LRM_ATTR_TASK_KEY); - const char *host = crm_element_value(input->xml, XML_LRM_ATTR_TARGET); - - if (find_action(graph, input->id) == NULL) { - if (host == NULL) { - do_crm_log(log_level, " * [Input %2d]: Unresolved dependency %s op %s", - input->id, actiontype2text(input->type), key); - } else { - do_crm_log(log_level, " * [Input %2d]: Unresolved dependency %s op %s on %s", - input->id, actiontype2text(input->type), key, host); - } - } +// Log synapse inputs that aren't in graph +static void +log_unresolved_inputs(unsigned int log_level, crm_graph_t *graph, + synapse_t *synapse) +{ + for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { + crm_action_t *input = (crm_action_t *) lpc->data; + const char *key = crm_element_value(input->xml, XML_LRM_ATTR_TASK_KEY); + const char *host = crm_element_value(input->xml, XML_LRM_ATTR_TARGET); + + if (find_action(graph, input->id) == NULL) { + do_crm_log(log_level, + " * [Input %2d]: Unresolved dependency %s op %s%s%s", + input->id, actiontype2text(input->type), key, + (host? " on " : ""), (host? host : "")); } } +} + +static void +log_synapse_action(unsigned int log_level, synapse_t *synapse, + crm_action_t *action, const char *pending_inputs) +{ + const char *key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY); + const char *host = crm_element_value(action->xml, XML_LRM_ATTR_TARGET); + char *desc = crm_strdup_printf("%s %s op %s", + synapse_state_str(synapse), + actiontype2text(action->type), key); + + do_crm_log(log_level, + "[Action %4d]: %-50s on %s (priority: %d, waiting: %s)", + action->id, desc, (host? host : "N/A"), + synapse->priority, pending_inputs); + free(desc); +} +static void +print_synapse(unsigned int log_level, crm_graph_t * graph, synapse_t * synapse) +{ + char *pending = NULL; + + if (!synapse->executed) { + pending = synapse_pending_inputs(graph, synapse); + } + for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) { + log_synapse_action(log_level, synapse, (crm_action_t *) lpc->data, + pending); + } free(pending); + if (!synapse->executed) { + log_unresolved_inputs(log_level, graph, synapse); + } } void print_action(int log_level, const char *prefix, crm_action_t * action) { print_synapse(log_level, NULL, action->synapse); } void print_graph(unsigned int log_level, crm_graph_t * graph) { GListPtr lpc = NULL; if (graph == NULL || graph->num_actions == 0) { if (log_level > LOG_DEBUG) { crm_debug("Empty transition graph"); } return; } do_crm_log(log_level, "Graph %d with %d actions:" " batch-limit=%d jobs, network-delay=%ums", graph->id, graph->num_actions, graph->batch_limit, graph->network_delay); for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) { synapse_t *synapse = (synapse_t *) lpc->data; print_synapse(log_level, graph, synapse); } } static const char * abort2text(enum transition_action abort_action) { switch (abort_action) { case tg_done: return "done"; case tg_stop: return "stop"; case tg_restart: return "restart"; case tg_shutdown: return "shutdown"; } return "unknown"; } bool update_abort_priority(crm_graph_t * graph, int priority, enum transition_action action, const char *abort_reason) { bool change = FALSE; if (graph == NULL) { return change; } if (graph->abort_priority < priority) { crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority); graph->abort_priority = priority; if (graph->abort_reason != NULL) { crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason); } graph->abort_reason = abort_reason; change = TRUE; } if (graph->completion_action < action) { crm_debug("Abort action %s superseded by %s: %s", abort2text(graph->completion_action), abort2text(action), abort_reason); graph->completion_action = action; change = TRUE; } return change; }