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

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