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

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