diff --git a/include/pcmki/pcmki_transition.h b/include/pcmki/pcmki_transition.h index 1b0682b83a..bc354919f4 100644 --- a/include/pcmki/pcmki_transition.h +++ b/include/pcmki/pcmki_transition.h @@ -1,143 +1,142 @@ /* * Copyright 2004-2021 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. */ #ifndef CRM_TRANSITION__H # define CRM_TRANSITION__H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef enum { action_type_pseudo, action_type_rsc, action_type_crm } action_type_e; typedef struct te_timer_s crm_action_timer_t; typedef struct crm_graph_s crm_graph_t; typedef struct synapse_s { int id; int priority; gboolean ready; gboolean failed; gboolean executed; gboolean confirmed; GList *actions; /* crm_action_t* */ GList *inputs; /* crm_action_t* */ } synapse_t; typedef struct crm_action_s { int id; int timeout; guint interval_ms; GHashTable *params; action_type_e type; crm_action_timer_t *timer; synapse_t *synapse; gboolean sent_update; /* sent to the CIB */ gboolean executed; /* sent to the CRM */ gboolean confirmed; gboolean failed; gboolean can_fail; //! \deprecated Will be removed in a future release xmlNode *xml; } crm_action_t; struct te_timer_s { int source_id; int timeout; crm_action_t *action; }; /* order matters here */ enum transition_action { tg_done, tg_stop, tg_restart, tg_shutdown, }; struct crm_graph_s { int id; char *source; int abort_priority; gboolean complete; const char *abort_reason; enum transition_action completion_action; int num_actions; int num_synapses; int batch_limit; guint network_delay; guint stonith_timeout; int fired; int pending; int skipped; int completed; int incomplete; GList *synapses; /* synapse_t* */ int migration_limit; }; typedef struct crm_graph_functions_s { gboolean(*pseudo) (crm_graph_t * graph, crm_action_t * action); gboolean(*rsc) (crm_graph_t * graph, crm_action_t * action); gboolean(*crmd) (crm_graph_t * graph, crm_action_t * action); gboolean(*stonith) (crm_graph_t * graph, crm_action_t * action); gboolean(*allowed) (crm_graph_t * graph, crm_action_t * action); } crm_graph_functions_t; enum transition_status { transition_active, transition_pending, /* active but no actions performed this time */ transition_complete, transition_stopped, transition_terminated, transition_action_failed, transition_failed, }; void set_default_graph_functions(void); void set_graph_functions(crm_graph_functions_t * fns); crm_graph_t *unpack_graph(xmlNode * xml_graph, const char *reference); int run_graph(crm_graph_t * graph); gboolean update_graph(crm_graph_t * graph, crm_action_t * action); void destroy_graph(crm_graph_t * graph); const char *transition_status(enum transition_status state); void print_graph(unsigned int log_level, crm_graph_t * graph); void print_action(int log_level, const char *prefix, crm_action_t * action); bool update_abort_priority(crm_graph_t * graph, int priority, enum transition_action action, const char *abort_reason); -const char *actiontype2text(action_type_e type); lrmd_event_data_t *convert_graph_action(xmlNode * resource, crm_action_t * action, int status, int rc); #ifdef __cplusplus } #endif #endif diff --git a/lib/pacemaker/Makefile.am b/lib/pacemaker/Makefile.am index e9425dd5ba..70b272c611 100644 --- a/lib/pacemaker/Makefile.am +++ b/lib/pacemaker/Makefile.am @@ -1,51 +1,52 @@ # # Copyright 2004-2021 the Pacemaker project contributors # # The version control history for this file may have further details. # # This source code is licensed under the GNU General Public License version 2 # or later (GPLv2+) WITHOUT ANY WARRANTY. # include $(top_srcdir)/mk/common.mk AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) ## libraries lib_LTLIBRARIES = libpacemaker.la ## SOURCES libpacemaker_la_LDFLAGS = -version-info 3:1:2 libpacemaker_la_CFLAGS = $(CFLAGS_HARDENED_LIB) libpacemaker_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB) libpacemaker_la_LIBADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/lrmd/liblrmd.la \ $(top_builddir)/lib/common/libcrmcommon.la # -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version # Use += rather than backlashed continuation lines for parsing by bumplibs libpacemaker_la_SOURCES = libpacemaker_la_SOURCES += pcmk_cluster_queries.c libpacemaker_la_SOURCES += pcmk_fence.c +libpacemaker_la_SOURCES += pcmk_graph_logging.c libpacemaker_la_SOURCES += pcmk_output.c libpacemaker_la_SOURCES += pcmk_output_utils.c libpacemaker_la_SOURCES += pcmk_resource.c libpacemaker_la_SOURCES += pcmk_sched_allocate.c libpacemaker_la_SOURCES += pcmk_sched_bundle.c libpacemaker_la_SOURCES += pcmk_sched_clone.c libpacemaker_la_SOURCES += pcmk_sched_constraints.c libpacemaker_la_SOURCES += pcmk_sched_graph.c libpacemaker_la_SOURCES += pcmk_sched_group.c libpacemaker_la_SOURCES += pcmk_sched_messages.c libpacemaker_la_SOURCES += pcmk_sched_native.c libpacemaker_la_SOURCES += pcmk_sched_notif.c libpacemaker_la_SOURCES += pcmk_sched_promotable.c libpacemaker_la_SOURCES += pcmk_sched_transition.c libpacemaker_la_SOURCES += pcmk_sched_utilization.c libpacemaker_la_SOURCES += pcmk_sched_utils.c libpacemaker_la_SOURCES += pcmk_trans_graph.c libpacemaker_la_SOURCES += pcmk_trans_unpack.c libpacemaker_la_SOURCES += pcmk_trans_utils.c diff --git a/lib/pacemaker/pcmk_trans_utils.c b/lib/pacemaker/pcmk_graph_logging.c similarity index 67% copy from lib/pacemaker/pcmk_trans_utils.c copy to lib/pacemaker/pcmk_graph_logging.c index 2a143f47ac..52e57b8082 100644 --- a/lib/pacemaker/pcmk_trans_utils.c +++ b/lib/pacemaker/pcmk_graph_logging.c @@ -1,305 +1,204 @@ /* * Copyright 2004-2021 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) { - long long fail_ll; - - if ((pcmk__scan_ll(getenv("PE_fail"), &fail_ll, 0LL) == pcmk_rc_ok) - && (fail_ll > 0LL) && (fail_ll <= INT_MAX)) { - fail = (int) fail_ll; - } 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 * +static const char * actiontype2text(action_type_e type) { switch (type) { case action_type_pseudo: return "pseudo"; case action_type_rsc: return "resource"; case action_type_crm: return "cluster"; } return "invalid"; } static crm_action_t * -find_action(crm_graph_t * graph, int id) +find_action(crm_graph_t *graph, int id) { GList *sIter = NULL; if (graph == NULL) { return NULL; } for (sIter = graph->synapses; sIter != NULL; sIter = sIter->next) { GList *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 const char * synapse_state_str(synapse_t *synapse) { if (synapse->failed) { return "Failed"; } else if (synapse->confirmed) { return "Completed"; } else if (synapse->executed) { return "In-flight"; } else if (synapse->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; size_t pending_len = 0; for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { crm_action_t *input = (crm_action_t *) lpc->data; if (input->failed) { pcmk__add_word(&pending, &pending_len, ID(input->xml)); } else if (input->confirmed) { // Confirmed successful inputs are not pending } else if (find_action(graph, input->id) != NULL) { // In-flight or pending pcmk__add_word(&pending, &pending_len, ID(input->xml)); } } if (pending == NULL) { pending = strdup("none"); } return pending; } // 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%s%s (priority: %d, waiting: %s)", action->id, desc, (host? " on " : ""), (host? host : ""), 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_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) +print_graph(unsigned int log_level, crm_graph_t *graph) { GList *lpc = NULL; if (graph == NULL || graph->num_actions == 0) { if (log_level == LOG_TRACE) { 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; -} diff --git a/lib/pacemaker/pcmk_trans_utils.c b/lib/pacemaker/pcmk_trans_utils.c index 2a143f47ac..681d6e709c 100644 --- a/lib/pacemaker/pcmk_trans_utils.c +++ b/lib/pacemaker/pcmk_trans_utils.c @@ -1,305 +1,116 @@ /* * Copyright 2004-2021 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) { long long fail_ll; if ((pcmk__scan_ll(getenv("PE_fail"), &fail_ll, 0LL) == pcmk_rc_ok) && (fail_ll > 0LL) && (fail_ll <= INT_MAX)) { fail = (int) fail_ll; } 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 "resource"; - case action_type_crm: - return "cluster"; - } - return "invalid"; -} - -static crm_action_t * -find_action(crm_graph_t * graph, int id) -{ - GList *sIter = NULL; - - if (graph == NULL) { - return NULL; - } - - for (sIter = graph->synapses; sIter != NULL; sIter = sIter->next) { - GList *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 const char * -synapse_state_str(synapse_t *synapse) -{ - if (synapse->failed) { - return "Failed"; - - } else if (synapse->confirmed) { - return "Completed"; - - } else if (synapse->executed) { - return "In-flight"; - - } else if (synapse->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; - size_t pending_len = 0; - - for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) { - crm_action_t *input = (crm_action_t *) lpc->data; - - if (input->failed) { - pcmk__add_word(&pending, &pending_len, ID(input->xml)); - - } else if (input->confirmed) { - // Confirmed successful inputs are not pending - - } else if (find_action(graph, input->id) != NULL) { - // In-flight or pending - pcmk__add_word(&pending, &pending_len, ID(input->xml)); - } - } - if (pending == NULL) { - pending = strdup("none"); - } - return pending; -} - -// 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%s%s (priority: %d, waiting: %s)", - action->id, desc, (host? " on " : ""), (host? host : ""), - 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) -{ - GList *lpc = NULL; - - if (graph == NULL || graph->num_actions == 0) { - if (log_level == LOG_TRACE) { - 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; }