root/lib/pacemaker/pcmk_sched_actions.c

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

DEFINITIONS

This source file includes following definitions.
  1. action_flags_for_ordering
  2. action_uuid_for_ordering
  3. action_for_ordering
  4. update_action_for_ordering_flags
  5. pcmk__update_action_for_orderings
  6. is_primitive_action
  7. handle_asymmetric_ordering
  8. handle_restart_ordering
  9. pcmk__update_ordered_actions
  10. pcmk__log_action
  11. pcmk__new_shutdown_action
  12. add_op_digest_to_xml
  13. pcmk__create_history_xml
  14. pcmk__action_locks_rsc_to_node
  15. sort_action_id
  16. pcmk__deduplicate_action_inputs
  17. pcmk__output_actions
  18. action_in_config
  19. task_for_digest
  20. only_sanitized_changed
  21. force_restart
  22. schedule_reload
  23. pcmk__check_action_config
  24. rsc_history_as_list
  25. process_rsc_history
  26. process_node_history
  27. pcmk__handle_rsc_config_changes

   1 /*
   2  * Copyright 2004-2022 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 <stdio.h>
  13 #include <sys/param.h>
  14 #include <glib.h>
  15 
  16 #include <crm/lrmd_internal.h>
  17 #include <pacemaker-internal.h>
  18 #include "libpacemaker_private.h"
  19 
  20 /*!
  21  * \internal
  22  * \brief Get the action flags relevant to ordering constraints
  23  *
  24  * \param[in] action  Action to check
  25  * \param[in] node    Node that *other* action in the ordering is on
  26  *                    (used only for clone resource actions)
  27  *
  28  * \return Action flags that should be used for orderings
  29  */
  30 static enum pe_action_flags
  31 action_flags_for_ordering(pe_action_t *action, pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33     bool runnable = false;
  34     enum pe_action_flags flags;
  35 
  36     // For non-resource actions, return the action flags
  37     if (action->rsc == NULL) {
  38         return action->flags;
  39     }
  40 
  41     /* For non-clone resources, or a clone action not assigned to a node,
  42      * return the flags as determined by the resource method without a node
  43      * specified.
  44      */
  45     flags = action->rsc->cmds->action_flags(action, NULL);
  46     if ((node == NULL) || !pe_rsc_is_clone(action->rsc)) {
  47         return flags;
  48     }
  49 
  50     /* Otherwise (i.e., for clone resource actions on a specific node), first
  51      * remember whether the non-node-specific action is runnable.
  52      */
  53     runnable = pcmk_is_set(flags, pe_action_runnable);
  54 
  55     // Then recheck the resource method with the node
  56     flags = action->rsc->cmds->action_flags(action, node);
  57 
  58     /* For clones in ordering constraints, the node-specific "runnable" doesn't
  59      * matter, just the non-node-specific setting (i.e., is the action runnable
  60      * anywhere).
  61      *
  62      * This applies only to runnable, and only for ordering constraints. This
  63      * function shouldn't be used for other types of constraints without
  64      * changes. Not very satisfying, but it's logical and appears to work well.
  65      */
  66     if (runnable && !pcmk_is_set(flags, pe_action_runnable)) {
  67         pe__set_raw_action_flags(flags, action->rsc->id,
  68                                  pe_action_runnable);
  69     }
  70     return flags;
  71 }
  72 
  73 /*!
  74  * \internal
  75  * \brief Get action UUID that should be used with a resource ordering
  76  *
  77  * When an action is ordered relative to an action for a collective resource
  78  * (clone, group, or bundle), it actually needs to be ordered after all
  79  * instances of the collective have completed the relevant action (for example,
  80  * given "start CLONE then start RSC", RSC must wait until all instances of
  81  * CLONE have started). Given the UUID and resource of the first action in an
  82  * ordering, this returns the UUID of the action that should actually be used
  83  * for ordering (for example, "CLONE_started_0" instead of "CLONE_start_0").
  84  *
  85  * \param[in] first_uuid    UUID of first action in ordering
  86  * \param[in] first_rsc     Resource of first action in ordering
  87  *
  88  * \return Newly allocated copy of UUID to use with ordering
  89  * \note It is the caller's responsibility to free the return value.
  90  */
  91 static char *
  92 action_uuid_for_ordering(const char *first_uuid, pe_resource_t *first_rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94     guint interval_ms = 0;
  95     char *uuid = NULL;
  96     char *rid = NULL;
  97     char *first_task_str = NULL;
  98     enum action_tasks first_task = no_action;
  99     enum action_tasks remapped_task = no_action;
 100 
 101     // Only non-notify actions for collective resources need remapping
 102     if ((strstr(first_uuid, "notify") != NULL)
 103         || (first_rsc->variant < pe_group)) {
 104         goto done;
 105     }
 106 
 107     // Only non-recurring actions need remapping
 108     CRM_ASSERT(parse_op_key(first_uuid, &rid, &first_task_str, &interval_ms));
 109     if (interval_ms > 0) {
 110         goto done;
 111     }
 112 
 113     first_task = text2task(first_task_str);
 114     switch (first_task) {
 115         case stop_rsc:
 116         case start_rsc:
 117         case action_notify:
 118         case action_promote:
 119         case action_demote:
 120             remapped_task = first_task + 1;
 121             break;
 122         case stopped_rsc:
 123         case started_rsc:
 124         case action_notified:
 125         case action_promoted:
 126         case action_demoted:
 127             remapped_task = first_task;
 128             break;
 129         case monitor_rsc:
 130         case shutdown_crm:
 131         case stonith_node:
 132             break;
 133         default:
 134             crm_err("Unknown action '%s' in ordering", first_task_str);
 135             break;
 136     }
 137 
 138     if (remapped_task != no_action) {
 139         /* If a (clone) resource has notifications enabled, we want to order
 140          * relative to when all notifications have been sent for the remapped
 141          * task. Only outermost resources or those in bundles have
 142          * notifications.
 143          */
 144         if (pcmk_is_set(first_rsc->flags, pe_rsc_notify)
 145             && ((first_rsc->parent == NULL)
 146                 || (pe_rsc_is_clone(first_rsc)
 147                     && (first_rsc->parent->variant == pe_container)))) {
 148             uuid = pcmk__notify_key(rid, "confirmed-post",
 149                                     task2text(remapped_task));
 150         } else {
 151             uuid = pcmk__op_key(rid, task2text(remapped_task), 0);
 152         }
 153         pe_rsc_trace(first_rsc,
 154                      "Remapped action UUID %s to %s for ordering purposes",
 155                      first_uuid, uuid);
 156     }
 157 
 158 done:
 159     if (uuid == NULL) {
 160         uuid = strdup(first_uuid);
 161         CRM_ASSERT(uuid != NULL);
 162     }
 163     free(first_task_str);
 164     free(rid);
 165     return uuid;
 166 }
 167 
 168 /*!
 169  * \internal
 170  * \brief Get actual action that should be used with an ordering
 171  *
 172  * When an action is ordered relative to an action for a collective resource
 173  * (clone, group, or bundle), it actually needs to be ordered after all
 174  * instances of the collective have completed the relevant action (for example,
 175  * given "start CLONE then start RSC", RSC must wait until all instances of
 176  * CLONE have started). Given the first action in an ordering, this returns the
 177  * the action that should actually be used for ordering (for example, the
 178  * started action instead of the start action).
 179  *
 180  * \param[in] action  First action in an ordering
 181  *
 182  * \return Actual action that should be used for the ordering
 183  */
 184 static pe_action_t *
 185 action_for_ordering(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 186 {
 187     pe_action_t *result = action;
 188     pe_resource_t *rsc = action->rsc;
 189 
 190     if ((rsc != NULL) && (rsc->variant >= pe_group) && (action->uuid != NULL)) {
 191         char *uuid = action_uuid_for_ordering(action->uuid, rsc);
 192 
 193         result = find_first_action(rsc->actions, uuid, NULL, NULL);
 194         if (result == NULL) {
 195             crm_warn("Not remapping %s to %s because %s does not have "
 196                      "remapped action", action->uuid, uuid, rsc->id);
 197             result = action;
 198         }
 199         free(uuid);
 200     }
 201     return result;
 202 }
 203 
 204 /*!
 205  * \internal
 206  * \brief Update flags for ordering's actions appropriately for ordering's flags
 207  *
 208  * \param[in] first        First action in an ordering
 209  * \param[in] then         Then action in an ordering
 210  * \param[in] first_flags  Action flags for \p first for ordering purposes
 211  * \param[in] then_flags   Action flags for \p then for ordering purposes
 212  * \param[in] order        Action wrapper for \p first in ordering
 213  * \param[in] data_set     Cluster working set
 214  *
 215  * \return Group of enum pcmk__updated flags
 216  */
 217 static uint32_t
 218 update_action_for_ordering_flags(pe_action_t *first, pe_action_t *then,
     /* [previous][next][first][last][top][bottom][index][help] */
 219                                  enum pe_action_flags first_flags,
 220                                  enum pe_action_flags then_flags,
 221                                  pe_action_wrapper_t *order,
 222                                  pe_working_set_t *data_set)
 223 {
 224     uint32_t changed = pcmk__updated_none;
 225 
 226     /* The node will only be used for clones. If interleaved, node will be NULL,
 227      * otherwise the ordering scope will be limited to the node. Normally, the
 228      * whole 'then' clone should restart if 'first' is restarted, so then->node
 229      * is needed.
 230      */
 231     pe_node_t *node = then->node;
 232 
 233     if (pcmk_is_set(order->type, pe_order_implies_then_on_node)) {
 234         /* For unfencing, only instances of 'then' on the same node as 'first'
 235          * (the unfencing operation) should restart, so reset node to
 236          * first->node, at which point this case is handled like a normal
 237          * pe_order_implies_then.
 238          */
 239         pe__clear_order_flags(order->type, pe_order_implies_then_on_node);
 240         pe__set_order_flags(order->type, pe_order_implies_then);
 241         node = first->node;
 242         pe_rsc_trace(then->rsc,
 243                      "%s then %s: mapped pe_order_implies_then_on_node to "
 244                      "pe_order_implies_then on %s",
 245                      first->uuid, then->uuid, pe__node_name(node));
 246     }
 247 
 248     if (pcmk_is_set(order->type, pe_order_implies_then)) {
 249         if (then->rsc != NULL) {
 250             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 251                                                                node,
 252                                                                first_flags & pe_action_optional,
 253                                                                pe_action_optional,
 254                                                                pe_order_implies_then,
 255                                                                data_set);
 256         } else if (!pcmk_is_set(first_flags, pe_action_optional)
 257                    && pcmk_is_set(then->flags, pe_action_optional)) {
 258             pe__clear_action_flags(then, pe_action_optional);
 259             pcmk__set_updated_flags(changed, first, pcmk__updated_then);
 260         }
 261         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_implies_then",
 262                      first->uuid, then->uuid,
 263                      (changed? "changed" : "unchanged"));
 264     }
 265 
 266     if (pcmk_is_set(order->type, pe_order_restart) && (then->rsc != NULL)) {
 267         enum pe_action_flags restart = pe_action_optional|pe_action_runnable;
 268 
 269         changed |= then->rsc->cmds->update_ordered_actions(first, then, node,
 270                                                            first_flags, restart,
 271                                                            pe_order_restart,
 272                                                            data_set);
 273         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_restart",
 274                      first->uuid, then->uuid,
 275                      (changed? "changed" : "unchanged"));
 276     }
 277 
 278     if (pcmk_is_set(order->type, pe_order_implies_first)) {
 279         if (first->rsc != NULL) {
 280             changed |= first->rsc->cmds->update_ordered_actions(first, then,
 281                                                                 node,
 282                                                                 first_flags,
 283                                                                 pe_action_optional,
 284                                                                 pe_order_implies_first,
 285                                                                 data_set);
 286         } else if (!pcmk_is_set(first_flags, pe_action_optional)
 287                    && pcmk_is_set(first->flags, pe_action_runnable)) {
 288             pe__clear_action_flags(first, pe_action_runnable);
 289             pcmk__set_updated_flags(changed, first, pcmk__updated_first);
 290         }
 291         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_implies_first",
 292                      first->uuid, then->uuid,
 293                      (changed? "changed" : "unchanged"));
 294     }
 295 
 296     if (pcmk_is_set(order->type, pe_order_promoted_implies_first)) {
 297         if (then->rsc != NULL) {
 298             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 299                                                                node,
 300                                                                first_flags & pe_action_optional,
 301                                                                pe_action_optional,
 302                                                                pe_order_promoted_implies_first,
 303                                                                data_set);
 304         }
 305         pe_rsc_trace(then->rsc,
 306                      "%s then %s: %s after pe_order_promoted_implies_first",
 307                      first->uuid, then->uuid,
 308                      (changed? "changed" : "unchanged"));
 309     }
 310 
 311     if (pcmk_is_set(order->type, pe_order_one_or_more)) {
 312         if (then->rsc != NULL) {
 313             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 314                                                                node,
 315                                                                first_flags,
 316                                                                pe_action_runnable,
 317                                                                pe_order_one_or_more,
 318                                                                data_set);
 319 
 320         } else if (pcmk_is_set(first_flags, pe_action_runnable)) {
 321             // We have another runnable instance of "first"
 322             then->runnable_before++;
 323 
 324             /* Mark "then" as runnable if it requires a certain number of
 325              * "before" instances to be runnable, and they now are.
 326              */
 327             if ((then->runnable_before >= then->required_runnable_before)
 328                 && !pcmk_is_set(then->flags, pe_action_runnable)) {
 329 
 330                 pe__set_action_flags(then, pe_action_runnable);
 331                 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
 332             }
 333         }
 334         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_one_or_more",
 335                      first->uuid, then->uuid,
 336                      (changed? "changed" : "unchanged"));
 337     }
 338 
 339     if (pcmk_is_set(order->type, pe_order_probe) && (then->rsc != NULL)) {
 340         if (!pcmk_is_set(first_flags, pe_action_runnable)
 341             && (first->rsc->running_on != NULL)) {
 342 
 343             pe_rsc_trace(then->rsc,
 344                          "%s then %s: ignoring because first is stopping",
 345                          first->uuid, then->uuid);
 346             order->type = pe_order_none;
 347         } else {
 348             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 349                                                                node,
 350                                                                first_flags,
 351                                                                pe_action_runnable,
 352                                                                pe_order_runnable_left,
 353                                                                data_set);
 354         }
 355         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_probe",
 356                      first->uuid, then->uuid,
 357                      (changed? "changed" : "unchanged"));
 358     }
 359 
 360     if (pcmk_is_set(order->type, pe_order_runnable_left)) {
 361         if (then->rsc != NULL) {
 362             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 363                                                                node,
 364                                                                first_flags,
 365                                                                pe_action_runnable,
 366                                                                pe_order_runnable_left,
 367                                                                data_set);
 368 
 369         } else if (!pcmk_is_set(first_flags, pe_action_runnable)
 370                    && pcmk_is_set(then->flags, pe_action_runnable)) {
 371 
 372             pe__clear_action_flags(then, pe_action_runnable);
 373             pcmk__set_updated_flags(changed, first, pcmk__updated_then);
 374         }
 375         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_runnable_left",
 376                      first->uuid, then->uuid,
 377                      (changed? "changed" : "unchanged"));
 378     }
 379 
 380     if (pcmk_is_set(order->type, pe_order_implies_first_migratable)) {
 381         if (then->rsc != NULL) {
 382             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 383                                                                node,
 384                                                                first_flags,
 385                                                                pe_action_optional,
 386                                                                pe_order_implies_first_migratable,
 387                                                                data_set);
 388         }
 389         pe_rsc_trace(then->rsc, "%s then %s: %s after "
 390                      "pe_order_implies_first_migratable",
 391                      first->uuid, then->uuid,
 392                      (changed? "changed" : "unchanged"));
 393     }
 394 
 395     if (pcmk_is_set(order->type, pe_order_pseudo_left)) {
 396         if (then->rsc != NULL) {
 397             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 398                                                                node,
 399                                                                first_flags,
 400                                                                pe_action_optional,
 401                                                                pe_order_pseudo_left,
 402                                                                data_set);
 403         }
 404         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_pseudo_left",
 405                      first->uuid, then->uuid,
 406                      (changed? "changed" : "unchanged"));
 407     }
 408 
 409     if (pcmk_is_set(order->type, pe_order_optional)) {
 410         if (then->rsc != NULL) {
 411             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 412                                                                node,
 413                                                                first_flags,
 414                                                                pe_action_runnable,
 415                                                                pe_order_optional,
 416                                                                data_set);
 417         }
 418         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_optional",
 419                      first->uuid, then->uuid,
 420                      (changed? "changed" : "unchanged"));
 421     }
 422 
 423     if (pcmk_is_set(order->type, pe_order_asymmetrical)) {
 424         if (then->rsc != NULL) {
 425             changed |= then->rsc->cmds->update_ordered_actions(first, then,
 426                                                                node,
 427                                                                first_flags,
 428                                                                pe_action_runnable,
 429                                                                pe_order_asymmetrical,
 430                                                                data_set);
 431         }
 432         pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_asymmetrical",
 433                      first->uuid, then->uuid,
 434                      (changed? "changed" : "unchanged"));
 435     }
 436 
 437     if (pcmk_is_set(first->flags, pe_action_runnable)
 438         && pcmk_is_set(order->type, pe_order_implies_then_printed)
 439         && !pcmk_is_set(first_flags, pe_action_optional)) {
 440 
 441         pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
 442                      then->uuid, first->uuid);
 443         pe__set_action_flags(then, pe_action_print_always);
 444         // Don't bother marking 'then' as changed just for this
 445     }
 446 
 447     if (pcmk_is_set(order->type, pe_order_implies_first_printed)
 448         && !pcmk_is_set(then_flags, pe_action_optional)) {
 449 
 450         pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
 451                      first->uuid, then->uuid);
 452         pe__set_action_flags(first, pe_action_print_always);
 453         // Don't bother marking 'first' as changed just for this
 454     }
 455 
 456     if (pcmk_any_flags_set(order->type, pe_order_implies_then
 457                                         |pe_order_implies_first
 458                                         |pe_order_restart)
 459         && (first->rsc != NULL)
 460         && !pcmk_is_set(first->rsc->flags, pe_rsc_managed)
 461         && pcmk_is_set(first->rsc->flags, pe_rsc_block)
 462         && !pcmk_is_set(first->flags, pe_action_runnable)
 463         && pcmk__str_eq(first->task, RSC_STOP, pcmk__str_casei)) {
 464 
 465         if (pcmk_is_set(then->flags, pe_action_runnable)) {
 466             pe__clear_action_flags(then, pe_action_runnable);
 467             pcmk__set_updated_flags(changed, first, pcmk__updated_then);
 468         }
 469         pe_rsc_trace(then->rsc, "%s then %s: %s after checking whether first "
 470                      "is blocked, unmanaged, unrunnable stop",
 471                      first->uuid, then->uuid,
 472                      (changed? "changed" : "unchanged"));
 473     }
 474 
 475     return changed;
 476 }
 477 
 478 // Convenience macros for logging action properties
 479 
 480 #define action_type_str(flags) \
 481     (pcmk_is_set((flags), pe_action_pseudo)? "pseudo-action" : "action")
 482 
 483 #define action_optional_str(flags) \
 484     (pcmk_is_set((flags), pe_action_optional)? "optional" : "required")
 485 
 486 #define action_runnable_str(flags) \
 487     (pcmk_is_set((flags), pe_action_runnable)? "runnable" : "unrunnable")
 488 
 489 #define action_node_str(a) \
 490     (((a)->node == NULL)? "no node" : (a)->node->details->uname)
 491 
 492 /*!
 493  * \internal
 494  * \brief Update an action's flags for all orderings where it is "then"
 495  *
 496  * \param[in] then      Action to update
 497  * \param[in] data_set  Cluster working set
 498  */
 499 void
 500 pcmk__update_action_for_orderings(pe_action_t *then, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 501 {
 502     GList *lpc = NULL;
 503     uint32_t changed = pcmk__updated_none;
 504     int last_flags = then->flags;
 505 
 506     pe_rsc_trace(then->rsc, "Updating %s %s (%s %s) on %s",
 507                  action_type_str(then->flags), then->uuid,
 508                  action_optional_str(then->flags),
 509                  action_runnable_str(then->flags), action_node_str(then));
 510 
 511     if (pcmk_is_set(then->flags, pe_action_requires_any)) {
 512         /* Initialize current known "runnable before" actions. As
 513          * update_action_for_ordering_flags() is called for each of then's
 514          * before actions, this number will increment as runnable 'first'
 515          * actions are encountered.
 516          */
 517         then->runnable_before = 0;
 518 
 519         if (then->required_runnable_before == 0) {
 520             /* @COMPAT This ordering constraint uses the deprecated
 521              * "require-all=false" attribute. Treat it like "clone-min=1".
 522              */
 523             then->required_runnable_before = 1;
 524         }
 525 
 526         /* The pe_order_one_or_more clause of update_action_for_ordering_flags()
 527          * (called below) will reset runnable if appropriate.
 528          */
 529         pe__clear_action_flags(then, pe_action_runnable);
 530     }
 531 
 532     for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
 533         pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
 534         pe_action_t *first = other->action;
 535 
 536         pe_node_t *then_node = then->node;
 537         pe_node_t *first_node = first->node;
 538 
 539         if ((first->rsc != NULL)
 540             && (first->rsc->variant == pe_group)
 541             && pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
 542 
 543             first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
 544             if (first_node != NULL) {
 545                 pe_rsc_trace(first->rsc, "Found %s for 'first' %s",
 546                              pe__node_name(first_node), first->uuid);
 547             }
 548         }
 549 
 550         if ((then->rsc != NULL)
 551             && (then->rsc->variant == pe_group)
 552             && pcmk__str_eq(then->task, RSC_START, pcmk__str_casei)) {
 553 
 554             then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
 555             if (then_node != NULL) {
 556                 pe_rsc_trace(then->rsc, "Found %s for 'then' %s",
 557                              pe__node_name(then_node), then->uuid);
 558             }
 559         }
 560 
 561         // Disable constraint if it only applies when on same node, but isn't
 562         if (pcmk_is_set(other->type, pe_order_same_node)
 563             && (first_node != NULL) && (then_node != NULL)
 564             && (first_node->details != then_node->details)) {
 565 
 566             pe_rsc_trace(then->rsc,
 567                          "Disabled ordering %s on %s then %s on %s: not same node",
 568                          other->action->uuid, pe__node_name(first_node),
 569                          then->uuid, pe__node_name(then_node));
 570             other->type = pe_order_none;
 571             continue;
 572         }
 573 
 574         pcmk__clear_updated_flags(changed, then, pcmk__updated_first);
 575 
 576         if ((first->rsc != NULL)
 577             && pcmk_is_set(other->type, pe_order_then_cancels_first)
 578             && !pcmk_is_set(then->flags, pe_action_optional)) {
 579 
 580             /* 'then' is required, so we must abandon 'first'
 581              * (e.g. a required stop cancels any agent reload).
 582              */
 583             pe__set_action_flags(other->action, pe_action_optional);
 584             if (!strcmp(first->task, CRMD_ACTION_RELOAD_AGENT)) {
 585                 pe__clear_resource_flags(first->rsc, pe_rsc_reload);
 586             }
 587         }
 588 
 589         if ((first->rsc != NULL) && (then->rsc != NULL)
 590             && (first->rsc != then->rsc) && !is_parent(then->rsc, first->rsc)) {
 591             first = action_for_ordering(first);
 592         }
 593         if (first != other->action) {
 594             pe_rsc_trace(then->rsc, "Ordering %s after %s instead of %s",
 595                          then->uuid, first->uuid, other->action->uuid);
 596         }
 597 
 598         pe_rsc_trace(then->rsc,
 599                      "%s (%#.6x) then %s (%#.6x): type=%#.6x node=%s",
 600                      first->uuid, first->flags, then->uuid, then->flags,
 601                      other->type, action_node_str(first));
 602 
 603         if (first == other->action) {
 604             /* 'first' was not remapped (e.g. from 'start' to 'running'), which
 605              * could mean it is a non-resource action, a primitive resource
 606              * action, or already expanded.
 607              */
 608             enum pe_action_flags first_flags, then_flags;
 609 
 610             first_flags = action_flags_for_ordering(first, then_node);
 611             then_flags = action_flags_for_ordering(then, first_node);
 612 
 613             changed |= update_action_for_ordering_flags(first, then,
 614                                                         first_flags, then_flags,
 615                                                         other, data_set);
 616 
 617             /* 'first' was for a complex resource (clone, group, etc),
 618              * create a new dependency if necessary
 619              */
 620         } else if (order_actions(first, then, other->type)) {
 621             /* This was the first time 'first' and 'then' were associated,
 622              * start again to get the new actions_before list
 623              */
 624             pcmk__set_updated_flags(changed, then, pcmk__updated_then);
 625             pe_rsc_trace(then->rsc,
 626                          "Disabled ordering %s then %s in favor of %s then %s",
 627                          other->action->uuid, then->uuid, first->uuid,
 628                          then->uuid);
 629             other->type = pe_order_none;
 630         }
 631 
 632 
 633         if (pcmk_is_set(changed, pcmk__updated_first)) {
 634             crm_trace("Re-processing %s and its 'after' actions "
 635                       "because it changed", first->uuid);
 636             for (GList *lpc2 = first->actions_after; lpc2 != NULL;
 637                  lpc2 = lpc2->next) {
 638                 pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc2->data;
 639 
 640                 pcmk__update_action_for_orderings(other->action, data_set);
 641             }
 642             pcmk__update_action_for_orderings(first, data_set);
 643         }
 644     }
 645 
 646     if (pcmk_is_set(then->flags, pe_action_requires_any)) {
 647         if (last_flags == then->flags) {
 648             pcmk__clear_updated_flags(changed, then, pcmk__updated_then);
 649         } else {
 650             pcmk__set_updated_flags(changed, then, pcmk__updated_then);
 651         }
 652     }
 653 
 654     if (pcmk_is_set(changed, pcmk__updated_then)) {
 655         crm_trace("Re-processing %s and its 'after' actions because it changed",
 656                   then->uuid);
 657         if (pcmk_is_set(last_flags, pe_action_runnable)
 658             && !pcmk_is_set(then->flags, pe_action_runnable)) {
 659             pcmk__block_colocation_dependents(then, data_set);
 660         }
 661         pcmk__update_action_for_orderings(then, data_set);
 662         for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
 663             pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
 664 
 665             pcmk__update_action_for_orderings(other->action, data_set);
 666         }
 667     }
 668 }
 669 
 670 static inline bool
 671 is_primitive_action(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 672 {
 673     return action && action->rsc && (action->rsc->variant == pe_native);
 674 }
 675 
 676 /*!
 677  * \internal
 678  * \brief Clear a single action flag and set reason text
 679  *
 680  * \param[in] action  Action whose flag should be cleared
 681  * \param[in] flag    Action flag that should be cleared
 682  * \param[in] reason  Action that is the reason why flag is being cleared
 683  */
 684 #define clear_action_flag_because(action, flag, reason) do {                \
 685         if (pcmk_is_set((action)->flags, (flag))) {                         \
 686             pe__clear_action_flags(action, flag);                           \
 687             if ((action)->rsc != (reason)->rsc) {                           \
 688                 char *reason_text = pe__action2reason((reason), (flag));    \
 689                 pe_action_set_reason((action), reason_text,                 \
 690                                    ((flag) == pe_action_migrate_runnable)); \
 691                 free(reason_text);                                          \
 692             }                                                               \
 693         }                                                                   \
 694     } while (0)
 695 
 696 /*!
 697  * \internal
 698  * \brief Update actions in an asymmetric ordering
 699  *
 700  * \param[in] first  'First' action in an asymmetric ordering
 701  * \param[in] then   'Then' action in an asymmetric ordering
 702  */
 703 static void
 704 handle_asymmetric_ordering(pe_action_t *first, pe_action_t *then)
     /* [previous][next][first][last][top][bottom][index][help] */
 705 {
 706     enum rsc_role_e then_rsc_role = RSC_ROLE_UNKNOWN;
 707     GList *then_on = NULL;
 708 
 709     if (then->rsc == NULL) {
 710         // Asymmetric orderings only matter if there's a resource involved
 711         return;
 712     }
 713 
 714     then_rsc_role = then->rsc->fns->state(then->rsc, TRUE);
 715     then_on = then->rsc->running_on;
 716 
 717     if ((then_rsc_role == RSC_ROLE_STOPPED)
 718         && pcmk__str_eq(then->task, RSC_STOP, pcmk__str_none)) {
 719         /* Nothing needs to be done for asymmetric ordering if 'then' is
 720          * supposed to be stopped after 'first' but is already stopped.
 721          */
 722         return;
 723     }
 724 
 725     if ((then_rsc_role >= RSC_ROLE_STARTED)
 726         && pcmk_is_set(then->flags, pe_action_optional)
 727         && (then->node != NULL)
 728         && pcmk__list_of_1(then_on)
 729         && (then->node->details == ((pe_node_t *) then_on->data)->details)
 730         && pcmk__str_eq(then->task, RSC_START, pcmk__str_none)) {
 731         /* Nothing needs to be done for asymmetric ordering if 'then' is
 732          * supposed to be started after 'first' but is already started --
 733          * unless the start is mandatory, which indicates the resource is
 734          * restarting and the ordering is still needed.
 735          */
 736         return;
 737     }
 738 
 739     if (!pcmk_is_set(first->flags, pe_action_runnable)) {
 740         // 'First' can't run, so 'then' can't either
 741         clear_action_flag_because(then, pe_action_optional, first);
 742         clear_action_flag_because(then, pe_action_runnable, first);
 743     }
 744 }
 745 
 746 /*!
 747  * \internal
 748  * \brief Set action bits appropriately when pe_restart_order is used
 749  *
 750  * \param[in] first   'First' action in an ordering with pe_restart_order
 751  * \param[in] then    'Then' action in an ordering with pe_restart_order
 752  * \param[in] filter  What action flags to care about
 753  *
 754  * \note pe_restart_order is set for "stop resource before starting it" and
 755  *       "stop later group member before stopping earlier group member"
 756  */
 757 static void
 758 handle_restart_ordering(pe_action_t *first, pe_action_t *then, uint32_t filter)
     /* [previous][next][first][last][top][bottom][index][help] */
 759 {
 760     const char *reason = NULL;
 761 
 762     CRM_ASSERT(is_primitive_action(first));
 763     CRM_ASSERT(is_primitive_action(then));
 764 
 765     // We need to update the action in two cases:
 766 
 767     // ... if 'then' is required
 768     if (pcmk_is_set(filter, pe_action_optional)
 769         && !pcmk_is_set(then->flags, pe_action_optional)) {
 770         reason = "restart";
 771     }
 772 
 773     /* ... if 'then' is unrunnable action on same resource (if a resource
 774      * should restart but can't start, we still want to stop)
 775      */
 776     if (pcmk_is_set(filter, pe_action_runnable)
 777         && !pcmk_is_set(then->flags, pe_action_runnable)
 778         && pcmk_is_set(then->rsc->flags, pe_rsc_managed)
 779         && (first->rsc == then->rsc)) {
 780         reason = "stop";
 781     }
 782 
 783     if (reason == NULL) {
 784         return;
 785     }
 786 
 787     pe_rsc_trace(first->rsc, "Handling %s -> %s for %s",
 788                  first->uuid, then->uuid, reason);
 789 
 790     // Make 'first' required if it is runnable
 791     if (pcmk_is_set(first->flags, pe_action_runnable)) {
 792         clear_action_flag_because(first, pe_action_optional, then);
 793     }
 794 
 795     // Make 'first' required if 'then' is required
 796     if (!pcmk_is_set(then->flags, pe_action_optional)) {
 797         clear_action_flag_because(first, pe_action_optional, then);
 798     }
 799 
 800     // Make 'first' unmigratable if 'then' is unmigratable
 801     if (!pcmk_is_set(then->flags, pe_action_migrate_runnable)) {
 802         clear_action_flag_because(first, pe_action_migrate_runnable, then);
 803     }
 804 
 805     // Make 'then' unrunnable if 'first' is required but unrunnable
 806     if (!pcmk_is_set(first->flags, pe_action_optional)
 807         && !pcmk_is_set(first->flags, pe_action_runnable)) {
 808         clear_action_flag_because(then, pe_action_runnable, first);
 809     }
 810 }
 811 
 812 /*!
 813  * \internal
 814  * \brief Update two actions according to an ordering between them
 815  *
 816  * Given information about an ordering of two actions, update the actions'
 817  * flags (and runnable_before members if appropriate) as appropriate for the
 818  * ordering. In some cases, the ordering could be disabled as well.
 819  *
 820  * \param[in,out] first     'First' action in an ordering
 821  * \param[in,out] then      'Then' action in an ordering
 822  * \param[in]     node      If not NULL, limit scope of ordering to this node
 823  *                          (ignored)
 824  * \param[in]     flags     Action flags for \p first for ordering purposes
 825  * \param[in]     filter    Action flags to limit scope of certain updates (may
 826  *                          include pe_action_optional to affect only mandatory
 827  *                          actions, and pe_action_runnable to affect only
 828  *                          runnable actions)
 829  * \param[in]     type      Group of enum pe_ordering flags to apply
 830  * \param[in,out] data_set  Cluster working set
 831  *
 832  * \return Group of enum pcmk__updated flags indicating what was updated
 833  */
 834 uint32_t
 835 pcmk__update_ordered_actions(pe_action_t *first, pe_action_t *then,
     /* [previous][next][first][last][top][bottom][index][help] */
 836                              const pe_node_t *node, uint32_t flags,
 837                              uint32_t filter, uint32_t type,
 838                              pe_working_set_t *data_set)
 839 {
 840     uint32_t changed = pcmk__updated_none;
 841     uint32_t then_flags = then->flags;
 842     uint32_t first_flags = first->flags;
 843 
 844     if (pcmk_is_set(type, pe_order_asymmetrical)) {
 845         handle_asymmetric_ordering(first, then);
 846     }
 847 
 848     if (pcmk_is_set(type, pe_order_implies_first)
 849         && !pcmk_is_set(then_flags, pe_action_optional)) {
 850         // Then is required, and implies first should be, too
 851 
 852         if (pcmk_is_set(filter, pe_action_optional)
 853             && !pcmk_is_set(flags, pe_action_optional)
 854             && pcmk_is_set(first_flags, pe_action_optional)) {
 855             clear_action_flag_because(first, pe_action_optional, then);
 856         }
 857 
 858         if (pcmk_is_set(flags, pe_action_migrate_runnable)
 859             && !pcmk_is_set(then->flags, pe_action_migrate_runnable)) {
 860             clear_action_flag_because(first, pe_action_migrate_runnable, then);
 861         }
 862     }
 863 
 864     if (pcmk_is_set(type, pe_order_promoted_implies_first)
 865         && (then->rsc != NULL) && (then->rsc->role == RSC_ROLE_PROMOTED)
 866         && pcmk_is_set(filter, pe_action_optional)
 867         && !pcmk_is_set(then->flags, pe_action_optional)) {
 868 
 869         clear_action_flag_because(first, pe_action_optional, then);
 870 
 871         if (pcmk_is_set(first->flags, pe_action_migrate_runnable)
 872             && !pcmk_is_set(then->flags, pe_action_migrate_runnable)) {
 873             clear_action_flag_because(first, pe_action_migrate_runnable,
 874                                       then);
 875         }
 876     }
 877 
 878     if (pcmk_is_set(type, pe_order_implies_first_migratable)
 879         && pcmk_is_set(filter, pe_action_optional)) {
 880 
 881         if (!pcmk_all_flags_set(then->flags,
 882                                 pe_action_migrate_runnable|pe_action_runnable)) {
 883             clear_action_flag_because(first, pe_action_runnable, then);
 884         }
 885 
 886         if (!pcmk_is_set(then->flags, pe_action_optional)) {
 887             clear_action_flag_because(first, pe_action_optional, then);
 888         }
 889     }
 890 
 891     if (pcmk_is_set(type, pe_order_pseudo_left)
 892         && pcmk_is_set(filter, pe_action_optional)
 893         && !pcmk_is_set(first->flags, pe_action_runnable)) {
 894 
 895         clear_action_flag_because(then, pe_action_migrate_runnable, first);
 896         pe__clear_action_flags(then, pe_action_pseudo);
 897     }
 898 
 899     if (pcmk_is_set(type, pe_order_runnable_left)
 900         && pcmk_is_set(filter, pe_action_runnable)
 901         && pcmk_is_set(then->flags, pe_action_runnable)
 902         && !pcmk_is_set(flags, pe_action_runnable)) {
 903 
 904         clear_action_flag_because(then, pe_action_runnable, first);
 905         clear_action_flag_because(then, pe_action_migrate_runnable, first);
 906     }
 907 
 908     if (pcmk_is_set(type, pe_order_implies_then)
 909         && pcmk_is_set(filter, pe_action_optional)
 910         && pcmk_is_set(then->flags, pe_action_optional)
 911         && !pcmk_is_set(flags, pe_action_optional)
 912         && !pcmk_is_set(first->flags, pe_action_migrate_runnable)) {
 913 
 914         clear_action_flag_because(then, pe_action_optional, first);
 915     }
 916 
 917     if (pcmk_is_set(type, pe_order_restart)) {
 918         handle_restart_ordering(first, then, filter);
 919     }
 920 
 921     if (then_flags != then->flags) {
 922         pcmk__set_updated_flags(changed, first, pcmk__updated_then);
 923         pe_rsc_trace(then->rsc,
 924                      "%s on %s: flags are now %#.6x (was %#.6x) "
 925                      "because of 'first' %s (%#.6x)",
 926                      then->uuid, pe__node_name(then->node),
 927                      then->flags, then_flags, first->uuid, first->flags);
 928 
 929         if ((then->rsc != NULL) && (then->rsc->parent != NULL)) {
 930             // Required to handle "X_stop then X_start" for cloned groups
 931             pcmk__update_action_for_orderings(then, data_set);
 932         }
 933     }
 934 
 935     if (first_flags != first->flags) {
 936         pcmk__set_updated_flags(changed, first, pcmk__updated_first);
 937         pe_rsc_trace(first->rsc,
 938                      "%s on %s: flags are now %#.6x (was %#.6x) "
 939                      "because of 'then' %s (%#.6x)",
 940                      first->uuid, pe__node_name(first->node),
 941                      first->flags, first_flags, then->uuid, then->flags);
 942     }
 943 
 944     return changed;
 945 }
 946 
 947 /*!
 948  * \internal
 949  * \brief Trace-log an action (optionally with its dependent actions)
 950  *
 951  * \param[in] pre_text  If not NULL, prefix the log with this plus ": "
 952  * \param[in] action    Action to log
 953  * \param[in] details   If true, recursively log dependent actions
 954  */
 955 void
 956 pcmk__log_action(const char *pre_text, pe_action_t *action, bool details)
     /* [previous][next][first][last][top][bottom][index][help] */
 957 {
 958     const char *node_uname = NULL;
 959     const char *node_uuid = NULL;
 960     const char *desc = NULL;
 961 
 962     CRM_CHECK(action != NULL, return);
 963 
 964     if (!pcmk_is_set(action->flags, pe_action_pseudo)) {
 965         if (action->node != NULL) {
 966             node_uname = action->node->details->uname;
 967             node_uuid = action->node->details->id;
 968         } else {
 969             node_uname = "<none>";
 970         }
 971     }
 972 
 973     switch (text2task(action->task)) {
 974         case stonith_node:
 975         case shutdown_crm:
 976             if (pcmk_is_set(action->flags, pe_action_pseudo)) {
 977                 desc = "Pseudo ";
 978             } else if (pcmk_is_set(action->flags, pe_action_optional)) {
 979                 desc = "Optional ";
 980             } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 981                 desc = "!!Non-Startable!! ";
 982             } else if (pcmk_is_set(action->flags, pe_action_processed)) {
 983                desc = "";
 984             } else {
 985                desc = "(Provisional) ";
 986             }
 987             crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
 988                       ((pre_text == NULL)? "" : pre_text),
 989                       ((pre_text == NULL)? "" : ": "),
 990                       desc, action->id, action->uuid,
 991                       (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
 992                       (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
 993                       (node_uuid? ")" : ""));
 994             break;
 995         default:
 996             if (pcmk_is_set(action->flags, pe_action_optional)) {
 997                 desc = "Optional ";
 998             } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
 999                 desc = "Pseudo ";
1000             } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
1001                 desc = "!!Non-Startable!! ";
1002             } else if (pcmk_is_set(action->flags, pe_action_processed)) {
1003                desc = "";
1004             } else {
1005                desc = "(Provisional) ";
1006             }
1007             crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
1008                       ((pre_text == NULL)? "" : pre_text),
1009                       ((pre_text == NULL)? "" : ": "),
1010                       desc, action->id, action->uuid,
1011                       (action->rsc? action->rsc->id : "<none>"),
1012                       (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1013                       (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1014                       (node_uuid? ")" : ""));
1015             break;
1016     }
1017 
1018     if (details) {
1019         GList *iter = NULL;
1020 
1021         crm_trace("\t\t====== Preceding Actions");
1022         for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1023             pe_action_wrapper_t *other = (pe_action_wrapper_t *) iter->data;
1024 
1025             pcmk__log_action("\t\t", other->action, false);
1026         }
1027         crm_trace("\t\t====== Subsequent Actions");
1028         for (iter = action->actions_after; iter != NULL; iter = iter->next) {
1029             pe_action_wrapper_t *other = (pe_action_wrapper_t *) iter->data;
1030 
1031             pcmk__log_action("\t\t", other->action, false);
1032         }
1033         crm_trace("\t\t====== End");
1034 
1035     } else {
1036         crm_trace("\t\t(before=%d, after=%d)",
1037                   g_list_length(action->actions_before),
1038                   g_list_length(action->actions_after));
1039     }
1040 }
1041 
1042 /*!
1043  * \internal
1044  * \brief Create a new shutdown action for a node
1045  *
1046  * \param[in] node         Node being shut down
1047  *
1048  * \return Newly created shutdown action for \p node
1049  */
1050 pe_action_t *
1051 pcmk__new_shutdown_action(pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1052 {
1053     char *shutdown_id = NULL;
1054     pe_action_t *shutdown_op = NULL;
1055 
1056     CRM_ASSERT(node != NULL);
1057 
1058     shutdown_id = crm_strdup_printf("%s-%s", CRM_OP_SHUTDOWN,
1059                                     node->details->uname);
1060 
1061     shutdown_op = custom_action(NULL, shutdown_id, CRM_OP_SHUTDOWN, node, FALSE,
1062                                 TRUE, node->details->data_set);
1063 
1064     pcmk__order_stops_before_shutdown(node, shutdown_op);
1065     add_hash_param(shutdown_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
1066     return shutdown_op;
1067 }
1068 
1069 /*!
1070  * \internal
1071  * \brief Calculate and add an operation digest to XML
1072  *
1073  * Calculate an operation digest, which enables us to later determine when a
1074  * restart is needed due to the resource's parameters being changed, and add it
1075  * to given XML.
1076  *
1077  * \param[in] op       Operation result from executor
1078  * \param[in] update   XML to add digest to
1079  */
1080 static void
1081 add_op_digest_to_xml(lrmd_event_data_t *op, xmlNode *update)
     /* [previous][next][first][last][top][bottom][index][help] */
1082 {
1083     char *digest = NULL;
1084     xmlNode *args_xml = NULL;
1085 
1086     if (op->params == NULL) {
1087         return;
1088     }
1089     args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
1090     g_hash_table_foreach(op->params, hash2field, args_xml);
1091     pcmk__filter_op_for_digest(args_xml);
1092     digest = calculate_operation_digest(args_xml, NULL);
1093     crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
1094     free_xml(args_xml);
1095     free(digest);
1096 }
1097 
1098 #define FAKE_TE_ID     "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1099 
1100 /*!
1101  * \internal
1102  * \brief Create XML for resource operation history update
1103  *
1104  * \param[in,out] parent          Parent XML node to add to
1105  * \param[in,out] op              Operation event data
1106  * \param[in]     caller_version  DC feature set
1107  * \param[in]     target_rc       Expected result of operation
1108  * \param[in]     node            Name of node on which operation was performed
1109  * \param[in]     origin          Arbitrary description of update source
1110  *
1111  * \return Newly created XML node for history update
1112  */
1113 xmlNode *
1114 pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *op,
     /* [previous][next][first][last][top][bottom][index][help] */
1115                          const char *caller_version, int target_rc,
1116                          const char *node, const char *origin)
1117 {
1118     char *key = NULL;
1119     char *magic = NULL;
1120     char *op_id = NULL;
1121     char *op_id_additional = NULL;
1122     char *local_user_data = NULL;
1123     const char *exit_reason = NULL;
1124 
1125     xmlNode *xml_op = NULL;
1126     const char *task = NULL;
1127 
1128     CRM_CHECK(op != NULL, return NULL);
1129     crm_trace("Creating history XML for %s-interval %s action for %s on %s "
1130               "(DC version: %s, origin: %s)",
1131               pcmk__readable_interval(op->interval_ms), op->op_type, op->rsc_id,
1132               ((node == NULL)? "no node" : node), caller_version, origin);
1133 
1134     task = op->op_type;
1135 
1136     /* Record a successful agent reload as a start, and a failed one as a
1137      * monitor, to make life easier for the scheduler when determining the
1138      * current state.
1139      *
1140      * @COMPAT We should check "reload" here only if the operation was for a
1141      * pre-OCF-1.1 resource agent, but we don't know that here, and we should
1142      * only ever get results for actions scheduled by us, so we can reasonably
1143      * assume any "reload" is actually a pre-1.1 agent reload.
1144      */
1145     if (pcmk__str_any_of(task, CRMD_ACTION_RELOAD, CRMD_ACTION_RELOAD_AGENT,
1146                          NULL)) {
1147         if (op->op_status == PCMK_EXEC_DONE) {
1148             task = CRMD_ACTION_START;
1149         } else {
1150             task = CRMD_ACTION_STATUS;
1151         }
1152     }
1153 
1154     key = pcmk__op_key(op->rsc_id, task, op->interval_ms);
1155     if (pcmk__str_eq(task, CRMD_ACTION_NOTIFY, pcmk__str_none)) {
1156         const char *n_type = crm_meta_value(op->params, "notify_type");
1157         const char *n_task = crm_meta_value(op->params, "notify_operation");
1158 
1159         CRM_LOG_ASSERT(n_type != NULL);
1160         CRM_LOG_ASSERT(n_task != NULL);
1161         op_id = pcmk__notify_key(op->rsc_id, n_type, n_task);
1162 
1163         if (op->op_status != PCMK_EXEC_PENDING) {
1164             /* Ignore notify errors.
1165              *
1166              * @TODO It might be better to keep the correct result here, and
1167              * ignore it in process_graph_event().
1168              */
1169             lrmd__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1170         }
1171 
1172     /* Migration history is preserved separately, which usually matters for
1173      * multiple nodes and is important for future cluster transitions.
1174      */
1175     } else if (pcmk__str_any_of(op->op_type, CRMD_ACTION_MIGRATE,
1176                                 CRMD_ACTION_MIGRATED, NULL)) {
1177         op_id = strdup(key);
1178 
1179     } else if (did_rsc_op_fail(op, target_rc)) {
1180         op_id = pcmk__op_key(op->rsc_id, "last_failure", 0);
1181         if (op->interval_ms == 0) {
1182             // Ensure 'last' gets updated, in case record-pending is true
1183             op_id_additional = pcmk__op_key(op->rsc_id, "last", 0);
1184         }
1185         exit_reason = op->exit_reason;
1186 
1187     } else if (op->interval_ms > 0) {
1188         op_id = strdup(key);
1189 
1190     } else {
1191         op_id = pcmk__op_key(op->rsc_id, "last", 0);
1192     }
1193 
1194   again:
1195     xml_op = pcmk__xe_match(parent, XML_LRM_TAG_RSC_OP, XML_ATTR_ID, op_id);
1196     if (xml_op == NULL) {
1197         xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
1198     }
1199 
1200     if (op->user_data == NULL) {
1201         crm_debug("Generating fake transition key for: " PCMK__OP_FMT
1202                   " %d from %s", op->rsc_id, op->op_type, op->interval_ms,
1203                   op->call_id, origin);
1204         local_user_data = pcmk__transition_key(-1, op->call_id, target_rc,
1205                                                FAKE_TE_ID);
1206         op->user_data = local_user_data;
1207     }
1208 
1209     if (magic == NULL) {
1210         magic = crm_strdup_printf("%d:%d;%s", op->op_status, op->rc,
1211                                   (const char *) op->user_data);
1212     }
1213 
1214     crm_xml_add(xml_op, XML_ATTR_ID, op_id);
1215     crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
1216     crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
1217     crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
1218     crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
1219     crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data);
1220     crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
1221     crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason == NULL ? "" : exit_reason);
1222     crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); /* For context during triage */
1223 
1224     crm_xml_add_int(xml_op, XML_LRM_ATTR_CALLID, op->call_id);
1225     crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
1226     crm_xml_add_int(xml_op, XML_LRM_ATTR_OPSTATUS, op->op_status);
1227     crm_xml_add_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, op->interval_ms);
1228 
1229     if (compare_version("2.1", caller_version) <= 0) {
1230         if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1231             crm_trace("Timing data (" PCMK__OP_FMT
1232                       "): last=%u change=%u exec=%u queue=%u",
1233                       op->rsc_id, op->op_type, op->interval_ms,
1234                       op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1235 
1236             if ((op->interval_ms != 0) && (op->t_rcchange != 0)) {
1237                 // Recurring ops may have changed rc after initial run
1238                 crm_xml_add_ll(xml_op, XML_RSC_OP_LAST_CHANGE,
1239                                (long long) op->t_rcchange);
1240             } else {
1241                 crm_xml_add_ll(xml_op, XML_RSC_OP_LAST_CHANGE,
1242                                (long long) op->t_run);
1243             }
1244 
1245             crm_xml_add_int(xml_op, XML_RSC_OP_T_EXEC, op->exec_time);
1246             crm_xml_add_int(xml_op, XML_RSC_OP_T_QUEUE, op->queue_time);
1247         }
1248     }
1249 
1250     if (pcmk__str_any_of(op->op_type, CRMD_ACTION_MIGRATE, CRMD_ACTION_MIGRATED, NULL)) {
1251         /*
1252          * Record migrate_source and migrate_target always for migrate ops.
1253          */
1254         const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
1255 
1256         crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1257 
1258         name = XML_LRM_ATTR_MIGRATE_TARGET;
1259         crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1260     }
1261 
1262     add_op_digest_to_xml(op, xml_op);
1263 
1264     if (op_id_additional) {
1265         free(op_id);
1266         op_id = op_id_additional;
1267         op_id_additional = NULL;
1268         goto again;
1269     }
1270 
1271     if (local_user_data) {
1272         free(local_user_data);
1273         op->user_data = NULL;
1274     }
1275     free(magic);
1276     free(op_id);
1277     free(key);
1278     return xml_op;
1279 }
1280 
1281 /*!
1282  * \internal
1283  * \brief Check whether an action shutdown-locks a resource to a node
1284  *
1285  * If the shutdown-lock cluster property is set, resources will not be recovered
1286  * on a different node if cleanly stopped, and may start only on that same node.
1287  * This function checks whether that applies to a given action, so that the
1288  * transition graph can be marked appropriately.
1289  *
1290  * \param[in] action  Action to check
1291  *
1292  * \return true if \p action locks its resource to the action's node,
1293  *         otherwise false
1294  */
1295 bool
1296 pcmk__action_locks_rsc_to_node(const pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1297 {
1298     // Only resource actions taking place on resource's lock node are locked
1299     if ((action == NULL) || (action->rsc == NULL)
1300         || (action->rsc->lock_node == NULL) || (action->node == NULL)
1301         || (action->node->details != action->rsc->lock_node->details)) {
1302         return false;
1303     }
1304 
1305     /* During shutdown, only stops are locked (otherwise, another action such as
1306      * a demote would cause the controller to clear the lock)
1307      */
1308     if (action->node->details->shutdown && (action->task != NULL)
1309         && (strcmp(action->task, RSC_STOP) != 0)) {
1310         return false;
1311     }
1312 
1313     return true;
1314 }
1315 
1316 /* lowest to highest */
1317 static gint
1318 sort_action_id(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
1319 {
1320     const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1321     const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1322 
1323     if (a == NULL) {
1324         return 1;
1325     }
1326     if (b == NULL) {
1327         return -1;
1328     }
1329     if (action_wrapper1->action->id < action_wrapper2->action->id) {
1330         return 1;
1331     }
1332     if (action_wrapper1->action->id > action_wrapper2->action->id) {
1333         return -1;
1334     }
1335     return 0;
1336 }
1337 
1338 /*!
1339  * \internal
1340  * \brief Remove any duplicate action inputs, merging action flags
1341  *
1342  * \param[in] action  Action whose inputs should be checked
1343  */
1344 void
1345 pcmk__deduplicate_action_inputs(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1346 {
1347     GList *item = NULL;
1348     GList *next = NULL;
1349     pe_action_wrapper_t *last_input = NULL;
1350 
1351     action->actions_before = g_list_sort(action->actions_before,
1352                                          sort_action_id);
1353     for (item = action->actions_before; item != NULL; item = next) {
1354         pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1355 
1356         next = item->next;
1357         if ((last_input != NULL)
1358             && (input->action->id == last_input->action->id)) {
1359             crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1360                       input->action->uuid, input->action->id,
1361                       action->uuid, action->id);
1362 
1363             /* For the purposes of scheduling, the ordering flags no longer
1364              * matter, but crm_simulate looks at certain ones when creating a
1365              * dot graph. Combining the flags is sufficient for that purpose.
1366              */
1367             last_input->type |= input->type;
1368             if (input->state == pe_link_dumped) {
1369                 last_input->state = pe_link_dumped;
1370             }
1371 
1372             free(item->data);
1373             action->actions_before = g_list_delete_link(action->actions_before,
1374                                                         item);
1375         } else {
1376             last_input = input;
1377             input->state = pe_link_not_dumped;
1378         }
1379     }
1380 }
1381 
1382 /*!
1383  * \internal
1384  * \brief Output all scheduled actions
1385  *
1386  * \param[in] data_set  Cluster working set
1387  */
1388 void
1389 pcmk__output_actions(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1390 {
1391     pcmk__output_t *out = data_set->priv;
1392 
1393     // Output node (non-resource) actions
1394     for (GList *iter = data_set->actions; iter != NULL; iter = iter->next) {
1395         char *node_name = NULL;
1396         char *task = NULL;
1397         pe_action_t *action = (pe_action_t *) iter->data;
1398 
1399         if (action->rsc != NULL) {
1400             continue; // Resource actions will be output later
1401 
1402         } else if (pcmk_is_set(action->flags, pe_action_optional)) {
1403             continue; // This action was not scheduled
1404         }
1405 
1406         if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1407             task = strdup("Shutdown");
1408 
1409         } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
1410             const char *op = g_hash_table_lookup(action->meta, "stonith_action");
1411 
1412             task = crm_strdup_printf("Fence (%s)", op);
1413 
1414         } else {
1415             continue; // Don't display other node action types
1416         }
1417 
1418         if (pe__is_guest_node(action->node)) {
1419             node_name = crm_strdup_printf("%s (resource: %s)",
1420                                           pe__node_name(action->node),
1421                                           action->node->details->remote_rsc->container->id);
1422         } else if (action->node != NULL) {
1423             node_name = crm_strdup_printf("%s", pe__node_name(action->node));
1424         }
1425 
1426         out->message(out, "node-action", task, node_name, action->reason);
1427 
1428         free(node_name);
1429         free(task);
1430     }
1431 
1432     // Output resource actions
1433     for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
1434         pe_resource_t *rsc = (pe_resource_t *) iter->data;
1435 
1436         rsc->cmds->output_actions(rsc);
1437     }
1438 }
1439 
1440 /*!
1441  * \internal
1442  * \brief Check whether action from resource history is still in configuration
1443  *
1444  * \param[in] rsc          Resource that action is for
1445  * \param[in] task         Action's name
1446  * \param[in] interval_ms  Action's interval (in milliseconds)
1447  *
1448  * \return true if action is still in resource configuration, otherwise false
1449  */
1450 static bool
1451 action_in_config(pe_resource_t *rsc, const char *task, guint interval_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
1452 {
1453     char *key = pcmk__op_key(rsc->id, task, interval_ms);
1454     bool config = (find_rsc_op_entry(rsc, key) != NULL);
1455 
1456     free(key);
1457     return config;
1458 }
1459 
1460 /*!
1461  * \internal
1462  * \brief Get action name needed to compare digest for configuration changes
1463  *
1464  * \param[in] task         Action name from history
1465  * \param[in] interval_ms  Action interval (in milliseconds)
1466  *
1467  * \return Action name whose digest should be compared
1468  */
1469 static const char *
1470 task_for_digest(const char *task, guint interval_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
1471 {
1472     /* Certain actions need to be compared against the parameters used to start
1473      * the resource.
1474      */
1475     if ((interval_ms == 0)
1476         && pcmk__str_any_of(task, RSC_STATUS, RSC_MIGRATED, RSC_PROMOTE, NULL)) {
1477         task = RSC_START;
1478     }
1479     return task;
1480 }
1481 
1482 /*!
1483  * \internal
1484  * \brief Check whether only sanitized parameters to an action changed
1485  *
1486  * When collecting CIB files for troubleshooting, crm_report will mask
1487  * sensitive resource parameters. If simulations were run using that, affected
1488  * resources would appear to need a restart, which would complicate
1489  * troubleshooting. To avoid that, we save a "secure digest" of non-sensitive
1490  * parameters. This function used that digest to check whether only masked
1491  * parameters are different.
1492  *
1493  * \param[in] xml_op       Resource history entry with secure digest
1494  * \param[in] digest_data  Operation digest information being compared
1495  * \param[in] data_set     Cluster working set
1496  *
1497  * \return true if only sanitized parameters changed, otherwise false
1498  */
1499 static bool
1500 only_sanitized_changed(xmlNode *xml_op, const op_digest_cache_t *digest_data,
     /* [previous][next][first][last][top][bottom][index][help] */
1501                        pe_working_set_t *data_set)
1502 {
1503     const char *digest_secure = NULL;
1504 
1505     if (!pcmk_is_set(data_set->flags, pe_flag_sanitized)) {
1506         // The scheduler is not being run as a simulation
1507         return false;
1508     }
1509 
1510     digest_secure = crm_element_value(xml_op, XML_LRM_ATTR_SECURE_DIGEST);
1511 
1512     return (digest_data->rc != RSC_DIGEST_MATCH) && (digest_secure != NULL)
1513            && (digest_data->digest_secure_calc != NULL)
1514            && (strcmp(digest_data->digest_secure_calc, digest_secure) == 0);
1515 }
1516 
1517 /*!
1518  * \internal
1519  * \brief Force a restart due to a configuration change
1520  *
1521  * \param[in] rsc          Resource that action is for
1522  * \param[in] task         Name of action whose configuration changed
1523  * \param[in] interval_ms  Action interval (in milliseconds)
1524  * \param[in] node         Node where resource should be restarted
1525  */
1526 static void
1527 force_restart(pe_resource_t *rsc, const char *task, guint interval_ms,
     /* [previous][next][first][last][top][bottom][index][help] */
1528               pe_node_t *node)
1529 {
1530     char *key = pcmk__op_key(rsc->id, task, interval_ms);
1531     pe_action_t *required = custom_action(rsc, key, task, NULL, FALSE, TRUE,
1532                                           rsc->cluster);
1533 
1534     pe_action_set_reason(required, "resource definition change", true);
1535     trigger_unfencing(rsc, node, "Device parameters changed", NULL,
1536                       rsc->cluster);
1537 }
1538 
1539 /*!
1540  * \internal
1541  * \brief Schedule a reload of a resource on a node
1542  *
1543  * \param[in] rsc   Resource to reload
1544  * \param[in] node  Where resource should be reloaded
1545  */
1546 static void
1547 schedule_reload(pe_resource_t *rsc, pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1548 {
1549     pe_action_t *reload = NULL;
1550 
1551     // For collective resources, just call recursively for children
1552     if (rsc->variant > pe_native) {
1553         g_list_foreach(rsc->children, (GFunc) schedule_reload, node);
1554         return;
1555     }
1556 
1557     // Skip the reload in certain situations
1558     if ((node == NULL)
1559         || !pcmk_is_set(rsc->flags, pe_rsc_managed)
1560         || pcmk_is_set(rsc->flags, pe_rsc_failed)) {
1561         pe_rsc_trace(rsc, "Skip reload of %s:%s%s %s",
1562                      rsc->id,
1563                      pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : " unmanaged",
1564                      pcmk_is_set(rsc->flags, pe_rsc_failed)? " failed" : "",
1565                      (node == NULL)? "inactive" : node->details->uname);
1566         return;
1567     }
1568 
1569     /* If a resource's configuration changed while a start was pending,
1570      * force a full restart instead of a reload.
1571      */
1572     if (pcmk_is_set(rsc->flags, pe_rsc_start_pending)) {
1573         pe_rsc_trace(rsc, "%s: preventing agent reload because start pending",
1574                      rsc->id);
1575         custom_action(rsc, stop_key(rsc), CRMD_ACTION_STOP, node, FALSE, TRUE,
1576                       rsc->cluster);
1577         return;
1578     }
1579 
1580     // Schedule the reload
1581     pe__set_resource_flags(rsc, pe_rsc_reload);
1582     reload = custom_action(rsc, reload_key(rsc), CRMD_ACTION_RELOAD_AGENT, node,
1583                            FALSE, TRUE, rsc->cluster);
1584     pe_action_set_reason(reload, "resource definition change", FALSE);
1585 
1586     // Set orderings so that a required stop or demote cancels the reload
1587     pcmk__new_ordering(NULL, NULL, reload, rsc, stop_key(rsc), NULL,
1588                        pe_order_optional|pe_order_then_cancels_first,
1589                        rsc->cluster);
1590     pcmk__new_ordering(NULL, NULL, reload, rsc, demote_key(rsc), NULL,
1591                        pe_order_optional|pe_order_then_cancels_first,
1592                        rsc->cluster);
1593 }
1594 
1595 /*!
1596  * \internal
1597  * \brief Handle any configuration change for an action
1598  *
1599  * Given an action from resource history, if the resource's configuration
1600  * changed since the action was done, schedule any actions needed (restart,
1601  * reload, unfencing, rescheduling recurring actions, etc.).
1602  *
1603  * \param[in] rsc     Resource that action is for
1604  * \param[in] node    Node that action was on
1605  * \param[in] xml_op  Action XML from resource history
1606  *
1607  * \return true if action configuration changed, otherwise false
1608  */
1609 bool
1610 pcmk__check_action_config(pe_resource_t *rsc, pe_node_t *node, xmlNode *xml_op)
     /* [previous][next][first][last][top][bottom][index][help] */
1611 {
1612     guint interval_ms = 0;
1613     const char *task = NULL;
1614     const op_digest_cache_t *digest_data = NULL;
1615 
1616     CRM_CHECK((rsc != NULL) && (node != NULL) && (xml_op != NULL),
1617               return false);
1618 
1619     task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1620     CRM_CHECK(task != NULL, return false);
1621 
1622     crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1623 
1624     // If this is a recurring action, check whether it has been orphaned
1625     if (interval_ms > 0) {
1626         if (action_in_config(rsc, task, interval_ms)) {
1627             pe_rsc_trace(rsc, "%s-interval %s for %s on %s is in configuration",
1628                          pcmk__readable_interval(interval_ms), task, rsc->id,
1629                          pe__node_name(node));
1630         } else if (pcmk_is_set(rsc->cluster->flags,
1631                                pe_flag_stop_action_orphans)) {
1632             pcmk__schedule_cancel(rsc,
1633                                   crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1634                                   task, interval_ms, node, "orphan");
1635             return true;
1636         } else {
1637             pe_rsc_debug(rsc, "%s-interval %s for %s on %s is orphaned",
1638                          pcmk__readable_interval(interval_ms), task, rsc->id,
1639                          pe__node_name(node));
1640             return true;
1641         }
1642     }
1643 
1644     crm_trace("Checking %s-interval %s for %s on %s for configuration changes",
1645               pcmk__readable_interval(interval_ms), task, rsc->id,
1646               pe__node_name(node));
1647     task = task_for_digest(task, interval_ms);
1648     digest_data = rsc_action_digest_cmp(rsc, xml_op, node, rsc->cluster);
1649 
1650     if (only_sanitized_changed(xml_op, digest_data, rsc->cluster)) {
1651         if (!pcmk__is_daemon && (rsc->cluster->priv != NULL)) {
1652             pcmk__output_t *out = rsc->cluster->priv;
1653 
1654             out->info(out,
1655                       "Only 'private' parameters to %s-interval %s for %s "
1656                       "on %s changed: %s",
1657                       pcmk__readable_interval(interval_ms), task, rsc->id,
1658                       pe__node_name(node),
1659                       crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
1660         }
1661         return false;
1662     }
1663 
1664     switch (digest_data->rc) {
1665         case RSC_DIGEST_RESTART:
1666             crm_log_xml_debug(digest_data->params_restart, "params:restart");
1667             force_restart(rsc, task, interval_ms, node);
1668             return true;
1669 
1670         case RSC_DIGEST_ALL:
1671         case RSC_DIGEST_UNKNOWN:
1672             // Changes that can potentially be handled by an agent reload
1673 
1674             if (interval_ms > 0) {
1675                 /* Recurring actions aren't reloaded per se, they are just
1676                  * re-scheduled so the next run uses the new parameters.
1677                  * The old instance will be cancelled automatically.
1678                  */
1679                 crm_log_xml_debug(digest_data->params_all, "params:reschedule");
1680                 pcmk__reschedule_recurring(rsc, task, interval_ms, node);
1681 
1682             } else if (crm_element_value(xml_op,
1683                                          XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
1684                 // Agent supports reload, so use it
1685                 trigger_unfencing(rsc, node,
1686                                   "Device parameters changed (reload)", NULL,
1687                                   rsc->cluster);
1688                 crm_log_xml_debug(digest_data->params_all, "params:reload");
1689                 schedule_reload(rsc, node);
1690 
1691             } else {
1692                 pe_rsc_trace(rsc,
1693                              "Restarting %s because agent doesn't support reload",
1694                              rsc->id);
1695                 crm_log_xml_debug(digest_data->params_restart,
1696                                   "params:restart");
1697                 force_restart(rsc, task, interval_ms, node);
1698             }
1699             return true;
1700 
1701         default:
1702             break;
1703     }
1704     return false;
1705 }
1706 
1707 /*!
1708  * \internal
1709  * \brief Create a list of resource's action history entries, sorted by call ID
1710  *
1711  * \param[in]  rsc          Resource whose history should be checked
1712  * \param[in]  rsc_entry    Resource's <lrm_rsc_op> status XML
1713  * \param[out] start_index  Where to store index of start-like action, if any
1714  * \param[out] stop_index   Where to store index of stop action, if any
1715  */
1716 static GList *
1717 rsc_history_as_list(pe_resource_t *rsc, xmlNode *rsc_entry,
     /* [previous][next][first][last][top][bottom][index][help] */
1718                     int *start_index, int *stop_index)
1719 {
1720     GList *ops = NULL;
1721 
1722     for (xmlNode *rsc_op = first_named_child(rsc_entry, XML_LRM_TAG_RSC_OP);
1723          rsc_op != NULL; rsc_op = crm_next_same_xml(rsc_op)) {
1724         ops = g_list_prepend(ops, rsc_op);
1725     }
1726     ops = g_list_sort(ops, sort_op_by_callid);
1727     calculate_active_ops(ops, start_index, stop_index);
1728     return ops;
1729 }
1730 
1731 /*!
1732  * \internal
1733  * \brief Process a resource's action history from the CIB status
1734  *
1735  * Given a resource's action history, if the resource's configuration
1736  * changed since the actions were done, schedule any actions needed (restart,
1737  * reload, unfencing, rescheduling recurring actions, clean-up, etc.).
1738  * (This also cancels recurring actions for maintenance mode, which is not
1739  * entirely related but convenient to do here.)
1740  *
1741  * \param[in] rsc_entry  Resource's <lrm_rsc_op> status XML
1742  * \param[in] rsc        Resource whose history is being processed
1743  * \param[in] node       Node whose history is being processed
1744  */
1745 static void
1746 process_rsc_history(xmlNode *rsc_entry, pe_resource_t *rsc, pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1747 {
1748     int offset = -1;
1749     int stop_index = 0;
1750     int start_index = 0;
1751     GList *sorted_op_list = NULL;
1752 
1753     if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
1754         if (pe_rsc_is_anon_clone(uber_parent(rsc))) {
1755             pe_rsc_trace(rsc,
1756                          "Skipping configuration check "
1757                          "for orphaned clone instance %s",
1758                          rsc->id);
1759         } else {
1760             pe_rsc_trace(rsc,
1761                          "Skipping configuration check and scheduling clean-up "
1762                          "for orphaned resource %s", rsc->id);
1763             pcmk__schedule_cleanup(rsc, node, false);
1764         }
1765         return;
1766     }
1767 
1768     if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
1769         if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, false)) {
1770             pcmk__schedule_cleanup(rsc, node, false);
1771         }
1772         pe_rsc_trace(rsc,
1773                      "Skipping configuration check for %s "
1774                      "because no longer active on %s",
1775                      rsc->id, pe__node_name(node));
1776         return;
1777     }
1778 
1779     pe_rsc_trace(rsc, "Checking for configuration changes for %s on %s",
1780                  rsc->id, pe__node_name(node));
1781 
1782     if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, true)) {
1783         pcmk__schedule_cleanup(rsc, node, false);
1784     }
1785 
1786     sorted_op_list = rsc_history_as_list(rsc, rsc_entry, &start_index,
1787                                          &stop_index);
1788     if (start_index < stop_index) {
1789         return; // Resource is stopped
1790     }
1791 
1792     for (GList *iter = sorted_op_list; iter != NULL; iter = iter->next) {
1793         xmlNode *rsc_op = (xmlNode *) iter->data;
1794         const char *task = NULL;
1795         guint interval_ms = 0;
1796 
1797         if (++offset < start_index) {
1798             // Skip actions that happened before a start
1799             continue;
1800         }
1801 
1802         task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
1803         crm_element_value_ms(rsc_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1804 
1805         if ((interval_ms > 0)
1806             && (pcmk_is_set(rsc->flags, pe_rsc_maintenance)
1807                 || node->details->maintenance)) {
1808             // Maintenance mode cancels recurring operations
1809             pcmk__schedule_cancel(rsc,
1810                                   crm_element_value(rsc_op, XML_LRM_ATTR_CALLID),
1811                                   task, interval_ms, node, "maintenance mode");
1812 
1813         } else if ((interval_ms > 0)
1814                    || pcmk__strcase_any_of(task, RSC_STATUS, RSC_START,
1815                                            RSC_PROMOTE, RSC_MIGRATED, NULL)) {
1816             /* If a resource operation failed, and the operation's definition
1817              * has changed, clear any fail count so they can be retried fresh.
1818              */
1819 
1820             if (pe__bundle_needs_remote_name(rsc, rsc->cluster)) {
1821                 /* We haven't allocated resources to nodes yet, so if the
1822                  * REMOTE_CONTAINER_HACK is used, we may calculate the digest
1823                  * based on the literal "#uname" value rather than the properly
1824                  * substituted value. That would mistakenly make the action
1825                  * definition appear to have been changed. Defer the check until
1826                  * later in this case.
1827                  */
1828                 pe__add_param_check(rsc_op, rsc, node, pe_check_active,
1829                                     rsc->cluster);
1830 
1831             } else if (pcmk__check_action_config(rsc, node, rsc_op)
1832                        && (pe_get_failcount(node, rsc, NULL, pe_fc_effective,
1833                                             NULL, rsc->cluster) != 0)) {
1834                 pe__clear_failcount(rsc, node, "action definition changed",
1835                                     rsc->cluster);
1836             }
1837         }
1838     }
1839     g_list_free(sorted_op_list);
1840 }
1841 
1842 /*!
1843  * \internal
1844  * \brief Process a node's action history from the CIB status
1845  *
1846  * Given a node's resource history, if the resource's configuration changed
1847  * since the actions were done, schedule any actions needed (restart,
1848  * reload, unfencing, rescheduling recurring actions, clean-up, etc.).
1849  * (This also cancels recurring actions for maintenance mode, which is not
1850  * entirely related but convenient to do here.)
1851  *
1852  * \param[in] node      Node whose history is being processed
1853  * \param[in] lrm_rscs  Node's <lrm_resources> from CIB status XML
1854  * \param[in] data_set  Cluster working set
1855  */
1856 static void
1857 process_node_history(pe_node_t *node, xmlNode *lrm_rscs, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1858 {
1859     crm_trace("Processing node history for %s", pe__node_name(node));
1860     for (xmlNode *rsc_entry = first_named_child(lrm_rscs, XML_LRM_TAG_RESOURCE);
1861          rsc_entry != NULL; rsc_entry = crm_next_same_xml(rsc_entry)) {
1862 
1863         if (xml_has_children(rsc_entry)) {
1864             GList *result = pcmk__rscs_matching_id(ID(rsc_entry), data_set);
1865 
1866             for (GList *iter = result; iter != NULL; iter = iter->next) {
1867                 pe_resource_t *rsc = (pe_resource_t *) iter->data;
1868 
1869                 if (rsc->variant == pe_native) {
1870                     process_rsc_history(rsc_entry, rsc, node);
1871                 }
1872             }
1873             g_list_free(result);
1874         }
1875     }
1876 }
1877 
1878 // XPath to find a node's resource history
1879 #define XPATH_NODE_HISTORY "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS             \
1880                            "/" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']" \
1881                            "/" XML_CIB_TAG_LRM "/" XML_LRM_TAG_RESOURCES
1882 
1883 /*!
1884  * \internal
1885  * \brief Process any resource configuration changes in the CIB status
1886  *
1887  * Go through all nodes' resource history, and if a resource's configuration
1888  * changed since its actions were done, schedule any actions needed (restart,
1889  * reload, unfencing, rescheduling recurring actions, clean-up, etc.).
1890  * (This also cancels recurring actions for maintenance mode, which is not
1891  * entirely related but convenient to do here.)
1892  *
1893  * \param[in] data_set  Cluster working set
1894  */
1895 void
1896 pcmk__handle_rsc_config_changes(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1897 {
1898     crm_trace("Check resource and action configuration for changes");
1899 
1900     /* Rather than iterate through the status section, iterate through the nodes
1901      * and search for the appropriate status subsection for each. This skips
1902      * orphaned nodes and lets us eliminate some cases before searching the XML.
1903      */
1904     for (GList *iter = data_set->nodes; iter != NULL; iter = iter->next) {
1905         pe_node_t *node = (pe_node_t *) iter->data;
1906 
1907         /* Don't bother checking actions for a node that can't run actions ...
1908          * unless it's in maintenance mode, in which case we still need to
1909          * cancel any existing recurring monitors.
1910          */
1911         if (node->details->maintenance
1912             || pcmk__node_available(node, false, false)) {
1913 
1914             char *xpath = NULL;
1915             xmlNode *history = NULL;
1916 
1917             xpath = crm_strdup_printf(XPATH_NODE_HISTORY, node->details->uname);
1918             history = get_xpath_object(xpath, data_set->input, LOG_NEVER);
1919             free(xpath);
1920 
1921             process_node_history(node, history, data_set);
1922         }
1923     }
1924 }

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