root/lib/pacemaker/pcmk_sched_graph.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_action_flags
  2. convert_non_atomic_uuid
  3. rsc_expand_action
  4. graph_update_action
  5. mark_start_blocked
  6. update_colo_start_chain
  7. update_action
  8. shutdown_constraints
  9. pcmk__order_vs_fence
  10. get_router_node
  11. add_node_to_xml_by_id
  12. add_node_to_xml
  13. add_maintenance_nodes
  14. add_maintenance_update
  15. add_downed_nodes
  16. should_lock_action
  17. action2xml
  18. should_dump_action
  19. sort_action_id
  20. check_dump_input
  21. graph_has_loop
  22. pcmk__ordering_is_invalid
  23. deduplicate_inputs
  24. graph_element_from_action

   1 /*
   2  * Copyright 2004-2021 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 General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <sys/param.h>
  13 #include <crm/crm.h>
  14 #include <crm/cib.h>
  15 #include <crm/msg_xml.h>
  16 #include <crm/common/xml.h>
  17 
  18 #include <glib.h>
  19 
  20 #include <pacemaker-internal.h>
  21 
  22 void update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set);
  23 gboolean rsc_update_action(pe_action_t * first, pe_action_t * then, enum pe_ordering type);
  24 
  25 static enum pe_action_flags
  26 get_action_flags(pe_action_t * action, pe_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     enum pe_action_flags flags = action->flags;
  29 
  30     if (action->rsc) {
  31         flags = action->rsc->cmds->action_flags(action, NULL);
  32 
  33         if (pe_rsc_is_clone(action->rsc) && node) {
  34 
  35             /* We only care about activity on $node */
  36             enum pe_action_flags clone_flags = action->rsc->cmds->action_flags(action, node);
  37 
  38             /* Go to great lengths to ensure the correct value for pe_action_runnable...
  39              *
  40              * If we are a clone, then for _ordering_ constraints, it's only relevant
  41              * if we are runnable _anywhere_.
  42              *
  43              * This only applies to _runnable_ though, and only for ordering constraints.
  44              * If this function is ever used during colocation, then we'll need additional logic
  45              *
  46              * Not very satisfying, but it's logical and appears to work well.
  47              */
  48             if (!pcmk_is_set(clone_flags, pe_action_runnable)
  49                 && pcmk_is_set(flags, pe_action_runnable)) {
  50 
  51                 pe__set_raw_action_flags(clone_flags, action->rsc->id,
  52                                          pe_action_runnable);
  53             }
  54             flags = clone_flags;
  55         }
  56     }
  57     return flags;
  58 }
  59 
  60 static char *
  61 convert_non_atomic_uuid(char *old_uuid, pe_resource_t * rsc, gboolean allow_notify,
     /* [previous][next][first][last][top][bottom][index][help] */
  62                         gboolean free_original)
  63 {
  64     guint interval_ms = 0;
  65     char *uuid = NULL;
  66     char *rid = NULL;
  67     char *raw_task = NULL;
  68     int task = no_action;
  69 
  70     CRM_ASSERT(rsc);
  71     pe_rsc_trace(rsc, "Processing %s", old_uuid);
  72     if (old_uuid == NULL) {
  73         return NULL;
  74 
  75     } else if (strstr(old_uuid, "notify") != NULL) {
  76         goto done;              /* no conversion */
  77 
  78     } else if (rsc->variant < pe_group) {
  79         goto done;              /* no conversion */
  80     }
  81 
  82     CRM_ASSERT(parse_op_key(old_uuid, &rid, &raw_task, &interval_ms));
  83     if (interval_ms > 0) {
  84         goto done;              /* no conversion */
  85     }
  86 
  87     task = text2task(raw_task);
  88     switch (task) {
  89         case stop_rsc:
  90         case start_rsc:
  91         case action_notify:
  92         case action_promote:
  93         case action_demote:
  94             break;
  95         case stopped_rsc:
  96         case started_rsc:
  97         case action_notified:
  98         case action_promoted:
  99         case action_demoted:
 100             task--;
 101             break;
 102         case monitor_rsc:
 103         case shutdown_crm:
 104         case stonith_node:
 105             task = no_action;
 106             break;
 107         default:
 108             crm_err("Unknown action: %s", raw_task);
 109             task = no_action;
 110             break;
 111     }
 112 
 113     if (task != no_action) {
 114         if (pcmk_is_set(rsc->flags, pe_rsc_notify) && allow_notify) {
 115             uuid = pcmk__notify_key(rid, "confirmed-post", task2text(task + 1));
 116 
 117         } else {
 118             uuid = pcmk__op_key(rid, task2text(task + 1), 0);
 119         }
 120         pe_rsc_trace(rsc, "Converted %s -> %s", old_uuid, uuid);
 121     }
 122 
 123   done:
 124     if (uuid == NULL) {
 125         uuid = strdup(old_uuid);
 126     }
 127 
 128     if (free_original) {
 129         free(old_uuid);
 130     }
 131 
 132     free(raw_task);
 133     free(rid);
 134     return uuid;
 135 }
 136 
 137 static pe_action_t *
 138 rsc_expand_action(pe_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140     gboolean notify = FALSE;
 141     pe_action_t *result = action;
 142     pe_resource_t *rsc = action->rsc;
 143 
 144     if (rsc == NULL) {
 145         return action;
 146     }
 147 
 148     if ((rsc->parent == NULL)
 149         || (pe_rsc_is_clone(rsc) && (rsc->parent->variant == pe_container))) {
 150         /* Only outermost resources have notification actions.
 151          * The exception is those in bundles.
 152          */
 153         notify = pcmk_is_set(rsc->flags, pe_rsc_notify);
 154     }
 155 
 156     if (rsc->variant >= pe_group) {
 157         /* Expand 'start' -> 'started' */
 158         char *uuid = NULL;
 159 
 160         uuid = convert_non_atomic_uuid(action->uuid, rsc, notify, FALSE);
 161         if (uuid) {
 162             pe_rsc_trace(rsc, "Converting %s to %s %d", action->uuid, uuid,
 163                          pcmk_is_set(rsc->flags, pe_rsc_notify));
 164             result = find_first_action(rsc->actions, uuid, NULL, NULL);
 165             if (result == NULL) {
 166                 crm_err("Couldn't expand %s to %s in %s", action->uuid, uuid, rsc->id);
 167                 result = action;
 168             }
 169             free(uuid);
 170         }
 171     }
 172     return result;
 173 }
 174 
 175 static enum pe_graph_flags
 176 graph_update_action(pe_action_t * first, pe_action_t * then, pe_node_t * node,
     /* [previous][next][first][last][top][bottom][index][help] */
 177                     enum pe_action_flags first_flags, enum pe_action_flags then_flags,
 178                     pe_action_wrapper_t *order, pe_working_set_t *data_set)
 179 {
 180     enum pe_graph_flags changed = pe_graph_none;
 181     enum pe_ordering type = order->type;
 182     gboolean processed = FALSE;
 183 
 184     /* TODO: Do as many of these in parallel as possible */
 185 
 186     if (pcmk_is_set(type, pe_order_implies_then_on_node)) {
 187         /* Normally we want the _whole_ 'then' clone to
 188          * restart if 'first' is restarted, so then->node is
 189          * needed.
 190          *
 191          * However for unfencing, we want to limit this to
 192          * instances on the same node as 'first' (the
 193          * unfencing operation), so first->node is supplied.
 194          *
 195          * Swap the node, from then on we can can treat it
 196          * like any other 'pe_order_implies_then'
 197          */
 198 
 199         pe__clear_order_flags(type, pe_order_implies_then_on_node);
 200         pe__set_order_flags(type, pe_order_implies_then);
 201         node = first->node;
 202     }
 203 
 204     pe__clear_raw_action_flags(first_flags, "first action update",
 205                                pe_action_pseudo);
 206 
 207     if (type & pe_order_implies_then) {
 208         processed = TRUE;
 209         if (then->rsc) {
 210             changed |= then->rsc->cmds->update_actions(first, then, node,
 211                 first_flags & pe_action_optional, pe_action_optional,
 212                 pe_order_implies_then, data_set);
 213 
 214         } else if (!pcmk_is_set(first_flags, pe_action_optional)) {
 215             if (update_action_flags(then, pe_action_optional | pe_action_clear, __func__, __LINE__)) {
 216                 pe__set_graph_flags(changed, first, pe_graph_updated_then);
 217             }
 218         }
 219         if (changed) {
 220             pe_rsc_trace(then->rsc, "implies right: %s then %s: changed", first->uuid, then->uuid);
 221         } else {
 222             crm_trace("implies right: %s then %s %p", first->uuid, then->uuid, then->rsc);
 223         }
 224     }
 225 
 226     if ((type & pe_order_restart) && then->rsc) {
 227         enum pe_action_flags restart = (pe_action_optional | pe_action_runnable);
 228 
 229         processed = TRUE;
 230         changed |= then->rsc->cmds->update_actions(first, then, node,
 231                                                    first_flags, restart,
 232                                                    pe_order_restart, data_set);
 233         if (changed) {
 234             pe_rsc_trace(then->rsc, "restart: %s then %s: changed", first->uuid, then->uuid);
 235         } else {
 236             crm_trace("restart: %s then %s", first->uuid, then->uuid);
 237         }
 238     }
 239 
 240     if (type & pe_order_implies_first) {
 241         processed = TRUE;
 242         if (first->rsc) {
 243             changed |= first->rsc->cmds->update_actions(first, then, node,
 244                 first_flags, pe_action_optional, pe_order_implies_first,
 245                 data_set);
 246 
 247         } else if (!pcmk_is_set(first_flags, pe_action_optional)) {
 248             pe_rsc_trace(first->rsc, "first unrunnable: %s (%d) then %s (%d)",
 249                          first->uuid, pcmk_is_set(first_flags, pe_action_optional),
 250                          then->uuid, pcmk_is_set(then_flags, pe_action_optional));
 251             if (update_action_flags(first, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
 252                 pe__set_graph_flags(changed, first, pe_graph_updated_first);
 253             }
 254         }
 255 
 256         if (changed) {
 257             pe_rsc_trace(then->rsc, "implies left: %s then %s: changed", first->uuid, then->uuid);
 258         } else {
 259             crm_trace("implies left: %s (%d) then %s (%d)",
 260                       first->uuid, pcmk_is_set(first_flags, pe_action_optional),
 261                       then->uuid, pcmk_is_set(then_flags, pe_action_optional));
 262         }
 263     }
 264 
 265     if (type & pe_order_promoted_implies_first) {
 266         processed = TRUE;
 267         if (then->rsc) {
 268             changed |= then->rsc->cmds->update_actions(first, then, node,
 269                 first_flags & pe_action_optional, pe_action_optional,
 270                 pe_order_promoted_implies_first, data_set);
 271         }
 272 
 273         if (changed) {
 274             pe_rsc_trace(then->rsc,
 275                          "implies left when right resource is promoted: "
 276                          "%s then %s: changed", first->uuid, then->uuid);
 277         } else {
 278             crm_trace("implies left when right resource is promoted: "
 279                       "%s then %s", first->uuid, then->uuid);
 280         }
 281     }
 282 
 283     if (type & pe_order_one_or_more) {
 284         processed = TRUE;
 285         if (then->rsc) {
 286             changed |= then->rsc->cmds->update_actions(first, then, node,
 287                 first_flags, pe_action_runnable, pe_order_one_or_more,
 288                 data_set);
 289 
 290         } else if (pcmk_is_set(first_flags, pe_action_runnable)) {
 291             /* alright. a "first" action is considered runnable, incremente
 292              * the 'runnable_before' counter */
 293             then->runnable_before++;
 294 
 295             /* if the runnable before count for then exceeds the required number
 296              * of "before" runnable actions... mark then as runnable */
 297             if (then->runnable_before >= then->required_runnable_before) {
 298                 if (update_action_flags(then, pe_action_runnable, __func__, __LINE__)) {
 299                     pe__set_graph_flags(changed, first, pe_graph_updated_then);
 300                 }
 301             }
 302         }
 303         if (changed) {
 304             pe_rsc_trace(then->rsc, "runnable_one_or_more: %s then %s: changed", first->uuid,
 305                          then->uuid);
 306         } else {
 307             crm_trace("runnable_one_or_more: %s then %s", first->uuid, then->uuid);
 308         }
 309     }
 310 
 311     if (then->rsc && pcmk_is_set(type, pe_order_probe)) {
 312         processed = TRUE;
 313 
 314         if (!pcmk_is_set(first_flags, pe_action_runnable)
 315             && (first->rsc->running_on != NULL)) {
 316 
 317             pe_rsc_trace(then->rsc, "Ignoring %s then %s - %s is about to be stopped",
 318                          first->uuid, then->uuid, first->rsc->id);
 319             type = pe_order_none;
 320             order->type = pe_order_none;
 321 
 322         } else {
 323             pe_rsc_trace(then->rsc, "Enforcing %s then %s", first->uuid, then->uuid);
 324             changed |= then->rsc->cmds->update_actions(first, then, node,
 325                 first_flags, pe_action_runnable, pe_order_runnable_left,
 326                 data_set);
 327         }
 328 
 329         if (changed) {
 330             pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
 331         } else {
 332             crm_trace("runnable: %s then %s", first->uuid, then->uuid);
 333         }
 334     }
 335 
 336     if (type & pe_order_runnable_left) {
 337         processed = TRUE;
 338         if (then->rsc) {
 339             changed |= then->rsc->cmds->update_actions(first, then, node,
 340                 first_flags, pe_action_runnable, pe_order_runnable_left,
 341                 data_set);
 342 
 343         } else if (!pcmk_is_set(first_flags, pe_action_runnable)) {
 344             pe_rsc_trace(then->rsc, "then unrunnable: %s then %s", first->uuid, then->uuid);
 345             if (update_action_flags(then, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
 346                 pe__set_graph_flags(changed, first, pe_graph_updated_then);
 347             }
 348         }
 349         if (changed) {
 350             pe_rsc_trace(then->rsc, "runnable: %s then %s: changed", first->uuid, then->uuid);
 351         } else {
 352             crm_trace("runnable: %s then %s", first->uuid, then->uuid);
 353         }
 354     }
 355 
 356     if (type & pe_order_implies_first_migratable) {
 357         processed = TRUE;
 358         if (then->rsc) {
 359             changed |= then->rsc->cmds->update_actions(first, then, node,
 360                 first_flags, pe_action_optional,
 361                 pe_order_implies_first_migratable, data_set);
 362         }
 363         if (changed) {
 364             pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
 365         } else {
 366             crm_trace("optional: %s then %s", first->uuid, then->uuid);
 367         }
 368     }
 369 
 370     if (type & pe_order_pseudo_left) {
 371         processed = TRUE;
 372         if (then->rsc) {
 373             changed |= then->rsc->cmds->update_actions(first, then, node,
 374                 first_flags, pe_action_optional, pe_order_pseudo_left,
 375                 data_set);
 376         }
 377         if (changed) {
 378             pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
 379         } else {
 380             crm_trace("optional: %s then %s", first->uuid, then->uuid);
 381         }
 382     }
 383 
 384     if (type & pe_order_optional) {
 385         processed = TRUE;
 386         if (then->rsc) {
 387             changed |= then->rsc->cmds->update_actions(first, then, node,
 388                 first_flags, pe_action_runnable, pe_order_optional, data_set);
 389         }
 390         if (changed) {
 391             pe_rsc_trace(then->rsc, "optional: %s then %s: changed", first->uuid, then->uuid);
 392         } else {
 393             crm_trace("optional: %s then %s", first->uuid, then->uuid);
 394         }
 395     }
 396 
 397     if (type & pe_order_asymmetrical) {
 398         processed = TRUE;
 399         if (then->rsc) {
 400             changed |= then->rsc->cmds->update_actions(first, then, node,
 401                 first_flags, pe_action_runnable, pe_order_asymmetrical,
 402                 data_set);
 403         }
 404 
 405         if (changed) {
 406             pe_rsc_trace(then->rsc, "asymmetrical: %s then %s: changed", first->uuid, then->uuid);
 407         } else {
 408             crm_trace("asymmetrical: %s then %s", first->uuid, then->uuid);
 409         }
 410 
 411     }
 412 
 413     if ((first->flags & pe_action_runnable) && (type & pe_order_implies_then_printed)
 414         && (first_flags & pe_action_optional) == 0) {
 415         processed = TRUE;
 416         crm_trace("%s implies %s printed", first->uuid, then->uuid);
 417         update_action_flags(then, pe_action_print_always, __func__, __LINE__);  /* don't care about changed */
 418     }
 419 
 420     if (pcmk_is_set(type, pe_order_implies_first_printed)
 421         && !pcmk_is_set(then_flags, pe_action_optional)) {
 422 
 423         processed = TRUE;
 424         crm_trace("%s implies %s printed", then->uuid, first->uuid);
 425         update_action_flags(first, pe_action_print_always, __func__, __LINE__); /* don't care about changed */
 426     }
 427 
 428     if ((type & pe_order_implies_then
 429          || type & pe_order_implies_first
 430          || type & pe_order_restart)
 431         && first->rsc
 432         && pcmk__str_eq(first->task, RSC_STOP, pcmk__str_casei)
 433         && !pcmk_is_set(first->rsc->flags, pe_rsc_managed)
 434         && pcmk_is_set(first->rsc->flags, pe_rsc_block)
 435         && !pcmk_is_set(first->flags, pe_action_runnable)) {
 436 
 437         if (update_action_flags(then, pe_action_runnable | pe_action_clear, __func__, __LINE__)) {
 438             pe__set_graph_flags(changed, first, pe_graph_updated_then);
 439         }
 440 
 441         if (changed) {
 442             pe_rsc_trace(then->rsc, "unmanaged left: %s then %s: changed", first->uuid, then->uuid);
 443         } else {
 444             crm_trace("unmanaged left: %s then %s", first->uuid, then->uuid);
 445         }
 446     }
 447 
 448     if (processed == FALSE) {
 449         crm_trace("Constraint 0x%.6x not applicable", type);
 450     }
 451 
 452     return changed;
 453 }
 454 
 455 static void
 456 mark_start_blocked(pe_resource_t *rsc, pe_resource_t *reason,
     /* [previous][next][first][last][top][bottom][index][help] */
 457                    pe_working_set_t *data_set)
 458 {
 459     GList *gIter = rsc->actions;
 460     char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
 461 
 462     for (; gIter != NULL; gIter = gIter->next) {
 463         pe_action_t *action = (pe_action_t *) gIter->data;
 464 
 465         if (!pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
 466             continue;
 467         }
 468         if (pcmk_is_set(action->flags, pe_action_runnable)) {
 469             pe_action_set_flag_reason(__func__, __LINE__, action, NULL,
 470                                       reason_text, pe_action_runnable, FALSE);
 471             update_colo_start_chain(action, data_set);
 472             update_action(action, data_set);
 473         }
 474     }
 475     free(reason_text);
 476 }
 477 
 478 void
 479 update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 480 {
 481     GList *gIter = NULL;
 482     pe_resource_t *rsc = NULL;
 483 
 484     if (!pcmk_is_set(action->flags, pe_action_runnable)
 485         && pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
 486 
 487         rsc = uber_parent(action->rsc);
 488         if (rsc->parent) {
 489             /* For bundles, uber_parent() returns the clone, not the bundle, so
 490              * the existence of rsc->parent implies this is a bundle.
 491              * In this case, we need the bundle resource, so that we can check
 492              * if all containers are stopped/stopping.
 493              */
 494             rsc = rsc->parent;
 495         }
 496     }
 497 
 498     if (rsc == NULL || rsc->rsc_cons_lhs == NULL) {
 499         return;
 500     }
 501 
 502     /* if rsc has children, all the children need to have start set to
 503      * unrunnable before we follow the colo chain for the parent. */
 504     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 505         pe_resource_t *child = (pe_resource_t *)gIter->data;
 506         pe_action_t *start = find_first_action(child->actions, NULL, RSC_START, NULL);
 507         if ((start == NULL) || pcmk_is_set(start->flags, pe_action_runnable)) {
 508             return;
 509         }
 510     }
 511 
 512     for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
 513         pcmk__colocation_t *colocate_with = (pcmk__colocation_t *) gIter->data;
 514 
 515         if (colocate_with->score == INFINITY) {
 516             mark_start_blocked(colocate_with->rsc_lh, action->rsc, data_set);
 517         }
 518     }
 519 }
 520 
 521 gboolean
 522 update_action(pe_action_t *then, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 523 {
 524     GList *lpc = NULL;
 525     enum pe_graph_flags changed = pe_graph_none;
 526     int last_flags = then->flags;
 527 
 528     crm_trace("Processing %s (%s %s %s)",
 529               then->uuid,
 530               pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
 531               pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
 532               pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
 533                 : (then->node? then->node->details->uname : ""));
 534 
 535     if (pcmk_is_set(then->flags, pe_action_requires_any)) {
 536         /* initialize current known runnable before actions to 0
 537          * from here as graph_update_action is called for each of
 538          * then's before actions, this number will increment as
 539          * runnable 'first' actions are encountered */
 540         then->runnable_before = 0;
 541 
 542         /* for backwards compatibility with previous options that use
 543          * the 'requires_any' flag, initialize required to 1 if it is
 544          * not set. */ 
 545         if (then->required_runnable_before == 0) {
 546             then->required_runnable_before = 1;
 547         }
 548         pe__clear_action_flags(then, pe_action_runnable);
 549         /* We are relying on the pe_order_one_or_more clause of
 550          * graph_update_action(), called as part of the:
 551          *
 552          *    'if (first == other->action)'
 553          *
 554          * block below, to set this back if appropriate
 555          */
 556     }
 557 
 558     for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
 559         pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
 560         pe_action_t *first = other->action;
 561 
 562         pe_node_t *then_node = then->node;
 563         pe_node_t *first_node = first->node;
 564 
 565         enum pe_action_flags then_flags = 0;
 566         enum pe_action_flags first_flags = 0;
 567 
 568         if (first->rsc && first->rsc->variant == pe_group && pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
 569             first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
 570             if (first_node) {
 571                 crm_trace("First: Found node %s for %s", first_node->details->uname, first->uuid);
 572             }
 573         }
 574 
 575         if (then->rsc && then->rsc->variant == pe_group && pcmk__str_eq(then->task, RSC_START, pcmk__str_casei)) {
 576             then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
 577             if (then_node) {
 578                 crm_trace("Then: Found node %s for %s", then_node->details->uname, then->uuid);
 579             }
 580         }
 581         /* Disable constraint if it only applies when on same node, but isn't */
 582         if (pcmk_is_set(other->type, pe_order_same_node)
 583             && (first_node != NULL) && (then_node != NULL)
 584             && (first_node->details != then_node->details)) {
 585 
 586             crm_trace("Disabled constraint %s on %s -> %s on %s",
 587                        other->action->uuid, first_node->details->uname,
 588                        then->uuid, then_node->details->uname);
 589             other->type = pe_order_none;
 590             continue;
 591         }
 592 
 593         pe__clear_graph_flags(changed, then, pe_graph_updated_first);
 594 
 595         if (first->rsc && pcmk_is_set(other->type, pe_order_then_cancels_first)
 596             && !pcmk_is_set(then->flags, pe_action_optional)) {
 597 
 598             /* 'then' is required, so we must abandon 'first'
 599              * (e.g. a required stop cancels any agent reload).
 600              */
 601             pe__set_action_flags(other->action, pe_action_optional);
 602             if (!strcmp(first->task, CRMD_ACTION_RELOAD_AGENT)) {
 603                 pe__clear_resource_flags(first->rsc, pe_rsc_reload);
 604             }
 605         }
 606 
 607         if (first->rsc && then->rsc && (first->rsc != then->rsc)
 608             && (is_parent(then->rsc, first->rsc) == FALSE)) {
 609             first = rsc_expand_action(first);
 610         }
 611         if (first != other->action) {
 612             crm_trace("Ordering %s after %s instead of %s", then->uuid, first->uuid,
 613                       other->action->uuid);
 614         }
 615 
 616         first_flags = get_action_flags(first, then_node);
 617         then_flags = get_action_flags(then, first_node);
 618 
 619         crm_trace("Checking %s (%s %s %s) against %s (%s %s %s) filter=0x%.6x type=0x%.6x",
 620                   then->uuid,
 621                   pcmk_is_set(then_flags, pe_action_optional)? "optional" : "required",
 622                   pcmk_is_set(then_flags, pe_action_runnable)? "runnable" : "unrunnable",
 623                   pcmk_is_set(then_flags, pe_action_pseudo)? "pseudo"
 624                     : (then->node? then->node->details->uname : ""),
 625                   first->uuid,
 626                   pcmk_is_set(first_flags, pe_action_optional)? "optional" : "required",
 627                   pcmk_is_set(first_flags, pe_action_runnable)? "runnable" : "unrunnable",
 628                   pcmk_is_set(first_flags, pe_action_pseudo)? "pseudo"
 629                     : (first->node? first->node->details->uname : ""),
 630                   first_flags, other->type);
 631 
 632         if (first == other->action) {
 633             /*
 634              * 'first' was not expanded (e.g. from 'start' to 'running'), which could mean it:
 635              * - has no associated resource,
 636              * - was a primitive,
 637              * - was pre-expanded (e.g. 'running' instead of 'start')
 638              *
 639              * The third argument here to graph_update_action() is a node which is used under two conditions:
 640              * - Interleaving, in which case first->node and
 641              *   then->node are equal (and NULL)
 642              * - If 'then' is a clone, to limit the scope of the
 643              *   constraint to instances on the supplied node
 644              *
 645              */
 646             pe_node_t *node = then->node;
 647             changed |= graph_update_action(first, then, node, first_flags,
 648                                            then_flags, other, data_set);
 649 
 650             /* 'first' was for a complex resource (clone, group, etc),
 651              * create a new dependency if necessary
 652              */
 653         } else if (order_actions(first, then, other->type)) {
 654             /* This was the first time 'first' and 'then' were associated,
 655              * start again to get the new actions_before list
 656              */
 657             pe__set_graph_flags(changed, then,
 658                                 pe_graph_updated_then|pe_graph_disable);
 659         }
 660 
 661         if (changed & pe_graph_disable) {
 662             crm_trace("Disabled constraint %s -> %s in favor of %s -> %s",
 663                       other->action->uuid, then->uuid, first->uuid, then->uuid);
 664             pe__clear_graph_flags(changed, then, pe_graph_disable);
 665             other->type = pe_order_none;
 666         }
 667 
 668         if (changed & pe_graph_updated_first) {
 669             GList *lpc2 = NULL;
 670 
 671             crm_trace("Updated %s (first %s %s %s), processing dependents ",
 672                       first->uuid,
 673                       pcmk_is_set(first->flags, pe_action_optional)? "optional" : "required",
 674                       pcmk_is_set(first->flags, pe_action_runnable)? "runnable" : "unrunnable",
 675                       pcmk_is_set(first->flags, pe_action_pseudo)? "pseudo"
 676                         : (first->node? first->node->details->uname : ""));
 677             for (lpc2 = first->actions_after; lpc2 != NULL; lpc2 = lpc2->next) {
 678                 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc2->data;
 679 
 680                 update_action(other->action, data_set);
 681             }
 682             update_action(first, data_set);
 683         }
 684     }
 685 
 686     if (pcmk_is_set(then->flags, pe_action_requires_any)) {
 687         if (last_flags != then->flags) {
 688             pe__set_graph_flags(changed, then, pe_graph_updated_then);
 689         } else {
 690             pe__clear_graph_flags(changed, then, pe_graph_updated_then);
 691         }
 692     }
 693 
 694     if (changed & pe_graph_updated_then) {
 695         crm_trace("Updated %s (then %s %s %s), processing dependents ",
 696                   then->uuid,
 697                   pcmk_is_set(then->flags, pe_action_optional)? "optional" : "required",
 698                   pcmk_is_set(then->flags, pe_action_runnable)? "runnable" : "unrunnable",
 699                   pcmk_is_set(then->flags, pe_action_pseudo)? "pseudo"
 700                     : (then->node? then->node->details-> uname : ""));
 701 
 702         if (pcmk_is_set(last_flags, pe_action_runnable)
 703             && !pcmk_is_set(then->flags, pe_action_runnable)) {
 704             update_colo_start_chain(then, data_set);
 705         }
 706         update_action(then, data_set);
 707         for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
 708             pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
 709 
 710             update_action(other->action, data_set);
 711         }
 712     }
 713 
 714     return FALSE;
 715 }
 716 
 717 gboolean
 718 shutdown_constraints(pe_node_t * node, pe_action_t * shutdown_op, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 719 {
 720     /* add the stop to the before lists so it counts as a pre-req
 721      * for the shutdown
 722      */
 723     GList *lpc = NULL;
 724 
 725     for (lpc = data_set->actions; lpc != NULL; lpc = lpc->next) {
 726         pe_action_t *action = (pe_action_t *) lpc->data;
 727 
 728         if (action->rsc == NULL || action->node == NULL) {
 729             continue;
 730         } else if (action->node->details != node->details) {
 731             continue;
 732         } else if (pcmk_is_set(action->rsc->flags, pe_rsc_maintenance)) {
 733             pe_rsc_trace(action->rsc, "Skipping %s: maintenance mode", action->uuid);
 734             continue;
 735         } else if (node->details->maintenance) {
 736             pe_rsc_trace(action->rsc, "Skipping %s: node %s is in maintenance mode",
 737                          action->uuid, node->details->uname);
 738             continue;
 739         } else if (!pcmk__str_eq(action->task, RSC_STOP, pcmk__str_casei)) {
 740             continue;
 741         } else if (!pcmk_any_flags_set(action->rsc->flags,
 742                                        pe_rsc_managed|pe_rsc_block)) {
 743             /*
 744              * If another action depends on this one, we may still end up blocking
 745              */
 746             pe_rsc_trace(action->rsc, "Skipping %s: unmanaged", action->uuid);
 747             continue;
 748         }
 749 
 750         pe_rsc_trace(action->rsc, "Ordering %s before shutdown on %s", action->uuid,
 751                      node->details->uname);
 752         pe__clear_action_flags(action, pe_action_optional);
 753         custom_action_order(action->rsc, NULL, action,
 754                             NULL, strdup(CRM_OP_SHUTDOWN), shutdown_op,
 755                             pe_order_optional | pe_order_runnable_left, data_set);
 756     }
 757 
 758     return TRUE;
 759 }
 760 
 761 /*!
 762  * \internal
 763  * \brief Order all actions appropriately relative to a fencing operation
 764  *
 765  * Ensure start operations of affected resources are ordered after fencing,
 766  * imply stop and demote operations of affected resources by marking them as
 767  * pseudo-actions, etc.
 768  *
 769  * \param[in]     stonith_op  Fencing operation
 770  * \param[in,out] data_set    Working set of cluster
 771  */
 772 void
 773 pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 774 {
 775     CRM_CHECK(stonith_op && data_set, return);
 776     for (GList *r = data_set->resources; r != NULL; r = r->next) {
 777         rsc_stonith_ordering((pe_resource_t *) r->data, stonith_op, data_set);
 778     }
 779 }
 780 
 781 static pe_node_t *
 782 get_router_node(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 783 {
 784     pe_node_t *began_on = NULL;
 785     pe_node_t *ended_on = NULL;
 786     bool partial_migration = FALSE;
 787     const char *task = action->task;
 788 
 789     if (pcmk__str_eq(task, CRM_OP_FENCE, pcmk__str_casei)
 790         || !pe__is_guest_or_remote_node(action->node)) {
 791         return NULL;
 792     }
 793 
 794     CRM_ASSERT(action->node->details->remote_rsc != NULL);
 795 
 796     began_on = pe__current_node(action->node->details->remote_rsc);
 797     ended_on = action->node->details->remote_rsc->allocated_to;
 798     if (action->node->details->remote_rsc
 799         && (action->node->details->remote_rsc->container == NULL)
 800         && action->node->details->remote_rsc->partial_migration_target) {
 801         partial_migration = TRUE;
 802     }
 803 
 804     if (began_on == NULL) {
 805         crm_trace("Routing %s for %s through remote connection's "
 806                   "next node %s (starting)%s",
 807                   action->task, (action->rsc? action->rsc->id : "no resource"),
 808                   (ended_on? ended_on->details->uname : "none"),
 809                   partial_migration? " (partial migration)" : "");
 810         return ended_on;
 811     }
 812 
 813     if (ended_on == NULL) {
 814         crm_trace("Routing %s for %s through remote connection's "
 815                   "current node %s (stopping)%s",
 816                   action->task, (action->rsc? action->rsc->id : "no resource"),
 817                   (began_on? began_on->details->uname : "none"),
 818                   partial_migration? " (partial migration)" : "");
 819         return began_on;
 820     }
 821 
 822     if (began_on->details == ended_on->details) {
 823         crm_trace("Routing %s for %s through remote connection's "
 824                   "current node %s (not moving)%s",
 825                   action->task, (action->rsc? action->rsc->id : "no resource"),
 826                   (began_on? began_on->details->uname : "none"),
 827                   partial_migration? " (partial migration)" : "");
 828         return began_on;
 829     }
 830 
 831     /* If we get here, the remote connection is moving during this transition.
 832      * This means some actions for resources behind the connection will get
 833      * routed through the cluster node the connection reource is currently on,
 834      * and others are routed through the cluster node the connection will end up
 835      * on.
 836      */
 837 
 838     if (pcmk__str_eq(task, "notify", pcmk__str_casei)) {
 839         task = g_hash_table_lookup(action->meta, "notify_operation");
 840     }
 841 
 842     /*
 843      * Stop, demote, and migration actions must occur before the connection can
 844      * move (these actions are required before the remote resource can stop). In
 845      * this case, we know these actions have to be routed through the initial
 846      * cluster node the connection resource lived on before the move takes
 847      * place.
 848      *
 849      * The exception is a partial migration of a (non-guest) remote connection
 850      * resource; in that case, all actions (even these) will be ordered after
 851      * the connection's pseudo-start on the migration target, so the target is
 852      * the router node.
 853      */
 854     if (pcmk__strcase_any_of(task, "cancel", "stop", "demote", "migrate_from",
 855                              "migrate_to", NULL) && !partial_migration) {
 856         crm_trace("Routing %s for %s through remote connection's "
 857                   "current node %s (moving)%s",
 858                   action->task, (action->rsc? action->rsc->id : "no resource"),
 859                   (began_on? began_on->details->uname : "none"),
 860                   partial_migration? " (partial migration)" : "");
 861         return began_on;
 862     }
 863 
 864     /* Everything else (start, promote, monitor, probe, refresh,
 865      * clear failcount, delete, ...) must occur after the connection starts on
 866      * the node it is moving to.
 867      */
 868     crm_trace("Routing %s for %s through remote connection's "
 869               "next node %s (moving)%s",
 870               action->task, (action->rsc? action->rsc->id : "no resource"),
 871               (ended_on? ended_on->details->uname : "none"),
 872               partial_migration? " (partial migration)" : "");
 873     return ended_on;
 874 }
 875 
 876 /*!
 877  * \internal
 878  * \brief Add an XML node tag for a specified ID
 879  *
 880  * \param[in]     id      Node UUID to add
 881  * \param[in,out] xml     Parent XML tag to add to
 882  */
 883 static xmlNode*
 884 add_node_to_xml_by_id(const char *id, xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 885 {
 886     xmlNode *node_xml;
 887 
 888     node_xml = create_xml_node(xml, XML_CIB_TAG_NODE);
 889     crm_xml_add(node_xml, XML_ATTR_UUID, id);
 890 
 891     return node_xml;
 892 }
 893 
 894 /*!
 895  * \internal
 896  * \brief Add an XML node tag for a specified node
 897  *
 898  * \param[in]     node  Node to add
 899  * \param[in,out] xml   XML to add node to
 900  */
 901 static void
 902 add_node_to_xml(const pe_node_t *node, void *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 903 {
 904     add_node_to_xml_by_id(node->details->id, (xmlNode *) xml);
 905 }
 906 
 907 /*!
 908  * \internal
 909  * \brief Add XML with nodes that need an update of their maintenance state
 910  *
 911  * \param[in,out] xml       Parent XML tag to add to
 912  * \param[in]     data_set  Working set for cluster
 913  */
 914 static int
 915 add_maintenance_nodes(xmlNode *xml, const pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 916 {
 917     GList *gIter = NULL;
 918     xmlNode *maintenance =
 919         xml?create_xml_node(xml, XML_GRAPH_TAG_MAINTENANCE):NULL;
 920     int count = 0;
 921 
 922     for (gIter = data_set->nodes; gIter != NULL;
 923          gIter = gIter->next) {
 924         pe_node_t *node = (pe_node_t *) gIter->data;
 925         struct pe_node_shared_s *details = node->details;
 926 
 927         if (!pe__is_guest_or_remote_node(node)) {
 928             continue; /* just remote nodes need to know atm */
 929         }
 930 
 931         if (details->maintenance != details->remote_maintenance) {
 932             if (maintenance) {
 933                 crm_xml_add(
 934                     add_node_to_xml_by_id(node->details->id, maintenance),
 935                     XML_NODE_IS_MAINTENANCE, details->maintenance?"1":"0");
 936             }
 937             count++;
 938         }
 939     }
 940     crm_trace("%s %d nodes to adjust maintenance-mode "
 941               "to transition", maintenance?"Added":"Counted", count);
 942     return count;
 943 }
 944 
 945 /*!
 946  * \internal
 947  * \brief Add pseudo action with nodes needing maintenance state update
 948  *
 949  * \param[in,out] data_set  Working set for cluster
 950  */
 951 void
 952 add_maintenance_update(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 953 {
 954     pe_action_t *action = NULL;
 955 
 956     if (add_maintenance_nodes(NULL, data_set)) {
 957         crm_trace("adding maintenance state update pseudo action");
 958         action = get_pseudo_op(CRM_OP_MAINTENANCE_NODES, data_set);
 959         pe__set_action_flags(action, pe_action_print_always);
 960     }
 961 }
 962 
 963 /*!
 964  * \internal
 965  * \brief Add XML with nodes that an action is expected to bring down
 966  *
 967  * If a specified action is expected to bring any nodes down, add an XML block
 968  * with their UUIDs. When a node is lost, this allows the controller to
 969  * determine whether it was expected.
 970  *
 971  * \param[in,out] xml       Parent XML tag to add to
 972  * \param[in]     action    Action to check for downed nodes
 973  * \param[in]     data_set  Working set for cluster
 974  */
 975 static void
 976 add_downed_nodes(xmlNode *xml, const pe_action_t *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 977                  const pe_working_set_t *data_set)
 978 {
 979     CRM_CHECK(xml && action && action->node && data_set, return);
 980 
 981     if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
 982 
 983         /* Shutdown makes the action's node down */
 984         xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
 985         add_node_to_xml_by_id(action->node->details->id, downed);
 986 
 987     } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
 988 
 989         /* Fencing makes the action's node and any hosted guest nodes down */
 990         const char *fence = g_hash_table_lookup(action->meta, "stonith_action");
 991 
 992         if (pcmk__strcase_any_of(fence, "off", "reboot", NULL)) {
 993             xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
 994             add_node_to_xml_by_id(action->node->details->id, downed);
 995             pe_foreach_guest_node(data_set, action->node, add_node_to_xml, downed);
 996         }
 997 
 998     } else if (action->rsc && action->rsc->is_remote_node
 999                && pcmk__str_eq(action->task, CRMD_ACTION_STOP, pcmk__str_casei)) {
1000 
1001         /* Stopping a remote connection resource makes connected node down,
1002          * unless it's part of a migration
1003          */
1004         GList *iter;
1005         pe_action_t *input;
1006         gboolean migrating = FALSE;
1007 
1008         for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1009             input = ((pe_action_wrapper_t *) iter->data)->action;
1010             if (input->rsc && pcmk__str_eq(action->rsc->id, input->rsc->id, pcmk__str_casei)
1011                 && pcmk__str_eq(input->task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
1012                 migrating = TRUE;
1013                 break;
1014             }
1015         }
1016         if (!migrating) {
1017             xmlNode *downed = create_xml_node(xml, XML_GRAPH_TAG_DOWNED);
1018             add_node_to_xml_by_id(action->rsc->id, downed);
1019         }
1020     }
1021 }
1022 
1023 static bool
1024 should_lock_action(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1025 {
1026     // Only actions taking place on resource's lock node are locked
1027     if ((action->rsc->lock_node == NULL) || (action->node == NULL)
1028         || (action->node->details != action->rsc->lock_node->details)) {
1029         return false;
1030     }
1031 
1032     /* During shutdown, only stops are locked (otherwise, another action such as
1033      * a demote would cause the controller to clear the lock)
1034      */
1035     if (action->node->details->shutdown && action->task
1036         && strcmp(action->task, RSC_STOP)) {
1037         return false;
1038     }
1039 
1040     return true;
1041 }
1042 
1043 static xmlNode *
1044 action2xml(pe_action_t * action, gboolean as_input, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1045 {
1046     gboolean needs_node_info = TRUE;
1047     gboolean needs_maintenance_info = FALSE;
1048     xmlNode *action_xml = NULL;
1049     xmlNode *args_xml = NULL;
1050 #if ENABLE_VERSIONED_ATTRS
1051     pe_rsc_action_details_t *rsc_details = NULL;
1052 #endif
1053 
1054     if (action == NULL) {
1055         return NULL;
1056     }
1057 
1058     if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
1059         /* All fences need node info; guest node fences are pseudo-events */
1060         action_xml = create_xml_node(NULL,
1061                                      pcmk_is_set(action->flags, pe_action_pseudo)?
1062                                      XML_GRAPH_TAG_PSEUDO_EVENT :
1063                                      XML_GRAPH_TAG_CRM_EVENT);
1064 
1065     } else if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1066         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1067 
1068     } else if (pcmk__str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT, pcmk__str_casei)) {
1069         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1070 
1071     } else if (pcmk__str_eq(action->task, CRM_OP_LRM_REFRESH, pcmk__str_casei)) {
1072         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1073 
1074     } else if (pcmk__str_eq(action->task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
1075         // CIB-only clean-up for shutdown locks
1076         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
1077         crm_xml_add(action_xml, PCMK__XA_MODE, XML_TAG_CIB);
1078 
1079 /*      } else if(pcmk__str_eq(action->task, RSC_PROBED, pcmk__str_casei)) { */
1080 /*              action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */
1081 
1082     } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
1083         if (pcmk__str_eq(action->task, CRM_OP_MAINTENANCE_NODES, pcmk__str_casei)) {
1084             needs_maintenance_info = TRUE;
1085         }
1086         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_PSEUDO_EVENT);
1087         needs_node_info = FALSE;
1088 
1089     } else {
1090         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
1091 
1092 #if ENABLE_VERSIONED_ATTRS
1093         rsc_details = pe_rsc_action_details(action);
1094 #endif
1095     }
1096 
1097     crm_xml_add_int(action_xml, XML_ATTR_ID, action->id);
1098     crm_xml_add(action_xml, XML_LRM_ATTR_TASK, action->task);
1099     if (action->rsc != NULL && action->rsc->clone_name != NULL) {
1100         char *clone_key = NULL;
1101         guint interval_ms;
1102 
1103         if (pcmk__guint_from_hash(action->meta,
1104                                   XML_LRM_ATTR_INTERVAL_MS, 0,
1105                                   &interval_ms) != pcmk_rc_ok) {
1106             interval_ms = 0;
1107         }
1108 
1109         if (pcmk__str_eq(action->task, RSC_NOTIFY, pcmk__str_casei)) {
1110             const char *n_type = g_hash_table_lookup(action->meta, "notify_type");
1111             const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1112 
1113             CRM_CHECK(n_type != NULL, crm_err("No notify type value found for %s", action->uuid));
1114             CRM_CHECK(n_task != NULL,
1115                       crm_err("No notify operation value found for %s", action->uuid));
1116             clone_key = pcmk__notify_key(action->rsc->clone_name,
1117                                          n_type, n_task);
1118 
1119         } else if(action->cancel_task) {
1120             clone_key = pcmk__op_key(action->rsc->clone_name,
1121                                      action->cancel_task, interval_ms);
1122         } else {
1123             clone_key = pcmk__op_key(action->rsc->clone_name,
1124                                      action->task, interval_ms);
1125         }
1126 
1127         CRM_CHECK(clone_key != NULL, crm_err("Could not generate a key for %s", action->uuid));
1128         crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, clone_key);
1129         crm_xml_add(action_xml, "internal_" XML_LRM_ATTR_TASK_KEY, action->uuid);
1130         free(clone_key);
1131 
1132     } else {
1133         crm_xml_add(action_xml, XML_LRM_ATTR_TASK_KEY, action->uuid);
1134     }
1135 
1136     if (needs_node_info && action->node != NULL) {
1137         pe_node_t *router_node = get_router_node(action);
1138 
1139         crm_xml_add(action_xml, XML_LRM_ATTR_TARGET, action->node->details->uname);
1140         crm_xml_add(action_xml, XML_LRM_ATTR_TARGET_UUID, action->node->details->id);
1141         if (router_node) {
1142             crm_xml_add(action_xml, XML_LRM_ATTR_ROUTER_NODE, router_node->details->uname);
1143         }
1144 
1145         g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET), strdup(action->node->details->uname));
1146         g_hash_table_insert(action->meta, strdup(XML_LRM_ATTR_TARGET_UUID), strdup(action->node->details->id));
1147     }
1148 
1149     /* No details if this action is only being listed in the inputs section */
1150     if (as_input) {
1151         return action_xml;
1152     }
1153 
1154     if (action->rsc && !pcmk_is_set(action->flags, pe_action_pseudo)) {
1155         int lpc = 0;
1156         xmlNode *rsc_xml = NULL;
1157         const char *attr_list[] = {
1158             XML_AGENT_ATTR_CLASS,
1159             XML_AGENT_ATTR_PROVIDER,
1160             XML_ATTR_TYPE
1161         };
1162 
1163         /* If a resource is locked to a node via shutdown-lock, mark its actions
1164          * so the controller can preserve the lock when the action completes.
1165          */
1166         if (should_lock_action(action)) {
1167             crm_xml_add_ll(action_xml, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
1168                            (long long) action->rsc->lock_time);
1169         }
1170 
1171         // List affected resource
1172 
1173         rsc_xml = create_xml_node(action_xml,
1174                                   crm_element_name(action->rsc->xml));
1175         if (pcmk_is_set(action->rsc->flags, pe_rsc_orphan)
1176             && action->rsc->clone_name) {
1177             /* Do not use the 'instance free' name here as that
1178              * might interfere with the instance we plan to keep.
1179              * Ie. if there are more than two named /anonymous/
1180              * instances on a given node, we need to make sure the
1181              * command goes to the right one.
1182              *
1183              * Keep this block, even when everyone is using
1184              * 'instance free' anonymous clone names - it means
1185              * we'll do the right thing if anyone toggles the
1186              * unique flag to 'off'
1187              */
1188             crm_debug("Using orphan clone name %s instead of %s", action->rsc->id,
1189                       action->rsc->clone_name);
1190             crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->clone_name);
1191             crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1192 
1193         } else if (!pcmk_is_set(action->rsc->flags, pe_rsc_unique)) {
1194             const char *xml_id = ID(action->rsc->xml);
1195 
1196             crm_debug("Using anonymous clone name %s for %s (aka. %s)", xml_id, action->rsc->id,
1197                       action->rsc->clone_name);
1198 
1199             /* ID is what we'd like client to use
1200              * ID_LONG is what they might know it as instead
1201              *
1202              * ID_LONG is only strictly needed /here/ during the
1203              * transition period until all nodes in the cluster
1204              * are running the new software /and/ have rebooted
1205              * once (meaning that they've only ever spoken to a DC
1206              * supporting this feature).
1207              *
1208              * If anyone toggles the unique flag to 'on', the
1209              * 'instance free' name will correspond to an orphan
1210              * and fall into the clause above instead
1211              */
1212             crm_xml_add(rsc_xml, XML_ATTR_ID, xml_id);
1213             if (action->rsc->clone_name && !pcmk__str_eq(xml_id, action->rsc->clone_name, pcmk__str_casei)) {
1214                 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->clone_name);
1215             } else {
1216                 crm_xml_add(rsc_xml, XML_ATTR_ID_LONG, action->rsc->id);
1217             }
1218 
1219         } else {
1220             CRM_ASSERT(action->rsc->clone_name == NULL);
1221             crm_xml_add(rsc_xml, XML_ATTR_ID, action->rsc->id);
1222         }
1223 
1224         for (lpc = 0; lpc < PCMK__NELEM(attr_list); lpc++) {
1225             crm_xml_add(rsc_xml, attr_list[lpc],
1226                         g_hash_table_lookup(action->rsc->meta, attr_list[lpc]));
1227         }
1228     }
1229 
1230     /* List any attributes in effect */
1231     args_xml = create_xml_node(NULL, XML_TAG_ATTRS);
1232     crm_xml_add(args_xml, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
1233 
1234     g_hash_table_foreach(action->extra, hash2field, args_xml);
1235     if (action->rsc != NULL && action->node) {
1236         // Get the resource instance attributes, evaluated properly for node
1237         GHashTable *params = pe_rsc_params(action->rsc, action->node, data_set);
1238 
1239         /* REMOTE_CONTAINER_HACK: If this is a remote connection resource with
1240          * addr="#uname", pull the actual value from the parameters evaluated
1241          * without a node (which was put there earlier in stage8() when the
1242          * bundle's expand() method was called).
1243          */
1244         const char *remote_addr = g_hash_table_lookup(params,
1245                                                       XML_RSC_ATTR_REMOTE_RA_ADDR);
1246 
1247         if (pcmk__str_eq(remote_addr, "#uname", pcmk__str_none)) {
1248             GHashTable *base = pe_rsc_params(action->rsc, NULL, data_set);
1249 
1250             remote_addr = g_hash_table_lookup(base,
1251                                               XML_RSC_ATTR_REMOTE_RA_ADDR);
1252             if (remote_addr != NULL) {
1253                 g_hash_table_insert(params, strdup(XML_RSC_ATTR_REMOTE_RA_ADDR),
1254                                     strdup(remote_addr));
1255             }
1256         }
1257 
1258         g_hash_table_foreach(params, hash2smartfield, args_xml);
1259 
1260 #if ENABLE_VERSIONED_ATTRS
1261         {
1262             xmlNode *versioned_parameters = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
1263 
1264             pe_get_versioned_attributes(versioned_parameters, action->rsc,
1265                                         action->node, data_set);
1266             if (xml_has_children(versioned_parameters)) {
1267                 add_node_copy(action_xml, versioned_parameters);
1268             }
1269             free_xml(versioned_parameters);
1270         }
1271 #endif
1272 
1273     } else if(action->rsc && action->rsc->variant <= pe_native) {
1274         GHashTable *params = pe_rsc_params(action->rsc, NULL, data_set);
1275 
1276         g_hash_table_foreach(params, hash2smartfield, args_xml);
1277 
1278 #if ENABLE_VERSIONED_ATTRS
1279         if (xml_has_children(action->rsc->versioned_parameters)) {
1280             add_node_copy(action_xml, action->rsc->versioned_parameters);
1281         }
1282 #endif
1283     }
1284 
1285 #if ENABLE_VERSIONED_ATTRS
1286     if (rsc_details) {
1287         if (xml_has_children(rsc_details->versioned_parameters)) {
1288             add_node_copy(action_xml, rsc_details->versioned_parameters);
1289         }
1290 
1291         if (xml_has_children(rsc_details->versioned_meta)) {
1292             add_node_copy(action_xml, rsc_details->versioned_meta);
1293         }
1294     }
1295 #endif
1296 
1297     g_hash_table_foreach(action->meta, hash2metafield, args_xml);
1298     if (action->rsc != NULL) {
1299         const char *value = g_hash_table_lookup(action->rsc->meta, "external-ip");
1300         pe_resource_t *parent = action->rsc;
1301 
1302         while (parent != NULL) {
1303             parent->cmds->append_meta(parent, args_xml);
1304             parent = parent->parent;
1305         }
1306 
1307         if(value) {
1308             hash2smartfield((gpointer)"pcmk_external_ip", (gpointer)value, (gpointer)args_xml);
1309         }
1310 
1311         if (action->node && /* make clang analyzer happy */
1312             pe__is_guest_node(action->node)) {
1313             pe_node_t *host = NULL;
1314             enum action_tasks task = text2task(action->task);
1315 
1316             if(task == action_notify || task == action_notified) {
1317                 const char *n_task = g_hash_table_lookup(action->meta, "notify_operation");
1318                 task = text2task(n_task);
1319             }
1320 
1321             // Differentiate between up and down actions
1322             switch (task) {
1323                 case stop_rsc:
1324                 case stopped_rsc:
1325                 case action_demote:
1326                 case action_demoted:
1327                     host = pe__current_node(action->node->details->remote_rsc->container);
1328                     break;
1329                 case start_rsc:
1330                 case started_rsc:
1331                 case monitor_rsc:
1332                 case action_promote:
1333                 case action_promoted:
1334                     host = action->node->details->remote_rsc->container->allocated_to;
1335                     break;
1336                 default:
1337                     break;
1338             }
1339 
1340             if(host) {
1341                 hash2metafield((gpointer)XML_RSC_ATTR_TARGET,
1342                                (gpointer)g_hash_table_lookup(action->rsc->meta, XML_RSC_ATTR_TARGET), (gpointer)args_xml);
1343                 hash2metafield((gpointer) PCMK__ENV_PHYSICAL_HOST,
1344                                (gpointer)host->details->uname,
1345                                (gpointer)args_xml);
1346             }
1347         }
1348 
1349     } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei) && action->node) {
1350         /* Pass the node's attributes as meta-attributes.
1351          *
1352          * @TODO: Determine whether it is still necessary to do this. It was
1353          * added in 33d99707, probably for the libfence-based implementation in
1354          * c9a90bd, which is no longer used.
1355          */
1356         g_hash_table_foreach(action->node->details->attrs, hash2metafield, args_xml);
1357     }
1358 
1359     sorted_xml(args_xml, action_xml, FALSE);
1360     free_xml(args_xml);
1361 
1362     /* List any nodes this action is expected to make down */
1363     if (needs_node_info && (action->node != NULL)) {
1364         add_downed_nodes(action_xml, action, data_set);
1365     }
1366 
1367     if (needs_maintenance_info) {
1368         add_maintenance_nodes(action_xml, data_set);
1369     }
1370 
1371     crm_log_xml_trace(action_xml, "dumped action");
1372     return action_xml;
1373 }
1374 
1375 static bool
1376 should_dump_action(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1377 {
1378     CRM_CHECK(action != NULL, return false);
1379 
1380     if (pcmk_is_set(action->flags, pe_action_dumped)) {
1381         crm_trace("Action %s (%d) already dumped", action->uuid, action->id);
1382         return false;
1383 
1384     } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1385                && pcmk__str_eq(action->task, CRM_OP_PROBED, pcmk__str_casei)) {
1386         GList *lpc = NULL;
1387 
1388         /* This is a horrible but convenient hack
1389          *
1390          * It mimimizes the number of actions with unsatisfied inputs
1391          * (i.e. not included in the graph)
1392          *
1393          * This in turn, means we can be more concise when printing
1394          * aborted/incomplete graphs.
1395          *
1396          * It also makes it obvious which node is preventing
1397          * probe_complete from running (presumably because it is only
1398          * partially up)
1399          *
1400          * For these reasons we tolerate such perversions
1401          */
1402 
1403         for (lpc = action->actions_after; lpc != NULL; lpc = lpc->next) {
1404             pe_action_wrapper_t *wrapper = (pe_action_wrapper_t *) lpc->data;
1405 
1406             if (!pcmk_is_set(wrapper->action->flags, pe_action_runnable)) {
1407                 /* Only interested in runnable operations */
1408             } else if (!pcmk__str_eq(wrapper->action->task, RSC_START, pcmk__str_casei)) {
1409                 /* Only interested in start operations */
1410             } else if (pcmk_is_set(wrapper->action->flags, pe_action_dumped)
1411                        || should_dump_action(wrapper->action)) {
1412                 crm_trace("Action %s (%d) should be dumped: "
1413                           "dependency of %s (%d)",
1414                           action->uuid, action->id,
1415                           wrapper->action->uuid, wrapper->action->id);
1416                 return true;
1417             }
1418         }
1419     }
1420 
1421     if (!pcmk_is_set(action->flags, pe_action_runnable)) {
1422         crm_trace("Ignoring action %s (%d): unrunnable",
1423                   action->uuid, action->id);
1424         return false;
1425 
1426     } else if (pcmk_is_set(action->flags, pe_action_optional)
1427                && !pcmk_is_set(action->flags, pe_action_print_always)) {
1428         crm_trace("Ignoring action %s (%d): optional",
1429                   action->uuid, action->id);
1430         return false;
1431 
1432     // Monitors should be dumped even for unmanaged resources
1433     } else if (action->rsc && !pcmk_is_set(action->rsc->flags, pe_rsc_managed)
1434                && !pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)) {
1435 
1436         const char *interval_ms_s = g_hash_table_lookup(action->meta,
1437                                                         XML_LRM_ATTR_INTERVAL_MS);
1438 
1439         // Cancellation of recurring monitors should still be dumped
1440         if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)) {
1441             crm_trace("Ignoring action %s (%d): for unmanaged resource (%s)",
1442                       action->uuid, action->id, action->rsc->id);
1443             return false;
1444         }
1445     }
1446 
1447     if (pcmk_is_set(action->flags, pe_action_pseudo) ||
1448         pcmk__strcase_any_of(action->task, CRM_OP_FENCE, CRM_OP_SHUTDOWN, NULL)) {
1449         /* skip the next checks */
1450         return true;
1451     }
1452 
1453     if (action->node == NULL) {
1454         pe_err("Skipping action %s (%d) "
1455                "because it was not allocated to a node (bug?)",
1456                action->uuid, action->id);
1457         log_action(LOG_DEBUG, "Unallocated action", action, false);
1458         return false;
1459 
1460     } else if (pcmk_is_set(action->flags, pe_action_dc)) {
1461         crm_trace("Action %s (%d) should be dumped: "
1462                   "can run on DC instead of %s",
1463                   action->uuid, action->id, action->node->details->uname);
1464 
1465     } else if (pe__is_guest_node(action->node)
1466                && !action->node->details->remote_requires_reset) {
1467         crm_trace("Action %s (%d) should be dumped: "
1468                   "assuming will be runnable on guest node %s",
1469                   action->uuid, action->id, action->node->details->uname);
1470 
1471     } else if (action->node->details->online == false) {
1472         pe_err("Skipping action %s (%d) "
1473                "because it was scheduled for offline node (bug?)",
1474                action->uuid, action->id);
1475         log_action(LOG_DEBUG, "Action for offline node", action, FALSE);
1476         return false;
1477 #if 0
1478         /* but this would also affect resources that can be safely
1479          *  migrated before a fencing op
1480          */
1481     } else if (action->node->details->unclean == false) {
1482         pe_err("Skipping action %s (%d) "
1483                "because it was scheduled for unclean node (bug?)",
1484                action->uuid, action->id);
1485         log_action(LOG_DEBUG, "Action for unclean node", action, false);
1486         return false;
1487 #endif
1488     }
1489     return true;
1490 }
1491 
1492 /* lowest to highest */
1493 static gint
1494 sort_action_id(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
1495 {
1496     const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1497     const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1498 
1499     if (a == NULL) {
1500         return 1;
1501     }
1502     if (b == NULL) {
1503         return -1;
1504     }
1505 
1506     if (action_wrapper1->action->id > action_wrapper2->action->id) {
1507         return -1;
1508     }
1509 
1510     if (action_wrapper1->action->id < action_wrapper2->action->id) {
1511         return 1;
1512     }
1513     return 0;
1514 }
1515 
1516 /*!
1517  * \internal
1518  * \brief Check whether an action input should be in the transition graph
1519  *
1520  * \param[in]     action  Action to check
1521  * \param[in,out] input   Action input to check
1522  *
1523  * \return true if input should be in graph, false otherwise
1524  * \note This function may not only check an input, but disable it under certian
1525  *       circumstances (load or anti-colocation orderings that are not needed).
1526  */
1527 static bool
1528 check_dump_input(pe_action_t *action, pe_action_wrapper_t *input)
     /* [previous][next][first][last][top][bottom][index][help] */
1529 {
1530     int type = input->type;
1531 
1532     if (input->state == pe_link_dumped) {
1533         return true;
1534     }
1535 
1536     pe__clear_order_flags(type, pe_order_implies_first_printed
1537                                 |pe_order_implies_then_printed
1538                                 |pe_order_optional);
1539 
1540     if (input->type == pe_order_none) {
1541         crm_trace("Ignoring %s (%d) input %s (%d): "
1542                   "ordering disabled",
1543                   action->uuid, action->id,
1544                   input->action->uuid, input->action->id);
1545         return false;
1546 
1547     } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1548                && (type == pe_order_none)
1549                && !pcmk__str_eq(input->action->uuid, CRM_OP_PROBED, pcmk__str_casei)) {
1550         crm_trace("Ignoring %s (%d) input %s (%d): "
1551                   "optional and input unrunnable",
1552                   action->uuid, action->id,
1553                   input->action->uuid, input->action->id);
1554         return false;
1555 
1556     } else if (!pcmk_is_set(input->action->flags, pe_action_runnable)
1557                && pcmk_is_set(input->type, pe_order_one_or_more)) {
1558         crm_trace("Ignoring %s (%d) input %s (%d): "
1559                   "one-or-more and input unrunnable",
1560                   action->uuid, action->id,
1561                   input->action->uuid, input->action->id);
1562         return false;
1563 
1564     } else if (pcmk_is_set(action->flags, pe_action_pseudo)
1565                && pcmk_is_set(input->type, pe_order_stonith_stop)) {
1566         crm_trace("Ignoring %s (%d) input %s (%d): "
1567                   "stonith stop but action is pseudo",
1568                   action->uuid, action->id,
1569                   input->action->uuid, input->action->id);
1570         return false;
1571 
1572     } else if (pcmk_is_set(input->type, pe_order_implies_first_migratable)
1573                && !pcmk_is_set(input->action->flags, pe_action_runnable)) {
1574         crm_trace("Ignoring %s (%d) input %s (%d): "
1575                   "implies input migratable but input unrunnable",
1576                   action->uuid, action->id,
1577                   input->action->uuid, input->action->id);
1578         return false;
1579 
1580     } else if (pcmk_is_set(input->type, pe_order_apply_first_non_migratable)
1581                && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)) {
1582         crm_trace("Ignoring %s (%d) input %s (%d): "
1583                   "only if input unmigratable but input unrunnable",
1584                   action->uuid, action->id,
1585                   input->action->uuid, input->action->id);
1586         return false;
1587 
1588     } else if ((input->type == pe_order_optional)
1589                && pcmk_is_set(input->action->flags, pe_action_migrate_runnable)
1590                && pcmk__ends_with(input->action->uuid, "_stop_0")) {
1591         crm_trace("Ignoring %s (%d) input %s (%d): "
1592                   "optional but stop in migration",
1593                   action->uuid, action->id,
1594                   input->action->uuid, input->action->id);
1595         return false;
1596 
1597     } else if (input->type == pe_order_load) {
1598         pe_node_t *input_node = input->action->node;
1599 
1600         // load orderings are relevant only if actions are for same node
1601 
1602         if (action->rsc && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)) {
1603             pe_node_t *allocated = action->rsc->allocated_to;
1604 
1605             /* For load_stopped -> migrate_to orderings, we care about where it
1606              * has been allocated to, not where it will be executed.
1607              */
1608             if ((input_node == NULL) || (allocated == NULL)
1609                 || (input_node->details != allocated->details)) {
1610                 crm_trace("Ignoring %s (%d) input %s (%d): "
1611                           "load ordering node mismatch %s vs %s",
1612                           action->uuid, action->id,
1613                           input->action->uuid, input->action->id,
1614                           (allocated? allocated->details->uname : "<none>"),
1615                           (input_node? input_node->details->uname : "<none>"));
1616                 input->type = pe_order_none;
1617                 return false;
1618             }
1619 
1620         } else if ((input_node == NULL) || (action->node == NULL)
1621                    || (input_node->details != action->node->details)) {
1622             crm_trace("Ignoring %s (%d) input %s (%d): "
1623                       "load ordering node mismatch %s vs %s",
1624                       action->uuid, action->id,
1625                       input->action->uuid, input->action->id,
1626                       (action->node? action->node->details->uname : "<none>"),
1627                       (input_node? input_node->details->uname : "<none>"));
1628             input->type = pe_order_none;
1629             return false;
1630 
1631         } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1632             crm_trace("Ignoring %s (%d) input %s (%d): "
1633                       "load ordering input optional",
1634                       action->uuid, action->id,
1635                       input->action->uuid, input->action->id);
1636             input->type = pe_order_none;
1637             return false;
1638         }
1639 
1640     } else if (input->type == pe_order_anti_colocation) {
1641         if (input->action->node && action->node
1642             && (input->action->node->details != action->node->details)) {
1643             crm_trace("Ignoring %s (%d) input %s (%d): "
1644                       "anti-colocation node mismatch %s vs %s",
1645                       action->uuid, action->id,
1646                       input->action->uuid, input->action->id,
1647                       action->node->details->uname,
1648                       input->action->node->details->uname);
1649             input->type = pe_order_none;
1650             return false;
1651 
1652         } else if (pcmk_is_set(input->action->flags, pe_action_optional)) {
1653             crm_trace("Ignoring %s (%d) input %s (%d): "
1654                       "anti-colocation input optional",
1655                       action->uuid, action->id,
1656                       input->action->uuid, input->action->id);
1657             input->type = pe_order_none;
1658             return false;
1659         }
1660 
1661     } else if (input->action->rsc
1662                && input->action->rsc != action->rsc
1663                && pcmk_is_set(input->action->rsc->flags, pe_rsc_failed)
1664                && !pcmk_is_set(input->action->rsc->flags, pe_rsc_managed)
1665                && pcmk__ends_with(input->action->uuid, "_stop_0")
1666                && action->rsc && pe_rsc_is_clone(action->rsc)) {
1667         crm_warn("Ignoring requirement that %s complete before %s:"
1668                  " unmanaged failed resources cannot prevent clone shutdown",
1669                  input->action->uuid, action->uuid);
1670         return false;
1671 
1672     } else if (pcmk_is_set(input->action->flags, pe_action_optional)
1673                && !pcmk_any_flags_set(input->action->flags,
1674                                       pe_action_print_always|pe_action_dumped)
1675                && !should_dump_action(input->action)) {
1676         crm_trace("Ignoring %s (%d) input %s (%d): "
1677                   "input optional",
1678                   action->uuid, action->id,
1679                   input->action->uuid, input->action->id);
1680         return false;
1681     }
1682 
1683     crm_trace("%s (%d) input %s (%d) @ %s should be dumped: %s, %s, %s, 0x%.6x",
1684               action->uuid, action->id,
1685               input->action->uuid, input->action->id,
1686               input->action->node? input->action->node->details->uname : "no node",
1687               pcmk_is_set(input->action->flags, pe_action_pseudo)? "pseudo" : "real",
1688               pcmk_is_set(input->action->flags, pe_action_runnable)? "runnable" : "unrunnable",
1689               pcmk_is_set(input->action->flags, pe_action_optional)? "optional" : "required",
1690               input->type);
1691     return true;
1692 }
1693 
1694 static bool
1695 graph_has_loop(pe_action_t *init_action, pe_action_t *action,
     /* [previous][next][first][last][top][bottom][index][help] */
1696                pe_action_wrapper_t *input)
1697 {
1698     bool has_loop = false;
1699 
1700     if (pcmk_is_set(input->action->flags, pe_action_tracking)) {
1701         crm_trace("Breaking tracking loop: %s@%s -> %s@%s (0x%.6x)",
1702                   input->action->uuid,
1703                   input->action->node? input->action->node->details->uname : "",
1704                   action->uuid,
1705                   action->node? action->node->details->uname : "",
1706                   input->type);
1707         return false;
1708     }
1709 
1710     // Don't need to check inputs that won't be used
1711     if (!check_dump_input(action, input)) {
1712         return false;
1713     }
1714 
1715     if (input->action == init_action) {
1716         crm_debug("Input loop found in %s@%s ->...-> %s@%s",
1717                   action->uuid,
1718                   action->node? action->node->details->uname : "",
1719                   init_action->uuid,
1720                   init_action->node? init_action->node->details->uname : "");
1721         return true;
1722     }
1723 
1724     pe__set_action_flags(input->action, pe_action_tracking);
1725 
1726     crm_trace("Checking inputs of action %s@%s input %s@%s (0x%.6x)"
1727               "for graph loop with %s@%s ",
1728               action->uuid,
1729               action->node? action->node->details->uname : "",
1730               input->action->uuid,
1731               input->action->node? input->action->node->details->uname : "",
1732               input->type,
1733               init_action->uuid,
1734               init_action->node? init_action->node->details->uname : "");
1735 
1736     // Recursively check input itself for loops
1737     for (GList *iter = input->action->actions_before;
1738          iter != NULL; iter = iter->next) {
1739 
1740         if (graph_has_loop(init_action, input->action,
1741                            (pe_action_wrapper_t *) iter->data)) {
1742             // Recursive call already logged a debug message
1743             has_loop = true;
1744             goto done;
1745         }
1746     }
1747 
1748 done:
1749     pe__clear_action_flags(input->action, pe_action_tracking);
1750 
1751     if (!has_loop) {
1752         crm_trace("No input loop found in %s@%s -> %s@%s (0x%.6x)",
1753                   input->action->uuid,
1754                   input->action->node? input->action->node->details->uname : "",
1755                   action->uuid,
1756                   action->node? action->node->details->uname : "",
1757                   input->type);
1758     }
1759     return has_loop;
1760 }
1761 
1762 bool
1763 pcmk__ordering_is_invalid(pe_action_t *action, pe_action_wrapper_t *input)
     /* [previous][next][first][last][top][bottom][index][help] */
1764 {
1765     /* Prevent user-defined ordering constraints between resources
1766      * running in a guest node and the resource that defines that node.
1767      */
1768     if (!pcmk_is_set(input->type, pe_order_preserve)
1769         && action->rsc && action->rsc->fillers
1770         && input->action->rsc && input->action->node
1771         && input->action->node->details->remote_rsc
1772         && (input->action->node->details->remote_rsc->container == action->rsc)) {
1773         crm_warn("Invalid ordering constraint between %s and %s",
1774                  input->action->rsc->id, action->rsc->id);
1775         return true;
1776     }
1777 
1778     /* If there's an order like
1779      * "rscB_stop node2"-> "load_stopped_node2" -> "rscA_migrate_to node1"
1780      *
1781      * then rscA is being migrated from node1 to node2, while rscB is being
1782      * migrated from node2 to node1. If there would be a graph loop,
1783      * break the order "load_stopped_node2" -> "rscA_migrate_to node1".
1784      */
1785     if ((input->type == pe_order_load) && action->rsc
1786         && pcmk__str_eq(action->task, RSC_MIGRATE, pcmk__str_casei)
1787         && graph_has_loop(action, action, input)) {
1788         return true;
1789     }
1790 
1791     return false;
1792 }
1793 
1794 // Remove duplicate inputs (regardless of flags)
1795 static void
1796 deduplicate_inputs(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1797 {
1798     GList *item = NULL;
1799     GList *next = NULL;
1800     pe_action_wrapper_t *last_input = NULL;
1801 
1802     action->actions_before = g_list_sort(action->actions_before,
1803                                          sort_action_id);
1804     for (item = action->actions_before; item != NULL; item = next) {
1805         pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1806 
1807         next = item->next;
1808         if (last_input && (input->action->id == last_input->action->id)) {
1809             crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1810                       input->action->uuid, input->action->id,
1811                       action->uuid, action->id);
1812 
1813             /* For the purposes of scheduling, the ordering flags no longer
1814              * matter, but crm_simulate looks at certain ones when creating a
1815              * dot graph. Combining the flags is sufficient for that purpose.
1816              */
1817             last_input->type |= input->type;
1818             if (input->state == pe_link_dumped) {
1819                 last_input->state = pe_link_dumped;
1820             }
1821 
1822             free(item->data);
1823             action->actions_before = g_list_delete_link(action->actions_before,
1824                                                         item);
1825         } else {
1826             last_input = input;
1827             input->state = pe_link_not_dumped;
1828         }
1829     }
1830 }
1831 
1832 /*!
1833  * \internal
1834  * \brief Add an action to the transition graph XML if appropriate
1835  *
1836  * \param[in] action    Action to possibly add
1837  * \param[in] data_set  Cluster working set
1838  *
1839  * \note This will de-duplicate the action inputs, meaning that the
1840  *       pe_action_wrapper_t:type flags can no longer be relied on to retain
1841  *       their original settings. That means this MUST be called after stage7()
1842  *       is complete, and nothing after this should rely on those type flags.
1843  *       (For example, some code looks for type equal to some flag rather than
1844  *       whether the flag is set, and some code looks for particular
1845  *       combinations of flags -- such code must be done before stage8().)
1846  */
1847 void
1848 graph_element_from_action(pe_action_t *action, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1849 {
1850     GList *lpc = NULL;
1851     int synapse_priority = 0;
1852     xmlNode *syn = NULL;
1853     xmlNode *set = NULL;
1854     xmlNode *in = NULL;
1855     xmlNode *xml_action = NULL;
1856     pe_action_wrapper_t *input = NULL;
1857 
1858     /* If we haven't already, de-duplicate inputs -- even if we won't be dumping
1859      * the action, so that crm_simulate dot graphs don't have duplicates.
1860      */
1861     if (!pcmk_is_set(action->flags, pe_action_dedup)) {
1862         deduplicate_inputs(action);
1863         pe__set_action_flags(action, pe_action_dedup);
1864     }
1865 
1866     if (should_dump_action(action) == FALSE) {
1867         return;
1868     }
1869 
1870     pe__set_action_flags(action, pe_action_dumped);
1871 
1872     syn = create_xml_node(data_set->graph, "synapse");
1873     set = create_xml_node(syn, "action_set");
1874     in = create_xml_node(syn, "inputs");
1875 
1876     crm_xml_add_int(syn, XML_ATTR_ID, data_set->num_synapse);
1877     data_set->num_synapse++;
1878 
1879     if (action->rsc != NULL) {
1880         synapse_priority = action->rsc->priority;
1881     }
1882     if (action->priority > synapse_priority) {
1883         synapse_priority = action->priority;
1884     }
1885     if (synapse_priority > 0) {
1886         crm_xml_add_int(syn, XML_CIB_ATTR_PRIORITY, synapse_priority);
1887     }
1888 
1889     xml_action = action2xml(action, FALSE, data_set);
1890     add_node_nocopy(set, crm_element_name(xml_action), xml_action);
1891 
1892     for (lpc = action->actions_before; lpc != NULL; lpc = lpc->next) {
1893         input = (pe_action_wrapper_t *) lpc->data;
1894         if (check_dump_input(action, input)) {
1895             xmlNode *input_xml = create_xml_node(in, "trigger");
1896 
1897             input->state = pe_link_dumped;
1898             xml_action = action2xml(input->action, TRUE, data_set);
1899             add_node_nocopy(input_xml, crm_element_name(xml_action), xml_action);
1900         }
1901     }
1902 }

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