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-2023 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,out] 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, const 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, const 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,out] first        First action in an ordering
 209  * \param[in,out] 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,out] order        Action wrapper for \p first in ordering
 213  * \param[in,out] 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,out] then      Action to update
 497  * \param[in,out] 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(const 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,out] 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  * If the "first" action in an asymmetric ordering is unrunnable, make the
 701  * "second" action unrunnable as well, if appropriate.
 702  *
 703  * \param[in]     first  'First' action in an asymmetric ordering
 704  * \param[in,out] then   'Then' action in an asymmetric ordering
 705  */
 706 static void
 707 handle_asymmetric_ordering(const pe_action_t *first, pe_action_t *then)
     /* [previous][next][first][last][top][bottom][index][help] */
 708 {
 709     /* Only resource actions after an unrunnable 'first' action need updates for
 710      * asymmetric ordering.
 711      */
 712     if ((then->rsc == NULL) || pcmk_is_set(first->flags, pe_action_runnable)) {
 713         return;
 714     }
 715 
 716     // Certain optional 'then' actions are unaffected by unrunnable 'first'
 717     if (pcmk_is_set(then->flags, pe_action_optional)) {
 718         enum rsc_role_e then_rsc_role = then->rsc->fns->state(then->rsc, TRUE);
 719 
 720         if ((then_rsc_role == RSC_ROLE_STOPPED)
 721             && pcmk__str_eq(then->task, RSC_STOP, pcmk__str_none)) {
 722             /* If 'then' should stop after 'first' but is already stopped, the
 723              * ordering is irrelevant.
 724              */
 725             return;
 726         } else if ((then_rsc_role >= RSC_ROLE_STARTED)
 727             && pcmk__str_eq(then->task, RSC_START, pcmk__str_none)
 728             && pe__rsc_running_on_only(then->rsc, then->node)) {
 729             /* Similarly if 'then' should start after 'first' but is already
 730              * started on a single node.
 731              */
 732             return;
 733         }
 734     }
 735 
 736     // 'First' can't run, so 'then' can't either
 737     clear_action_flag_because(then, pe_action_optional, first);
 738     clear_action_flag_because(then, pe_action_runnable, first);
 739 }
 740 
 741 /*!
 742  * \internal
 743  * \brief Set action bits appropriately when pe_restart_order is used
 744  *
 745  * \param[in,out] first   'First' action in an ordering with pe_restart_order
 746  * \param[in,out] then    'Then' action in an ordering with pe_restart_order
 747  * \param[in]     filter  What action flags to care about
 748  *
 749  * \note pe_restart_order is set for "stop resource before starting it" and
 750  *       "stop later group member before stopping earlier group member"
 751  */
 752 static void
 753 handle_restart_ordering(pe_action_t *first, pe_action_t *then, uint32_t filter)
     /* [previous][next][first][last][top][bottom][index][help] */
 754 {
 755     const char *reason = NULL;
 756 
 757     CRM_ASSERT(is_primitive_action(first));
 758     CRM_ASSERT(is_primitive_action(then));
 759 
 760     // We need to update the action in two cases:
 761 
 762     // ... if 'then' is required
 763     if (pcmk_is_set(filter, pe_action_optional)
 764         && !pcmk_is_set(then->flags, pe_action_optional)) {
 765         reason = "restart";
 766     }
 767 
 768     /* ... if 'then' is unrunnable action on same resource (if a resource
 769      * should restart but can't start, we still want to stop)
 770      */
 771     if (pcmk_is_set(filter, pe_action_runnable)
 772         && !pcmk_is_set(then->flags, pe_action_runnable)
 773         && pcmk_is_set(then->rsc->flags, pe_rsc_managed)
 774         && (first->rsc == then->rsc)) {
 775         reason = "stop";
 776     }
 777 
 778     if (reason == NULL) {
 779         return;
 780     }
 781 
 782     pe_rsc_trace(first->rsc, "Handling %s -> %s for %s",
 783                  first->uuid, then->uuid, reason);
 784 
 785     // Make 'first' required if it is runnable
 786     if (pcmk_is_set(first->flags, pe_action_runnable)) {
 787         clear_action_flag_because(first, pe_action_optional, then);
 788     }
 789 
 790     // Make 'first' required if 'then' is required
 791     if (!pcmk_is_set(then->flags, pe_action_optional)) {
 792         clear_action_flag_because(first, pe_action_optional, then);
 793     }
 794 
 795     // Make 'first' unmigratable if 'then' is unmigratable
 796     if (!pcmk_is_set(then->flags, pe_action_migrate_runnable)) {
 797         clear_action_flag_because(first, pe_action_migrate_runnable, then);
 798     }
 799 
 800     // Make 'then' unrunnable if 'first' is required but unrunnable
 801     if (!pcmk_is_set(first->flags, pe_action_optional)
 802         && !pcmk_is_set(first->flags, pe_action_runnable)) {
 803         clear_action_flag_because(then, pe_action_runnable, first);
 804     }
 805 }
 806 
 807 /*!
 808  * \internal
 809  * \brief Update two actions according to an ordering between them
 810  *
 811  * Given information about an ordering of two actions, update the actions' flags
 812  * (and runnable_before members if appropriate) as appropriate for the ordering.
 813  * Effects may cascade to other orderings involving the actions as well.
 814  *
 815  * \param[in,out] first     'First' action in an ordering
 816  * \param[in,out] then      'Then' action in an ordering
 817  * \param[in]     node      If not NULL, limit scope of ordering to this node
 818  *                          (ignored)
 819  * \param[in]     flags     Action flags for \p first for ordering purposes
 820  * \param[in]     filter    Action flags to limit scope of certain updates (may
 821  *                          include pe_action_optional to affect only mandatory
 822  *                          actions, and pe_action_runnable to affect only
 823  *                          runnable actions)
 824  * \param[in]     type      Group of enum pe_ordering flags to apply
 825  * \param[in,out] data_set  Cluster working set
 826  *
 827  * \return Group of enum pcmk__updated flags indicating what was updated
 828  */
 829 uint32_t
 830 pcmk__update_ordered_actions(pe_action_t *first, pe_action_t *then,
     /* [previous][next][first][last][top][bottom][index][help] */
 831                              const pe_node_t *node, uint32_t flags,
 832                              uint32_t filter, uint32_t type,
 833                              pe_working_set_t *data_set)
 834 {
 835     uint32_t changed = pcmk__updated_none;
 836     uint32_t then_flags = then->flags;
 837     uint32_t first_flags = first->flags;
 838 
 839     if (pcmk_is_set(type, pe_order_asymmetrical)) {
 840         handle_asymmetric_ordering(first, then);
 841     }
 842 
 843     if (pcmk_is_set(type, pe_order_implies_first)
 844         && !pcmk_is_set(then_flags, pe_action_optional)) {
 845         // Then is required, and implies first should be, too
 846 
 847         if (pcmk_is_set(filter, pe_action_optional)
 848             && !pcmk_is_set(flags, pe_action_optional)
 849             && pcmk_is_set(first_flags, pe_action_optional)) {
 850             clear_action_flag_because(first, pe_action_optional, then);
 851         }
 852 
 853         if (pcmk_is_set(flags, pe_action_migrate_runnable)
 854             && !pcmk_is_set(then->flags, pe_action_migrate_runnable)) {
 855             clear_action_flag_because(first, pe_action_migrate_runnable, then);
 856         }
 857     }
 858 
 859     if (pcmk_is_set(type, pe_order_promoted_implies_first)
 860         && (then->rsc != NULL) && (then->rsc->role == RSC_ROLE_PROMOTED)
 861         && pcmk_is_set(filter, pe_action_optional)
 862         && !pcmk_is_set(then->flags, pe_action_optional)) {
 863 
 864         clear_action_flag_because(first, pe_action_optional, then);
 865 
 866         if (pcmk_is_set(first->flags, pe_action_migrate_runnable)
 867             && !pcmk_is_set(then->flags, pe_action_migrate_runnable)) {
 868             clear_action_flag_because(first, pe_action_migrate_runnable,
 869                                       then);
 870         }
 871     }
 872 
 873     if (pcmk_is_set(type, pe_order_implies_first_migratable)
 874         && pcmk_is_set(filter, pe_action_optional)) {
 875 
 876         if (!pcmk_all_flags_set(then->flags,
 877                                 pe_action_migrate_runnable|pe_action_runnable)) {
 878             clear_action_flag_because(first, pe_action_runnable, then);
 879         }
 880 
 881         if (!pcmk_is_set(then->flags, pe_action_optional)) {
 882             clear_action_flag_because(first, pe_action_optional, then);
 883         }
 884     }
 885 
 886     if (pcmk_is_set(type, pe_order_pseudo_left)
 887         && pcmk_is_set(filter, pe_action_optional)
 888         && !pcmk_is_set(first->flags, pe_action_runnable)) {
 889 
 890         clear_action_flag_because(then, pe_action_migrate_runnable, first);
 891         pe__clear_action_flags(then, pe_action_pseudo);
 892     }
 893 
 894     if (pcmk_is_set(type, pe_order_runnable_left)
 895         && pcmk_is_set(filter, pe_action_runnable)
 896         && pcmk_is_set(then->flags, pe_action_runnable)
 897         && !pcmk_is_set(flags, pe_action_runnable)) {
 898 
 899         clear_action_flag_because(then, pe_action_runnable, first);
 900         clear_action_flag_because(then, pe_action_migrate_runnable, first);
 901     }
 902 
 903     if (pcmk_is_set(type, pe_order_implies_then)
 904         && pcmk_is_set(filter, pe_action_optional)
 905         && pcmk_is_set(then->flags, pe_action_optional)
 906         && !pcmk_is_set(flags, pe_action_optional)
 907         && !pcmk_is_set(first->flags, pe_action_migrate_runnable)) {
 908 
 909         clear_action_flag_because(then, pe_action_optional, first);
 910     }
 911 
 912     if (pcmk_is_set(type, pe_order_restart)) {
 913         handle_restart_ordering(first, then, filter);
 914     }
 915 
 916     if (then_flags != then->flags) {
 917         pcmk__set_updated_flags(changed, first, pcmk__updated_then);
 918         pe_rsc_trace(then->rsc,
 919                      "%s on %s: flags are now %#.6x (was %#.6x) "
 920                      "because of 'first' %s (%#.6x)",
 921                      then->uuid, pe__node_name(then->node),
 922                      then->flags, then_flags, first->uuid, first->flags);
 923 
 924         if ((then->rsc != NULL) && (then->rsc->parent != NULL)) {
 925             // Required to handle "X_stop then X_start" for cloned groups
 926             pcmk__update_action_for_orderings(then, data_set);
 927         }
 928     }
 929 
 930     if (first_flags != first->flags) {
 931         pcmk__set_updated_flags(changed, first, pcmk__updated_first);
 932         pe_rsc_trace(first->rsc,
 933                      "%s on %s: flags are now %#.6x (was %#.6x) "
 934                      "because of 'then' %s (%#.6x)",
 935                      first->uuid, pe__node_name(first->node),
 936                      first->flags, first_flags, then->uuid, then->flags);
 937     }
 938 
 939     return changed;
 940 }
 941 
 942 /*!
 943  * \internal
 944  * \brief Trace-log an action (optionally with its dependent actions)
 945  *
 946  * \param[in] pre_text  If not NULL, prefix the log with this plus ": "
 947  * \param[in] action    Action to log
 948  * \param[in] details   If true, recursively log dependent actions
 949  */
 950 void
 951 pcmk__log_action(const char *pre_text, const pe_action_t *action, bool details)
     /* [previous][next][first][last][top][bottom][index][help] */
 952 {
 953     const char *node_uname = NULL;
 954     const char *node_uuid = NULL;
 955     const char *desc = NULL;
 956 
 957     CRM_CHECK(action != NULL, return);
 958 
 959     if (!pcmk_is_set(action->flags, pe_action_pseudo)) {
 960         if (action->node != NULL) {
 961             node_uname = action->node->details->uname;
 962             node_uuid = action->node->details->id;
 963         } else {
 964             node_uname = "<none>";
 965         }
 966     }
 967 
 968     switch (text2task(action->task)) {
 969         case stonith_node:
 970         case shutdown_crm:
 971             if (pcmk_is_set(action->flags, pe_action_pseudo)) {
 972                 desc = "Pseudo ";
 973             } else if (pcmk_is_set(action->flags, pe_action_optional)) {
 974                 desc = "Optional ";
 975             } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 976                 desc = "!!Non-Startable!! ";
 977             } else if (pcmk_is_set(action->flags, pe_action_processed)) {
 978                desc = "";
 979             } else {
 980                desc = "(Provisional) ";
 981             }
 982             crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
 983                       ((pre_text == NULL)? "" : pre_text),
 984                       ((pre_text == NULL)? "" : ": "),
 985                       desc, action->id, action->uuid,
 986                       (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
 987                       (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
 988                       (node_uuid? ")" : ""));
 989             break;
 990         default:
 991             if (pcmk_is_set(action->flags, pe_action_optional)) {
 992                 desc = "Optional ";
 993             } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
 994                 desc = "Pseudo ";
 995             } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 996                 desc = "!!Non-Startable!! ";
 997             } else if (pcmk_is_set(action->flags, pe_action_processed)) {
 998                desc = "";
 999             } else {
1000                desc = "(Provisional) ";
1001             }
1002             crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
1003                       ((pre_text == NULL)? "" : pre_text),
1004                       ((pre_text == NULL)? "" : ": "),
1005                       desc, action->id, action->uuid,
1006                       (action->rsc? action->rsc->id : "<none>"),
1007                       (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1008                       (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1009                       (node_uuid? ")" : ""));
1010             break;
1011     }
1012 
1013     if (details) {
1014         const GList *iter = NULL;
1015         const pe_action_wrapper_t *other = NULL;
1016 
1017         crm_trace("\t\t====== Preceding Actions");
1018         for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1019             other = (const pe_action_wrapper_t *) iter->data;
1020             pcmk__log_action("\t\t", other->action, false);
1021         }
1022         crm_trace("\t\t====== Subsequent Actions");
1023         for (iter = action->actions_after; iter != NULL; iter = iter->next) {
1024             other = (const pe_action_wrapper_t *) iter->data;
1025             pcmk__log_action("\t\t", other->action, false);
1026         }
1027         crm_trace("\t\t====== End");
1028 
1029     } else {
1030         crm_trace("\t\t(before=%d, after=%d)",
1031                   g_list_length(action->actions_before),
1032                   g_list_length(action->actions_after));
1033     }
1034 }
1035 
1036 /*!
1037  * \internal
1038  * \brief Create a new shutdown action for a node
1039  *
1040  * \param[in,out] node  Node being shut down
1041  *
1042  * \return Newly created shutdown action for \p node
1043  */
1044 pe_action_t *
1045 pcmk__new_shutdown_action(pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1046 {
1047     char *shutdown_id = NULL;
1048     pe_action_t *shutdown_op = NULL;
1049 
1050     CRM_ASSERT(node != NULL);
1051 
1052     shutdown_id = crm_strdup_printf("%s-%s", CRM_OP_SHUTDOWN,
1053                                     node->details->uname);
1054 
1055     shutdown_op = custom_action(NULL, shutdown_id, CRM_OP_SHUTDOWN, node, FALSE,
1056                                 TRUE, node->details->data_set);
1057 
1058     pcmk__order_stops_before_shutdown(node, shutdown_op);
1059     add_hash_param(shutdown_op->meta, XML_ATTR_TE_NOWAIT, XML_BOOLEAN_TRUE);
1060     return shutdown_op;
1061 }
1062 
1063 /*!
1064  * \internal
1065  * \brief Calculate and add an operation digest to XML
1066  *
1067  * Calculate an operation digest, which enables us to later determine when a
1068  * restart is needed due to the resource's parameters being changed, and add it
1069  * to given XML.
1070  *
1071  * \param[in]     op      Operation result from executor
1072  * \param[in,out] update  XML to add digest to
1073  */
1074 static void
1075 add_op_digest_to_xml(const lrmd_event_data_t *op, xmlNode *update)
     /* [previous][next][first][last][top][bottom][index][help] */
1076 {
1077     char *digest = NULL;
1078     xmlNode *args_xml = NULL;
1079 
1080     if (op->params == NULL) {
1081         return;
1082     }
1083     args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
1084     g_hash_table_foreach(op->params, hash2field, args_xml);
1085     pcmk__filter_op_for_digest(args_xml);
1086     digest = calculate_operation_digest(args_xml, NULL);
1087     crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
1088     free_xml(args_xml);
1089     free(digest);
1090 }
1091 
1092 #define FAKE_TE_ID     "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1093 
1094 /*!
1095  * \internal
1096  * \brief Create XML for resource operation history update
1097  *
1098  * \param[in,out] parent          Parent XML node to add to
1099  * \param[in,out] op              Operation event data
1100  * \param[in]     caller_version  DC feature set
1101  * \param[in]     target_rc       Expected result of operation
1102  * \param[in]     node            Name of node on which operation was performed
1103  * \param[in]     origin          Arbitrary description of update source
1104  *
1105  * \return Newly created XML node for history update
1106  */
1107 xmlNode *
1108 pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *op,
     /* [previous][next][first][last][top][bottom][index][help] */
1109                          const char *caller_version, int target_rc,
1110                          const char *node, const char *origin)
1111 {
1112     char *key = NULL;
1113     char *magic = NULL;
1114     char *op_id = NULL;
1115     char *op_id_additional = NULL;
1116     char *local_user_data = NULL;
1117     const char *exit_reason = NULL;
1118 
1119     xmlNode *xml_op = NULL;
1120     const char *task = NULL;
1121 
1122     CRM_CHECK(op != NULL, return NULL);
1123     crm_trace("Creating history XML for %s-interval %s action for %s on %s "
1124               "(DC version: %s, origin: %s)",
1125               pcmk__readable_interval(op->interval_ms), op->op_type, op->rsc_id,
1126               ((node == NULL)? "no node" : node), caller_version, origin);
1127 
1128     task = op->op_type;
1129 
1130     /* Record a successful agent reload as a start, and a failed one as a
1131      * monitor, to make life easier for the scheduler when determining the
1132      * current state.
1133      *
1134      * @COMPAT We should check "reload" here only if the operation was for a
1135      * pre-OCF-1.1 resource agent, but we don't know that here, and we should
1136      * only ever get results for actions scheduled by us, so we can reasonably
1137      * assume any "reload" is actually a pre-1.1 agent reload.
1138      */
1139     if (pcmk__str_any_of(task, CRMD_ACTION_RELOAD, CRMD_ACTION_RELOAD_AGENT,
1140                          NULL)) {
1141         if (op->op_status == PCMK_EXEC_DONE) {
1142             task = CRMD_ACTION_START;
1143         } else {
1144             task = CRMD_ACTION_STATUS;
1145         }
1146     }
1147 
1148     key = pcmk__op_key(op->rsc_id, task, op->interval_ms);
1149     if (pcmk__str_eq(task, CRMD_ACTION_NOTIFY, pcmk__str_none)) {
1150         const char *n_type = crm_meta_value(op->params, "notify_type");
1151         const char *n_task = crm_meta_value(op->params, "notify_operation");
1152 
1153         CRM_LOG_ASSERT(n_type != NULL);
1154         CRM_LOG_ASSERT(n_task != NULL);
1155         op_id = pcmk__notify_key(op->rsc_id, n_type, n_task);
1156 
1157         if (op->op_status != PCMK_EXEC_PENDING) {
1158             /* Ignore notify errors.
1159              *
1160              * @TODO It might be better to keep the correct result here, and
1161              * ignore it in process_graph_event().
1162              */
1163             lrmd__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1164         }
1165 
1166     /* Migration history is preserved separately, which usually matters for
1167      * multiple nodes and is important for future cluster transitions.
1168      */
1169     } else if (pcmk__str_any_of(op->op_type, CRMD_ACTION_MIGRATE,
1170                                 CRMD_ACTION_MIGRATED, NULL)) {
1171         op_id = strdup(key);
1172 
1173     } else if (did_rsc_op_fail(op, target_rc)) {
1174         op_id = pcmk__op_key(op->rsc_id, "last_failure", 0);
1175         if (op->interval_ms == 0) {
1176             // Ensure 'last' gets updated, in case record-pending is true
1177             op_id_additional = pcmk__op_key(op->rsc_id, "last", 0);
1178         }
1179         exit_reason = op->exit_reason;
1180 
1181     } else if (op->interval_ms > 0) {
1182         op_id = strdup(key);
1183 
1184     } else {
1185         op_id = pcmk__op_key(op->rsc_id, "last", 0);
1186     }
1187 
1188   again:
1189     xml_op = pcmk__xe_match(parent, XML_LRM_TAG_RSC_OP, XML_ATTR_ID, op_id);
1190     if (xml_op == NULL) {
1191         xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
1192     }
1193 
1194     if (op->user_data == NULL) {
1195         crm_debug("Generating fake transition key for: " PCMK__OP_FMT
1196                   " %d from %s", op->rsc_id, op->op_type, op->interval_ms,
1197                   op->call_id, origin);
1198         local_user_data = pcmk__transition_key(-1, op->call_id, target_rc,
1199                                                FAKE_TE_ID);
1200         op->user_data = local_user_data;
1201     }
1202 
1203     if (magic == NULL) {
1204         magic = crm_strdup_printf("%d:%d;%s", op->op_status, op->rc,
1205                                   (const char *) op->user_data);
1206     }
1207 
1208     crm_xml_add(xml_op, XML_ATTR_ID, op_id);
1209     crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
1210     crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
1211     crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
1212     crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
1213     crm_xml_add(xml_op, XML_ATTR_TRANSITION_KEY, op->user_data);
1214     crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
1215     crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason == NULL ? "" : exit_reason);
1216     crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); /* For context during triage */
1217 
1218     crm_xml_add_int(xml_op, XML_LRM_ATTR_CALLID, op->call_id);
1219     crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
1220     crm_xml_add_int(xml_op, XML_LRM_ATTR_OPSTATUS, op->op_status);
1221     crm_xml_add_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, op->interval_ms);
1222 
1223     if (compare_version("2.1", caller_version) <= 0) {
1224         if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1225             crm_trace("Timing data (" PCMK__OP_FMT
1226                       "): last=%u change=%u exec=%u queue=%u",
1227                       op->rsc_id, op->op_type, op->interval_ms,
1228                       op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1229 
1230             if ((op->interval_ms != 0) && (op->t_rcchange != 0)) {
1231                 // Recurring ops may have changed rc after initial run
1232                 crm_xml_add_ll(xml_op, XML_RSC_OP_LAST_CHANGE,
1233                                (long long) op->t_rcchange);
1234             } else {
1235                 crm_xml_add_ll(xml_op, XML_RSC_OP_LAST_CHANGE,
1236                                (long long) op->t_run);
1237             }
1238 
1239             crm_xml_add_int(xml_op, XML_RSC_OP_T_EXEC, op->exec_time);
1240             crm_xml_add_int(xml_op, XML_RSC_OP_T_QUEUE, op->queue_time);
1241         }
1242     }
1243 
1244     if (pcmk__str_any_of(op->op_type, CRMD_ACTION_MIGRATE, CRMD_ACTION_MIGRATED, NULL)) {
1245         /*
1246          * Record migrate_source and migrate_target always for migrate ops.
1247          */
1248         const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
1249 
1250         crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1251 
1252         name = XML_LRM_ATTR_MIGRATE_TARGET;
1253         crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1254     }
1255 
1256     add_op_digest_to_xml(op, xml_op);
1257 
1258     if (op_id_additional) {
1259         free(op_id);
1260         op_id = op_id_additional;
1261         op_id_additional = NULL;
1262         goto again;
1263     }
1264 
1265     if (local_user_data) {
1266         free(local_user_data);
1267         op->user_data = NULL;
1268     }
1269     free(magic);
1270     free(op_id);
1271     free(key);
1272     return xml_op;
1273 }
1274 
1275 /*!
1276  * \internal
1277  * \brief Check whether an action shutdown-locks a resource to a node
1278  *
1279  * If the shutdown-lock cluster property is set, resources will not be recovered
1280  * on a different node if cleanly stopped, and may start only on that same node.
1281  * This function checks whether that applies to a given action, so that the
1282  * transition graph can be marked appropriately.
1283  *
1284  * \param[in] action  Action to check
1285  *
1286  * \return true if \p action locks its resource to the action's node,
1287  *         otherwise false
1288  */
1289 bool
1290 pcmk__action_locks_rsc_to_node(const pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1291 {
1292     // Only resource actions taking place on resource's lock node are locked
1293     if ((action == NULL) || (action->rsc == NULL)
1294         || (action->rsc->lock_node == NULL) || (action->node == NULL)
1295         || (action->node->details != action->rsc->lock_node->details)) {
1296         return false;
1297     }
1298 
1299     /* During shutdown, only stops are locked (otherwise, another action such as
1300      * a demote would cause the controller to clear the lock)
1301      */
1302     if (action->node->details->shutdown && (action->task != NULL)
1303         && (strcmp(action->task, RSC_STOP) != 0)) {
1304         return false;
1305     }
1306 
1307     return true;
1308 }
1309 
1310 /* lowest to highest */
1311 static gint
1312 sort_action_id(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
1313 {
1314     const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1315     const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1316 
1317     if (a == NULL) {
1318         return 1;
1319     }
1320     if (b == NULL) {
1321         return -1;
1322     }
1323     if (action_wrapper1->action->id < action_wrapper2->action->id) {
1324         return 1;
1325     }
1326     if (action_wrapper1->action->id > action_wrapper2->action->id) {
1327         return -1;
1328     }
1329     return 0;
1330 }
1331 
1332 /*!
1333  * \internal
1334  * \brief Remove any duplicate action inputs, merging action flags
1335  *
1336  * \param[in,out] action  Action whose inputs should be checked
1337  */
1338 void
1339 pcmk__deduplicate_action_inputs(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1340 {
1341     GList *item = NULL;
1342     GList *next = NULL;
1343     pe_action_wrapper_t *last_input = NULL;
1344 
1345     action->actions_before = g_list_sort(action->actions_before,
1346                                          sort_action_id);
1347     for (item = action->actions_before; item != NULL; item = next) {
1348         pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1349 
1350         next = item->next;
1351         if ((last_input != NULL)
1352             && (input->action->id == last_input->action->id)) {
1353             crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1354                       input->action->uuid, input->action->id,
1355                       action->uuid, action->id);
1356 
1357             /* For the purposes of scheduling, the ordering flags no longer
1358              * matter, but crm_simulate looks at certain ones when creating a
1359              * dot graph. Combining the flags is sufficient for that purpose.
1360              */
1361             last_input->type |= input->type;
1362             if (input->state == pe_link_dumped) {
1363                 last_input->state = pe_link_dumped;
1364             }
1365 
1366             free(item->data);
1367             action->actions_before = g_list_delete_link(action->actions_before,
1368                                                         item);
1369         } else {
1370             last_input = input;
1371             input->state = pe_link_not_dumped;
1372         }
1373     }
1374 }
1375 
1376 /*!
1377  * \internal
1378  * \brief Output all scheduled actions
1379  *
1380  * \param[in,out] data_set  Cluster working set
1381  */
1382 void
1383 pcmk__output_actions(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1384 {
1385     pcmk__output_t *out = data_set->priv;
1386 
1387     // Output node (non-resource) actions
1388     for (GList *iter = data_set->actions; iter != NULL; iter = iter->next) {
1389         char *node_name = NULL;
1390         char *task = NULL;
1391         pe_action_t *action = (pe_action_t *) iter->data;
1392 
1393         if (action->rsc != NULL) {
1394             continue; // Resource actions will be output later
1395 
1396         } else if (pcmk_is_set(action->flags, pe_action_optional)) {
1397             continue; // This action was not scheduled
1398         }
1399 
1400         if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1401             task = strdup("Shutdown");
1402 
1403         } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
1404             const char *op = g_hash_table_lookup(action->meta, "stonith_action");
1405 
1406             task = crm_strdup_printf("Fence (%s)", op);
1407 
1408         } else {
1409             continue; // Don't display other node action types
1410         }
1411 
1412         if (pe__is_guest_node(action->node)) {
1413             node_name = crm_strdup_printf("%s (resource: %s)",
1414                                           pe__node_name(action->node),
1415                                           action->node->details->remote_rsc->container->id);
1416         } else if (action->node != NULL) {
1417             node_name = crm_strdup_printf("%s", pe__node_name(action->node));
1418         }
1419 
1420         out->message(out, "node-action", task, node_name, action->reason);
1421 
1422         free(node_name);
1423         free(task);
1424     }
1425 
1426     // Output resource actions
1427     for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
1428         pe_resource_t *rsc = (pe_resource_t *) iter->data;
1429 
1430         rsc->cmds->output_actions(rsc);
1431     }
1432 }
1433 
1434 /*!
1435  * \internal
1436  * \brief Check whether action from resource history is still in configuration
1437  *
1438  * \param[in] rsc          Resource that action is for
1439  * \param[in] task         Action's name
1440  * \param[in] interval_ms  Action's interval (in milliseconds)
1441  *
1442  * \return true if action is still in resource configuration, otherwise false
1443  */
1444 static bool
1445 action_in_config(const pe_resource_t *rsc, const char *task, guint interval_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
1446 {
1447     char *key = pcmk__op_key(rsc->id, task, interval_ms);
1448     bool config = (find_rsc_op_entry(rsc, key) != NULL);
1449 
1450     free(key);
1451     return config;
1452 }
1453 
1454 /*!
1455  * \internal
1456  * \brief Get action name needed to compare digest for configuration changes
1457  *
1458  * \param[in] task         Action name from history
1459  * \param[in] interval_ms  Action interval (in milliseconds)
1460  *
1461  * \return Action name whose digest should be compared
1462  */
1463 static const char *
1464 task_for_digest(const char *task, guint interval_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
1465 {
1466     /* Certain actions need to be compared against the parameters used to start
1467      * the resource.
1468      */
1469     if ((interval_ms == 0)
1470         && pcmk__str_any_of(task, RSC_STATUS, RSC_MIGRATED, RSC_PROMOTE, NULL)) {
1471         task = RSC_START;
1472     }
1473     return task;
1474 }
1475 
1476 /*!
1477  * \internal
1478  * \brief Check whether only sanitized parameters to an action changed
1479  *
1480  * When collecting CIB files for troubleshooting, crm_report will mask
1481  * sensitive resource parameters. If simulations were run using that, affected
1482  * resources would appear to need a restart, which would complicate
1483  * troubleshooting. To avoid that, we save a "secure digest" of non-sensitive
1484  * parameters. This function used that digest to check whether only masked
1485  * parameters are different.
1486  *
1487  * \param[in] xml_op       Resource history entry with secure digest
1488  * \param[in] digest_data  Operation digest information being compared
1489  * \param[in] data_set     Cluster working set
1490  *
1491  * \return true if only sanitized parameters changed, otherwise false
1492  */
1493 static bool
1494 only_sanitized_changed(const xmlNode *xml_op,
     /* [previous][next][first][last][top][bottom][index][help] */
1495                        const op_digest_cache_t *digest_data,
1496                        const pe_working_set_t *data_set)
1497 {
1498     const char *digest_secure = NULL;
1499 
1500     if (!pcmk_is_set(data_set->flags, pe_flag_sanitized)) {
1501         // The scheduler is not being run as a simulation
1502         return false;
1503     }
1504 
1505     digest_secure = crm_element_value(xml_op, XML_LRM_ATTR_SECURE_DIGEST);
1506 
1507     return (digest_data->rc != RSC_DIGEST_MATCH) && (digest_secure != NULL)
1508            && (digest_data->digest_secure_calc != NULL)
1509            && (strcmp(digest_data->digest_secure_calc, digest_secure) == 0);
1510 }
1511 
1512 /*!
1513  * \internal
1514  * \brief Force a restart due to a configuration change
1515  *
1516  * \param[in,out] rsc          Resource that action is for
1517  * \param[in]     task         Name of action whose configuration changed
1518  * \param[in]     interval_ms  Action interval (in milliseconds)
1519  * \param[in,out] node         Node where resource should be restarted
1520  */
1521 static void
1522 force_restart(pe_resource_t *rsc, const char *task, guint interval_ms,
     /* [previous][next][first][last][top][bottom][index][help] */
1523               pe_node_t *node)
1524 {
1525     char *key = pcmk__op_key(rsc->id, task, interval_ms);
1526     pe_action_t *required = custom_action(rsc, key, task, NULL, FALSE, TRUE,
1527                                           rsc->cluster);
1528 
1529     pe_action_set_reason(required, "resource definition change", true);
1530     trigger_unfencing(rsc, node, "Device parameters changed", NULL,
1531                       rsc->cluster);
1532 }
1533 
1534 /*!
1535  * \internal
1536  * \brief Schedule a reload of a resource on a node
1537  *
1538  * \param[in,out] rsc   Resource to reload
1539  * \param[in]     node  Where resource should be reloaded
1540  */
1541 static void
1542 schedule_reload(pe_resource_t *rsc, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1543 {
1544     pe_action_t *reload = NULL;
1545 
1546     // For collective resources, just call recursively for children
1547     if (rsc->variant > pe_native) {
1548         g_list_foreach(rsc->children, (GFunc) schedule_reload, (gpointer) node);
1549         return;
1550     }
1551 
1552     // Skip the reload in certain situations
1553     if ((node == NULL)
1554         || !pcmk_is_set(rsc->flags, pe_rsc_managed)
1555         || pcmk_is_set(rsc->flags, pe_rsc_failed)) {
1556         pe_rsc_trace(rsc, "Skip reload of %s:%s%s %s",
1557                      rsc->id,
1558                      pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : " unmanaged",
1559                      pcmk_is_set(rsc->flags, pe_rsc_failed)? " failed" : "",
1560                      (node == NULL)? "inactive" : node->details->uname);
1561         return;
1562     }
1563 
1564     /* If a resource's configuration changed while a start was pending,
1565      * force a full restart instead of a reload.
1566      */
1567     if (pcmk_is_set(rsc->flags, pe_rsc_start_pending)) {
1568         pe_rsc_trace(rsc, "%s: preventing agent reload because start pending",
1569                      rsc->id);
1570         custom_action(rsc, stop_key(rsc), CRMD_ACTION_STOP, node, FALSE, TRUE,
1571                       rsc->cluster);
1572         return;
1573     }
1574 
1575     // Schedule the reload
1576     pe__set_resource_flags(rsc, pe_rsc_reload);
1577     reload = custom_action(rsc, reload_key(rsc), CRMD_ACTION_RELOAD_AGENT, node,
1578                            FALSE, TRUE, rsc->cluster);
1579     pe_action_set_reason(reload, "resource definition change", FALSE);
1580 
1581     // Set orderings so that a required stop or demote cancels the reload
1582     pcmk__new_ordering(NULL, NULL, reload, rsc, stop_key(rsc), NULL,
1583                        pe_order_optional|pe_order_then_cancels_first,
1584                        rsc->cluster);
1585     pcmk__new_ordering(NULL, NULL, reload, rsc, demote_key(rsc), NULL,
1586                        pe_order_optional|pe_order_then_cancels_first,
1587                        rsc->cluster);
1588 }
1589 
1590 /*!
1591  * \internal
1592  * \brief Handle any configuration change for an action
1593  *
1594  * Given an action from resource history, if the resource's configuration
1595  * changed since the action was done, schedule any actions needed (restart,
1596  * reload, unfencing, rescheduling recurring actions, etc.).
1597  *
1598  * \param[in,out] rsc     Resource that action is for
1599  * \param[in,out] node    Node that action was on
1600  * \param[in]     xml_op  Action XML from resource history
1601  *
1602  * \return true if action configuration changed, otherwise false
1603  */
1604 bool
1605 pcmk__check_action_config(pe_resource_t *rsc, pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
1606                           const xmlNode *xml_op)
1607 {
1608     guint interval_ms = 0;
1609     const char *task = NULL;
1610     const op_digest_cache_t *digest_data = NULL;
1611 
1612     CRM_CHECK((rsc != NULL) && (node != NULL) && (xml_op != NULL),
1613               return false);
1614 
1615     task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1616     CRM_CHECK(task != NULL, return false);
1617 
1618     crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1619 
1620     // If this is a recurring action, check whether it has been orphaned
1621     if (interval_ms > 0) {
1622         if (action_in_config(rsc, task, interval_ms)) {
1623             pe_rsc_trace(rsc, "%s-interval %s for %s on %s is in configuration",
1624                          pcmk__readable_interval(interval_ms), task, rsc->id,
1625                          pe__node_name(node));
1626         } else if (pcmk_is_set(rsc->cluster->flags,
1627                                pe_flag_stop_action_orphans)) {
1628             pcmk__schedule_cancel(rsc,
1629                                   crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1630                                   task, interval_ms, node, "orphan");
1631             return true;
1632         } else {
1633             pe_rsc_debug(rsc, "%s-interval %s for %s on %s is orphaned",
1634                          pcmk__readable_interval(interval_ms), task, rsc->id,
1635                          pe__node_name(node));
1636             return true;
1637         }
1638     }
1639 
1640     crm_trace("Checking %s-interval %s for %s on %s for configuration changes",
1641               pcmk__readable_interval(interval_ms), task, rsc->id,
1642               pe__node_name(node));
1643     task = task_for_digest(task, interval_ms);
1644     digest_data = rsc_action_digest_cmp(rsc, xml_op, node, rsc->cluster);
1645 
1646     if (only_sanitized_changed(xml_op, digest_data, rsc->cluster)) {
1647         if (!pcmk__is_daemon && (rsc->cluster->priv != NULL)) {
1648             pcmk__output_t *out = rsc->cluster->priv;
1649 
1650             out->info(out,
1651                       "Only 'private' parameters to %s-interval %s for %s "
1652                       "on %s changed: %s",
1653                       pcmk__readable_interval(interval_ms), task, rsc->id,
1654                       pe__node_name(node),
1655                       crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
1656         }
1657         return false;
1658     }
1659 
1660     switch (digest_data->rc) {
1661         case RSC_DIGEST_RESTART:
1662             crm_log_xml_debug(digest_data->params_restart, "params:restart");
1663             force_restart(rsc, task, interval_ms, node);
1664             return true;
1665 
1666         case RSC_DIGEST_ALL:
1667         case RSC_DIGEST_UNKNOWN:
1668             // Changes that can potentially be handled by an agent reload
1669 
1670             if (interval_ms > 0) {
1671                 /* Recurring actions aren't reloaded per se, they are just
1672                  * re-scheduled so the next run uses the new parameters.
1673                  * The old instance will be cancelled automatically.
1674                  */
1675                 crm_log_xml_debug(digest_data->params_all, "params:reschedule");
1676                 pcmk__reschedule_recurring(rsc, task, interval_ms, node);
1677 
1678             } else if (crm_element_value(xml_op,
1679                                          XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
1680                 // Agent supports reload, so use it
1681                 trigger_unfencing(rsc, node,
1682                                   "Device parameters changed (reload)", NULL,
1683                                   rsc->cluster);
1684                 crm_log_xml_debug(digest_data->params_all, "params:reload");
1685                 schedule_reload(rsc, node);
1686 
1687             } else {
1688                 pe_rsc_trace(rsc,
1689                              "Restarting %s because agent doesn't support reload",
1690                              rsc->id);
1691                 crm_log_xml_debug(digest_data->params_restart,
1692                                   "params:restart");
1693                 force_restart(rsc, task, interval_ms, node);
1694             }
1695             return true;
1696 
1697         default:
1698             break;
1699     }
1700     return false;
1701 }
1702 
1703 /*!
1704  * \internal
1705  * \brief Create a list of resource's action history entries, sorted by call ID
1706  *
1707  * \param[in]  rsc_entry    Resource's <lrm_rsc_op> status XML
1708  * \param[out] start_index  Where to store index of start-like action, if any
1709  * \param[out] stop_index   Where to store index of stop action, if any
1710  */
1711 static GList *
1712 rsc_history_as_list(const xmlNode *rsc_entry, int *start_index, int *stop_index)
     /* [previous][next][first][last][top][bottom][index][help] */
1713 {
1714     GList *ops = NULL;
1715 
1716     for (xmlNode *rsc_op = first_named_child(rsc_entry, XML_LRM_TAG_RSC_OP);
1717          rsc_op != NULL; rsc_op = crm_next_same_xml(rsc_op)) {
1718         ops = g_list_prepend(ops, rsc_op);
1719     }
1720     ops = g_list_sort(ops, sort_op_by_callid);
1721     calculate_active_ops(ops, start_index, stop_index);
1722     return ops;
1723 }
1724 
1725 /*!
1726  * \internal
1727  * \brief Process a resource's action history from the CIB status
1728  *
1729  * Given a resource's action history, if the resource's configuration
1730  * changed since the actions were done, schedule any actions needed (restart,
1731  * reload, unfencing, rescheduling recurring actions, clean-up, etc.).
1732  * (This also cancels recurring actions for maintenance mode, which is not
1733  * entirely related but convenient to do here.)
1734  *
1735  * \param[in]     rsc_entry  Resource's <lrm_rsc_op> status XML
1736  * \param[in,out] rsc        Resource whose history is being processed
1737  * \param[in,out] node       Node whose history is being processed
1738  */
1739 static void
1740 process_rsc_history(const xmlNode *rsc_entry, pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
1741                     pe_node_t *node)
1742 {
1743     int offset = -1;
1744     int stop_index = 0;
1745     int start_index = 0;
1746     GList *sorted_op_list = NULL;
1747 
1748     if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
1749         if (pe_rsc_is_anon_clone(pe__const_top_resource(rsc, false))) {
1750             pe_rsc_trace(rsc,
1751                          "Skipping configuration check "
1752                          "for orphaned clone instance %s",
1753                          rsc->id);
1754         } else {
1755             pe_rsc_trace(rsc,
1756                          "Skipping configuration check and scheduling clean-up "
1757                          "for orphaned resource %s", rsc->id);
1758             pcmk__schedule_cleanup(rsc, node, false);
1759         }
1760         return;
1761     }
1762 
1763     if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
1764         if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, false)) {
1765             pcmk__schedule_cleanup(rsc, node, false);
1766         }
1767         pe_rsc_trace(rsc,
1768                      "Skipping configuration check for %s "
1769                      "because no longer active on %s",
1770                      rsc->id, pe__node_name(node));
1771         return;
1772     }
1773 
1774     pe_rsc_trace(rsc, "Checking for configuration changes for %s on %s",
1775                  rsc->id, pe__node_name(node));
1776 
1777     if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, true)) {
1778         pcmk__schedule_cleanup(rsc, node, false);
1779     }
1780 
1781     sorted_op_list = rsc_history_as_list(rsc_entry, &start_index, &stop_index);
1782     if (start_index < stop_index) {
1783         return; // Resource is stopped
1784     }
1785 
1786     for (GList *iter = sorted_op_list; iter != NULL; iter = iter->next) {
1787         xmlNode *rsc_op = (xmlNode *) iter->data;
1788         const char *task = NULL;
1789         guint interval_ms = 0;
1790 
1791         if (++offset < start_index) {
1792             // Skip actions that happened before a start
1793             continue;
1794         }
1795 
1796         task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
1797         crm_element_value_ms(rsc_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1798 
1799         if ((interval_ms > 0)
1800             && (pcmk_is_set(rsc->flags, pe_rsc_maintenance)
1801                 || node->details->maintenance)) {
1802             // Maintenance mode cancels recurring operations
1803             pcmk__schedule_cancel(rsc,
1804                                   crm_element_value(rsc_op, XML_LRM_ATTR_CALLID),
1805                                   task, interval_ms, node, "maintenance mode");
1806 
1807         } else if ((interval_ms > 0)
1808                    || pcmk__strcase_any_of(task, RSC_STATUS, RSC_START,
1809                                            RSC_PROMOTE, RSC_MIGRATED, NULL)) {
1810             /* If a resource operation failed, and the operation's definition
1811              * has changed, clear any fail count so they can be retried fresh.
1812              */
1813 
1814             if (pe__bundle_needs_remote_name(rsc)) {
1815                 /* We haven't allocated resources to nodes yet, so if the
1816                  * REMOTE_CONTAINER_HACK is used, we may calculate the digest
1817                  * based on the literal "#uname" value rather than the properly
1818                  * substituted value. That would mistakenly make the action
1819                  * definition appear to have been changed. Defer the check until
1820                  * later in this case.
1821                  */
1822                 pe__add_param_check(rsc_op, rsc, node, pe_check_active,
1823                                     rsc->cluster);
1824 
1825             } else if (pcmk__check_action_config(rsc, node, rsc_op)
1826                        && (pe_get_failcount(node, rsc, NULL, pe_fc_effective,
1827                                             NULL) != 0)) {
1828                 pe__clear_failcount(rsc, node, "action definition changed",
1829                                     rsc->cluster);
1830             }
1831         }
1832     }
1833     g_list_free(sorted_op_list);
1834 }
1835 
1836 /*!
1837  * \internal
1838  * \brief Process a node's action history from the CIB status
1839  *
1840  * Given a node's resource history, if the resource's configuration changed
1841  * since the actions were done, schedule any actions needed (restart,
1842  * reload, unfencing, rescheduling recurring actions, clean-up, etc.).
1843  * (This also cancels recurring actions for maintenance mode, which is not
1844  * entirely related but convenient to do here.)
1845  *
1846  * \param[in,out] node      Node whose history is being processed
1847  * \param[in]     lrm_rscs  Node's <lrm_resources> from CIB status XML
1848  */
1849 static void
1850 process_node_history(pe_node_t *node, const xmlNode *lrm_rscs)
     /* [previous][next][first][last][top][bottom][index][help] */
1851 {
1852     crm_trace("Processing node history for %s", pe__node_name(node));
1853     for (const xmlNode *rsc_entry = first_named_child(lrm_rscs,
1854                                                       XML_LRM_TAG_RESOURCE);
1855          rsc_entry != NULL; rsc_entry = crm_next_same_xml(rsc_entry)) {
1856 
1857         if (xml_has_children(rsc_entry)) {
1858             GList *result = pcmk__rscs_matching_id(ID(rsc_entry),
1859                                                    node->details->data_set);
1860 
1861             for (GList *iter = result; iter != NULL; iter = iter->next) {
1862                 pe_resource_t *rsc = (pe_resource_t *) iter->data;
1863 
1864                 if (rsc->variant == pe_native) {
1865                     process_rsc_history(rsc_entry, rsc, node);
1866                 }
1867             }
1868             g_list_free(result);
1869         }
1870     }
1871 }
1872 
1873 // XPath to find a node's resource history
1874 #define XPATH_NODE_HISTORY "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS             \
1875                            "/" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']" \
1876                            "/" XML_CIB_TAG_LRM "/" XML_LRM_TAG_RESOURCES
1877 
1878 /*!
1879  * \internal
1880  * \brief Process any resource configuration changes in the CIB status
1881  *
1882  * Go through all nodes' resource history, and if a resource's configuration
1883  * changed since its actions were done, schedule any actions needed (restart,
1884  * reload, unfencing, rescheduling recurring actions, clean-up, etc.).
1885  * (This also cancels recurring actions for maintenance mode, which is not
1886  * entirely related but convenient to do here.)
1887  *
1888  * \param[in,out] data_set  Cluster working set
1889  */
1890 void
1891 pcmk__handle_rsc_config_changes(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1892 {
1893     crm_trace("Check resource and action configuration for changes");
1894 
1895     /* Rather than iterate through the status section, iterate through the nodes
1896      * and search for the appropriate status subsection for each. This skips
1897      * orphaned nodes and lets us eliminate some cases before searching the XML.
1898      */
1899     for (GList *iter = data_set->nodes; iter != NULL; iter = iter->next) {
1900         pe_node_t *node = (pe_node_t *) iter->data;
1901 
1902         /* Don't bother checking actions for a node that can't run actions ...
1903          * unless it's in maintenance mode, in which case we still need to
1904          * cancel any existing recurring monitors.
1905          */
1906         if (node->details->maintenance
1907             || pcmk__node_available(node, false, false)) {
1908 
1909             char *xpath = NULL;
1910             xmlNode *history = NULL;
1911 
1912             xpath = crm_strdup_printf(XPATH_NODE_HISTORY, node->details->uname);
1913             history = get_xpath_object(xpath, data_set->input, LOG_NEVER);
1914             free(xpath);
1915 
1916             process_node_history(node, history);
1917         }
1918     }
1919 }

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