root/lib/pacemaker/pcmk_trans_utils.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pseudo_action_dummy
  2. set_default_graph_functions
  3. set_graph_functions
  4. transition_status
  5. actiontype2text
  6. find_action
  7. synapse_state_str
  8. synapse_pending_inputs
  9. log_unresolved_inputs
  10. log_synapse_action
  11. print_synapse
  12. print_action
  13. print_graph
  14. abort2text
  15. update_abort_priority

   1 /*
   2  * Copyright 2004-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <crm/crm.h>
  13 #include <crm/msg_xml.h>
  14 #include <crm/common/xml.h>
  15 #include <pacemaker-internal.h>
  16 
  17 extern crm_graph_functions_t *graph_fns;
  18 
  19 static gboolean
  20 pseudo_action_dummy(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
  21 {
  22     static int fail = -1;
  23 
  24     if (fail < 0) {
  25         char *fail_s = getenv("PE_fail");
  26 
  27         if (fail_s) {
  28             fail = (int) crm_parse_ll(fail_s, NULL);
  29         } else {
  30             fail = 0;
  31         }
  32     }
  33 
  34     crm_trace("Dummy event handler: action %d executed", action->id);
  35     if (action->id == fail) {
  36         crm_err("Dummy event handler: pretending action %d failed", action->id);
  37         action->failed = TRUE;
  38         graph->abort_priority = INFINITY;
  39     }
  40     action->confirmed = TRUE;
  41     update_graph(graph, action);
  42     return TRUE;
  43 }
  44 
  45 crm_graph_functions_t default_fns = {
  46     pseudo_action_dummy,
  47     pseudo_action_dummy,
  48     pseudo_action_dummy,
  49     pseudo_action_dummy
  50 };
  51 
  52 void
  53 set_default_graph_functions(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55     graph_fns = &default_fns;
  56 }
  57 
  58 void
  59 set_graph_functions(crm_graph_functions_t * fns)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61     crm_info("Setting custom graph functions");
  62     graph_fns = fns;
  63 
  64     CRM_ASSERT(graph_fns != NULL);
  65     CRM_ASSERT(graph_fns->rsc != NULL);
  66     CRM_ASSERT(graph_fns->crmd != NULL);
  67     CRM_ASSERT(graph_fns->pseudo != NULL);
  68     CRM_ASSERT(graph_fns->stonith != NULL);
  69 }
  70 
  71 const char *
  72 transition_status(enum transition_status state)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74     switch (state) {
  75         case transition_active:
  76             return "active";
  77         case transition_pending:
  78             return "pending";
  79         case transition_complete:
  80             return "complete";
  81         case transition_stopped:
  82             return "stopped";
  83         case transition_terminated:
  84             return "terminated";
  85         case transition_action_failed:
  86             return "failed (action)";
  87         case transition_failed:
  88             return "failed";
  89     }
  90     return "unknown";
  91 }
  92 
  93 const char *
  94 actiontype2text(action_type_e type)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96     switch (type) {
  97         case action_type_pseudo:
  98             return "pseudo";
  99         case action_type_rsc:
 100             return "resource";
 101         case action_type_crm:
 102             return "cluster";
 103     }
 104     return "invalid";
 105 }
 106 
 107 static crm_action_t *
 108 find_action(crm_graph_t * graph, int id)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     GListPtr sIter = NULL;
 111 
 112     if (graph == NULL) {
 113         return NULL;
 114     }
 115 
 116     for (sIter = graph->synapses; sIter != NULL; sIter = sIter->next) {
 117         GListPtr aIter = NULL;
 118         synapse_t *synapse = (synapse_t *) sIter->data;
 119 
 120         for (aIter = synapse->actions; aIter != NULL; aIter = aIter->next) {
 121             crm_action_t *action = (crm_action_t *) aIter->data;
 122 
 123             if (action->id == id) {
 124                 return action;
 125             }
 126         }
 127     }
 128     return NULL;
 129 }
 130 
 131 static const char *
 132 synapse_state_str(synapse_t *synapse)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134     if (synapse->failed) {
 135         return "Failed";
 136 
 137     } else if (synapse->confirmed) {
 138         return "Completed";
 139 
 140     } else if (synapse->executed) {
 141         return "In-flight";
 142 
 143     } else if (synapse->ready) {
 144         return "Ready";
 145     }
 146     return "Pending";
 147 }
 148 
 149 // List action IDs of inputs in graph that haven't completed successfully
 150 static char *
 151 synapse_pending_inputs(crm_graph_t *graph, synapse_t *synapse)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153     char *pending = NULL;
 154     size_t pending_len = 0;
 155 
 156     for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
 157         crm_action_t *input = (crm_action_t *) lpc->data;
 158 
 159         if (input->failed) {
 160             pcmk__add_word(&pending, &pending_len, ID(input->xml));
 161 
 162         } else if (input->confirmed) {
 163             // Confirmed successful inputs are not pending
 164 
 165         } else if (find_action(graph, input->id) != NULL) {
 166             // In-flight or pending
 167             pcmk__add_word(&pending, &pending_len, ID(input->xml));
 168         }
 169     }
 170     if (pending == NULL) {
 171         pending = strdup("none");
 172     }
 173     return pending;
 174 }
 175 
 176 // Log synapse inputs that aren't in graph
 177 static void
 178 log_unresolved_inputs(unsigned int log_level, crm_graph_t *graph,
     /* [previous][next][first][last][top][bottom][index][help] */
 179                       synapse_t *synapse)
 180 {
 181     for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
 182         crm_action_t *input = (crm_action_t *) lpc->data;
 183         const char *key = crm_element_value(input->xml, XML_LRM_ATTR_TASK_KEY);
 184         const char *host = crm_element_value(input->xml, XML_LRM_ATTR_TARGET);
 185 
 186         if (find_action(graph, input->id) == NULL) {
 187             do_crm_log(log_level,
 188                        " * [Input %2d]: Unresolved dependency %s op %s%s%s",
 189                        input->id, actiontype2text(input->type), key,
 190                        (host? " on " : ""), (host? host : ""));
 191         }
 192     }
 193 }
 194 
 195 static void
 196 log_synapse_action(unsigned int log_level, synapse_t *synapse,
     /* [previous][next][first][last][top][bottom][index][help] */
 197                    crm_action_t *action, const char *pending_inputs)
 198 {
 199     const char *key = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
 200     const char *host = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 201     char *desc = crm_strdup_printf("%s %s op %s",
 202                                    synapse_state_str(synapse),
 203                                    actiontype2text(action->type), key);
 204 
 205     do_crm_log(log_level,
 206                "[Action %4d]: %-50s%s%s (priority: %d, waiting: %s)",
 207                action->id, desc, (host? " on " : ""), (host? host : ""),
 208                synapse->priority, pending_inputs);
 209     free(desc);
 210 }
 211 
 212 static void
 213 print_synapse(unsigned int log_level, crm_graph_t * graph, synapse_t * synapse)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215     char *pending = NULL;
 216 
 217     if (!synapse->executed) {
 218         pending = synapse_pending_inputs(graph, synapse);
 219     }
 220     for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
 221         log_synapse_action(log_level, synapse, (crm_action_t *) lpc->data,
 222                            pending);
 223     }
 224     free(pending);
 225     if (!synapse->executed) {
 226         log_unresolved_inputs(log_level, graph, synapse);
 227     }
 228 }
 229 
 230 void
 231 print_action(int log_level, const char *prefix, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 232 {
 233     print_synapse(log_level, NULL, action->synapse);
 234 }
 235 
 236 void
 237 print_graph(unsigned int log_level, crm_graph_t * graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239     GListPtr lpc = NULL;
 240 
 241     if (graph == NULL || graph->num_actions == 0) {
 242         if (log_level == LOG_TRACE) {
 243             crm_debug("Empty transition graph");
 244         }
 245         return;
 246     }
 247 
 248     do_crm_log(log_level, "Graph %d with %d actions:"
 249                " batch-limit=%d jobs, network-delay=%ums",
 250                graph->id, graph->num_actions,
 251                graph->batch_limit, graph->network_delay);
 252 
 253     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
 254         synapse_t *synapse = (synapse_t *) lpc->data;
 255 
 256         print_synapse(log_level, graph, synapse);
 257     }
 258 }
 259 
 260 static const char *
 261 abort2text(enum transition_action abort_action)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263     switch (abort_action) {
 264         case tg_done:
 265             return "done";
 266         case tg_stop:
 267             return "stop";
 268         case tg_restart:
 269             return "restart";
 270         case tg_shutdown:
 271             return "shutdown";
 272     }
 273     return "unknown";
 274 }
 275 
 276 bool
 277 update_abort_priority(crm_graph_t * graph, int priority,
     /* [previous][next][first][last][top][bottom][index][help] */
 278                       enum transition_action action, const char *abort_reason)
 279 {
 280     bool change = FALSE;
 281 
 282     if (graph == NULL) {
 283         return change;
 284     }
 285 
 286     if (graph->abort_priority < priority) {
 287         crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority);
 288         graph->abort_priority = priority;
 289         if (graph->abort_reason != NULL) {
 290             crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason);
 291         }
 292         graph->abort_reason = abort_reason;
 293         change = TRUE;
 294     }
 295 
 296     if (graph->completion_action < action) {
 297         crm_debug("Abort action %s superseded by %s: %s",
 298                   abort2text(graph->completion_action), abort2text(action), abort_reason);
 299         graph->completion_action = action;
 300         change = TRUE;
 301     }
 302 
 303     return change;
 304 }

/* [previous][next][first][last][top][bottom][index][help] */