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

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