root/lib/pacemaker/pcmk_trans_graph.c

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

DEFINITIONS

This source file includes following definitions.
  1. update_synapse_ready
  2. update_synapse_confirmed
  3. update_graph
  4. should_fire_synapse
  5. initiate_action
  6. fire_synapse
  7. run_graph

   1 /*
   2  * Copyright 2004-2019 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 crm_graph_functions_t *graph_fns = NULL;
  18 
  19 static gboolean
  20 update_synapse_ready(synapse_t * synapse, int action_id)
     /* [previous][next][first][last][top][bottom][index][help] */
  21 {
  22     GListPtr lpc = NULL;
  23     gboolean updates = FALSE;
  24 
  25     CRM_CHECK(synapse->executed == FALSE, return FALSE);
  26     CRM_CHECK(synapse->confirmed == FALSE, return FALSE);
  27 
  28     synapse->ready = TRUE;
  29     for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
  30         crm_action_t *prereq = (crm_action_t *) lpc->data;
  31 
  32         crm_trace("Processing input %d", prereq->id);
  33 
  34         if (prereq->id == action_id) {
  35             crm_trace("Marking input %d of synapse %d confirmed", action_id, synapse->id);
  36             prereq->confirmed = TRUE;
  37             updates = TRUE;
  38 
  39         } else if (prereq->confirmed == FALSE) {
  40             synapse->ready = FALSE;
  41         }
  42 
  43     }
  44 
  45     if (updates) {
  46         crm_trace("Updated synapse %d", synapse->id);
  47     }
  48     return updates;
  49 }
  50 
  51 static gboolean
  52 update_synapse_confirmed(synapse_t * synapse, int action_id)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54     GListPtr lpc = NULL;
  55     gboolean updates = FALSE;
  56     gboolean is_confirmed = TRUE;
  57 
  58     CRM_CHECK(synapse->executed, return FALSE);
  59     CRM_CHECK(synapse->confirmed == FALSE, return TRUE);
  60 
  61     is_confirmed = TRUE;
  62     for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
  63         crm_action_t *action = (crm_action_t *) lpc->data;
  64 
  65         crm_trace("Processing action %d", action->id);
  66 
  67         if (action->id == action_id) {
  68             crm_trace("Confirmed: Action %d of Synapse %d", action_id, synapse->id);
  69             action->confirmed = TRUE;
  70             updates = TRUE;
  71 
  72         } else if (action->confirmed == FALSE) {
  73             is_confirmed = FALSE;
  74             crm_trace("Synapse %d still not confirmed after action %d", synapse->id, action_id);
  75         }
  76     }
  77 
  78     if (is_confirmed && synapse->confirmed == FALSE) {
  79         crm_trace("Confirmed: Synapse %d", synapse->id);
  80         synapse->confirmed = TRUE;
  81         updates = TRUE;
  82     }
  83 
  84     if (updates) {
  85         crm_trace("Updated synapse %d", synapse->id);
  86     }
  87     return updates;
  88 }
  89 
  90 gboolean
  91 update_graph(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93     gboolean rc = FALSE;
  94     gboolean updates = FALSE;
  95     GListPtr lpc = NULL;
  96 
  97     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
  98         synapse_t *synapse = (synapse_t *) lpc->data;
  99 
 100         if (synapse->confirmed || synapse->failed) {
 101             crm_trace("Synapse complete");
 102 
 103         } else if (synapse->executed) {
 104             crm_trace("Synapse executed");
 105             rc = update_synapse_confirmed(synapse, action->id);
 106 
 107         } else if (action->failed == FALSE || synapse->priority == INFINITY) {
 108             rc = update_synapse_ready(synapse, action->id);
 109         }
 110         updates = updates || rc;
 111     }
 112 
 113     if (updates) {
 114         crm_trace("Updated graph with completed action %d", action->id);
 115     }
 116     return updates;
 117 }
 118 
 119 static gboolean
 120 should_fire_synapse(crm_graph_t * graph, synapse_t * synapse)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122     GListPtr lpc = NULL;
 123 
 124     CRM_CHECK(synapse->executed == FALSE, return FALSE);
 125     CRM_CHECK(synapse->confirmed == FALSE, return FALSE);
 126 
 127     crm_trace("Checking pre-reqs for synapse %d", synapse->id);
 128     /* lookup prereqs */
 129     synapse->ready = TRUE;
 130     for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
 131         crm_action_t *prereq = (crm_action_t *) lpc->data;
 132 
 133         crm_trace("Processing input %d", prereq->id);
 134         if (prereq->confirmed == FALSE) {
 135             crm_trace("Input %d for synapse %d not satisfied: not confirmed", prereq->id, synapse->id);
 136             synapse->ready = FALSE;
 137             break;
 138         } else if(prereq->failed && prereq->can_fail == FALSE) {
 139             crm_trace("Input %d for synapse %d not satisfied: failed", prereq->id, synapse->id);
 140             synapse->ready = FALSE;
 141             break;
 142         }
 143     }
 144 
 145     for (lpc = synapse->actions; synapse->ready && lpc != NULL; lpc = lpc->next) {
 146         crm_action_t *a = (crm_action_t *) lpc->data;
 147 
 148         if (a->type == action_type_pseudo) {
 149             /* None of the below applies to pseudo ops */
 150 
 151         } else if (synapse->priority < graph->abort_priority) {
 152             crm_trace("Skipping synapse %d: abort level %d", synapse->id, graph->abort_priority);
 153             graph->skipped++;
 154             return FALSE;
 155 
 156         } else if(graph_fns->allowed && graph_fns->allowed(graph, a) == FALSE) {
 157             crm_trace("Deferring synapse %d: allowed", synapse->id);
 158             return FALSE;
 159         }
 160     }
 161 
 162     return synapse->ready;
 163 }
 164 
 165 static gboolean
 166 initiate_action(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168     const char *id = NULL;
 169 
 170     CRM_CHECK(action->executed == FALSE, return FALSE);
 171 
 172     id = ID(action->xml);
 173     CRM_CHECK(id != NULL, return FALSE);
 174 
 175     action->executed = TRUE;
 176     if (action->type == action_type_pseudo) {
 177         crm_trace("Executing pseudo-event: %s (%d)", id, action->id);
 178         return graph_fns->pseudo(graph, action);
 179 
 180     } else if (action->type == action_type_rsc) {
 181         crm_trace("Executing rsc-event: %s (%d)", id, action->id);
 182         return graph_fns->rsc(graph, action);
 183 
 184     } else if (action->type == action_type_crm) {
 185         const char *task = NULL;
 186 
 187         task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 188         CRM_CHECK(task != NULL, return FALSE);
 189 
 190         if (pcmk__str_eq(task, CRM_OP_FENCE, pcmk__str_casei)) {
 191             crm_trace("Executing STONITH-event: %s (%d)", id, action->id);
 192             return graph_fns->stonith(graph, action);
 193         }
 194 
 195         crm_trace("Executing crm-event: %s (%d)", id, action->id);
 196         return graph_fns->crmd(graph, action);
 197     }
 198 
 199     crm_err("Failed on unsupported command type: %s (id=%s)", crm_element_name(action->xml), id);
 200     return FALSE;
 201 }
 202 
 203 static gboolean
 204 fire_synapse(crm_graph_t * graph, synapse_t * synapse)
     /* [previous][next][first][last][top][bottom][index][help] */
 205 {
 206     GListPtr lpc = NULL;
 207 
 208     CRM_CHECK(synapse != NULL, return FALSE);
 209     CRM_CHECK(synapse->ready, return FALSE);
 210     CRM_CHECK(synapse->confirmed == FALSE, return TRUE);
 211 
 212     crm_trace("Synapse %d fired", synapse->id);
 213     synapse->executed = TRUE;
 214     for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
 215         crm_action_t *action = (crm_action_t *) lpc->data;
 216 
 217         /* allow some leeway */
 218         gboolean passed = FALSE;
 219 
 220         /* Invoke the action and start the timer */
 221         passed = initiate_action(graph, action);
 222         if (passed == FALSE) {
 223             crm_err("Failed initiating <%s id=%d> in synapse %d",
 224                     crm_element_name(action->xml), action->id, synapse->id);
 225             synapse->confirmed = TRUE;
 226             action->confirmed = TRUE;
 227             action->failed = TRUE;
 228             return FALSE;
 229         }
 230     }
 231 
 232     return TRUE;
 233 }
 234 
 235 int
 236 run_graph(crm_graph_t * graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238     GListPtr lpc = NULL;
 239     int stat_log_level = LOG_DEBUG;
 240     int pass_result = transition_active;
 241 
 242     const char *status = "In-progress";
 243 
 244     if (graph_fns == NULL) {
 245         set_default_graph_functions();
 246     }
 247     if (graph == NULL) {
 248         return transition_complete;
 249     }
 250 
 251     graph->fired = 0;
 252     graph->pending = 0;
 253     graph->skipped = 0;
 254     graph->completed = 0;
 255     graph->incomplete = 0;
 256     crm_trace("Entering graph %d callback", graph->id);
 257 
 258     /* Pre-calculate the number of completed and in-flight operations */
 259     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
 260         synapse_t *synapse = (synapse_t *) lpc->data;
 261 
 262         if (synapse->confirmed) {
 263             crm_trace("Synapse %d complete", synapse->id);
 264             graph->completed++;
 265 
 266         } else if (synapse->failed == FALSE && synapse->executed) {
 267             crm_trace("Synapse %d: confirmation pending", synapse->id);
 268             graph->pending++;
 269         }
 270     }
 271 
 272     /* Now check if there is work to do */
 273     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
 274         synapse_t *synapse = (synapse_t *) lpc->data;
 275 
 276         if (graph->batch_limit > 0 && graph->pending >= graph->batch_limit) {
 277             crm_debug("Throttling output: batch limit (%d) reached", graph->batch_limit);
 278             break;
 279         } else if (synapse->failed) {
 280             graph->skipped++;
 281             continue;
 282 
 283         } else if (synapse->confirmed || synapse->executed) {
 284             /* Already handled */
 285             continue;
 286         }
 287 
 288         if (should_fire_synapse(graph, synapse)) {
 289             crm_trace("Synapse %d fired", synapse->id);
 290             graph->fired++;
 291             if(fire_synapse(graph, synapse) == FALSE) {
 292                 crm_err("Synapse %d failed to fire", synapse->id);
 293                 stat_log_level = LOG_ERR;
 294                 graph->abort_priority = INFINITY;
 295                 graph->incomplete++;
 296                 graph->fired--;
 297             }
 298 
 299             if (synapse->confirmed == FALSE) {
 300                 graph->pending++;
 301             }
 302 
 303         } else {
 304             crm_trace("Synapse %d cannot fire", synapse->id);
 305             graph->incomplete++;
 306         }
 307     }
 308 
 309     if (graph->pending == 0 && graph->fired == 0) {
 310         graph->complete = TRUE;
 311         stat_log_level = LOG_NOTICE;
 312         pass_result = transition_complete;
 313         status = "Complete";
 314 
 315         if (graph->incomplete != 0 && graph->abort_priority <= 0) {
 316             stat_log_level = LOG_WARNING;
 317             pass_result = transition_terminated;
 318             status = "Terminated";
 319 
 320         } else if (graph->skipped != 0) {
 321             status = "Stopped";
 322         }
 323 
 324     } else if (graph->fired == 0) {
 325         pass_result = transition_pending;
 326     }
 327 
 328     do_crm_log(stat_log_level,
 329                "Transition %d (Complete=%d, Pending=%d,"
 330                " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s",
 331                graph->id, graph->completed, graph->pending, graph->fired,
 332                graph->skipped, graph->incomplete, graph->source, status);
 333 
 334     return pass_result;
 335 }

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