root/pengine/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. stonith_constraints
  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. action2xml
  17. should_dump_action
  18. sort_action_id
  19. check_dump_input
  20. graph_has_loop
  21. should_dump_input
  22. graph_element_from_action

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

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