pacemaker  2.1.8-3980678f03
Scalable High-Availability cluster resource manager
pcmk_sched_actions.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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>
18 #include <pacemaker-internal.h>
19 #include "libpacemaker_private.h"
20 
31 static uint32_t
32 action_flags_for_ordering(pcmk_action_t *action, const pcmk_node_t *node)
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) || !pcmk__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  */
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)) {
70  }
71  return flags;
72 }
73 
92 static char *
93 action_uuid_for_ordering(const char *first_uuid,
94  const pcmk_resource_t *first_rsc)
95 {
96  guint interval_ms = 0;
97  char *uuid = NULL;
98  char *rid = NULL;
99  char *first_task_str = NULL;
100  enum action_tasks first_task = pcmk_action_unspecified;
101  enum action_tasks remapped_task = pcmk_action_unspecified;
102 
103  // Only non-notify actions for collective resources need remapping
104  if ((strstr(first_uuid, PCMK_ACTION_NOTIFY) != NULL)
105  || (first_rsc->variant < pcmk_rsc_variant_group)) {
106  goto done;
107  }
108 
109  // Only non-recurring actions need remapping
110  CRM_ASSERT(parse_op_key(first_uuid, &rid, &first_task_str, &interval_ms));
111  if (interval_ms > 0) {
112  goto done;
113  }
114 
115  first_task = pcmk_parse_action(first_task_str);
116  switch (first_task) {
117  case pcmk_action_stop:
118  case pcmk_action_start:
119  case pcmk_action_notify:
120  case pcmk_action_promote:
121  case pcmk_action_demote:
122  remapped_task = first_task + 1;
123  break;
124  case pcmk_action_stopped:
125  case pcmk_action_started:
128  case pcmk_action_demoted:
129  remapped_task = first_task;
130  break;
131  case pcmk_action_monitor:
133  case pcmk_action_fence:
134  break;
135  default:
136  crm_err("Unknown action '%s' in ordering", first_task_str);
137  break;
138  }
139 
140  if (remapped_task != pcmk_action_unspecified) {
141  /* If a clone or bundle has notifications enabled, the ordering will be
142  * relative to when notifications have been sent for the remapped task.
143  */
144  if (pcmk_is_set(first_rsc->flags, pcmk_rsc_notify)
145  && (pcmk__is_clone(first_rsc) || pcmk__is_bundled(first_rsc))) {
146  uuid = pcmk__notify_key(rid, "confirmed-post",
147  pcmk_action_text(remapped_task));
148  } else {
149  uuid = pcmk__op_key(rid, pcmk_action_text(remapped_task), 0);
150  }
151  pcmk__rsc_trace(first_rsc,
152  "Remapped action UUID %s to %s for ordering purposes",
153  first_uuid, uuid);
154  }
155 
156 done:
157  free(first_task_str);
158  free(rid);
159  return (uuid != NULL)? uuid : pcmk__str_copy(first_uuid);
160 }
161 
178 static pcmk_action_t *
179 action_for_ordering(pcmk_action_t *action)
180 {
182  pcmk_resource_t *rsc = action->rsc;
183 
184  if ((rsc != NULL) && (rsc->variant >= pcmk_rsc_variant_group)
185  && (action->uuid != NULL)) {
186  char *uuid = action_uuid_for_ordering(action->uuid, rsc);
187 
188  result = find_first_action(rsc->actions, uuid, NULL, NULL);
189  if (result == NULL) {
190  crm_warn("Not remapping %s to %s because %s does not have "
191  "remapped action", action->uuid, uuid, rsc->id);
192  result = action;
193  }
194  free(uuid);
195  }
196  return result;
197 }
198 
218 static inline uint32_t
219 update(pcmk_resource_t *rsc, pcmk_action_t *first, pcmk_action_t *then,
220  const pcmk_node_t *node, uint32_t flags, uint32_t filter, uint32_t type,
222 {
223  return rsc->cmds->update_ordered_actions(first, then, node, flags, filter,
224  type, scheduler);
225 }
226 
240 static uint32_t
241 update_action_for_ordering_flags(pcmk_action_t *first, pcmk_action_t *then,
242  uint32_t first_flags, uint32_t then_flags,
243  pcmk__related_action_t *order,
245 {
246  uint32_t changed = pcmk__updated_none;
247 
248  /* The node will only be used for clones. If interleaved, node will be NULL,
249  * otherwise the ordering scope will be limited to the node. Normally, the
250  * whole 'then' clone should restart if 'first' is restarted, so then->node
251  * is needed.
252  */
253  pcmk_node_t *node = then->node;
254 
256  /* For unfencing, only instances of 'then' on the same node as 'first'
257  * (the unfencing operation) should restart, so reset node to
258  * first->node, at which point this case is handled like a normal
259  * pcmk__ar_first_implies_then.
260  */
264  node = first->node;
265  pcmk__rsc_trace(then->rsc,
266  "%s then %s: mapped "
267  "pcmk__ar_first_implies_same_node_then to "
268  "pcmk__ar_first_implies_then on %s",
269  first->uuid, then->uuid, pcmk__node_name(node));
270  }
271 
273  if (then->rsc != NULL) {
274  changed |= update(then->rsc, first, then, node,
275  first_flags & pcmk_action_optional,
277  scheduler);
278  } else if (!pcmk_is_set(first_flags, pcmk_action_optional)
282  }
283  pcmk__rsc_trace(then->rsc,
284  "%s then %s: %s after pcmk__ar_first_implies_then",
285  first->uuid, then->uuid,
286  (changed? "changed" : "unchanged"));
287  }
288 
290  && (then->rsc != NULL)) {
293 
294  changed |= update(then->rsc, first, then, node, first_flags, restart,
296  pcmk__rsc_trace(then->rsc,
297  "%s then %s: %s after pcmk__ar_intermediate_stop",
298  first->uuid, then->uuid,
299  (changed? "changed" : "unchanged"));
300  }
301 
303  if (first->rsc != NULL) {
304  changed |= update(first->rsc, first, then, node, first_flags,
306  scheduler);
307  } else if (!pcmk_is_set(first_flags, pcmk_action_optional)
308  && pcmk_is_set(first->flags, pcmk_action_runnable)) {
311  }
312  pcmk__rsc_trace(then->rsc,
313  "%s then %s: %s after pcmk__ar_then_implies_first",
314  first->uuid, then->uuid,
315  (changed? "changed" : "unchanged"));
316  }
317 
319  if (then->rsc != NULL) {
320  changed |= update(then->rsc, first, then, node,
321  first_flags & pcmk_action_optional,
324  }
325  pcmk__rsc_trace(then->rsc,
326  "%s then %s: %s after "
327  "pcmk__ar_promoted_then_implies_first",
328  first->uuid, then->uuid,
329  (changed? "changed" : "unchanged"));
330  }
331 
332  if (pcmk_is_set(order->type, pcmk__ar_min_runnable)) {
333  if (then->rsc != NULL) {
334  changed |= update(then->rsc, first, then, node, first_flags,
336  scheduler);
337 
338  } else if (pcmk_is_set(first_flags, pcmk_action_runnable)) {
339  // We have another runnable instance of "first"
340  then->runnable_before++;
341 
342  /* Mark "then" as runnable if it requires a certain number of
343  * "before" instances to be runnable, and they now are.
344  */
345  if ((then->runnable_before >= then->required_runnable_before)
346  && !pcmk_is_set(then->flags, pcmk_action_runnable)) {
347 
350  }
351  }
352  pcmk__rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_min_runnable",
353  first->uuid, then->uuid,
354  (changed? "changed" : "unchanged"));
355  }
356 
358  && (then->rsc != NULL)) {
359 
360  if (!pcmk_is_set(first_flags, pcmk_action_runnable)
361  && (first->rsc != NULL) && (first->rsc->running_on != NULL)) {
362 
363  pcmk__rsc_trace(then->rsc,
364  "%s then %s: ignoring because first is stopping",
365  first->uuid, then->uuid);
366  order->type = (enum pe_ordering) pcmk__ar_none;
367  } else {
368  changed |= update(then->rsc, first, then, node, first_flags,
371  }
372  pcmk__rsc_trace(then->rsc,
373  "%s then %s: %s after pcmk__ar_nested_remote_probe",
374  first->uuid, then->uuid,
375  (changed? "changed" : "unchanged"));
376  }
377 
379  if (then->rsc != NULL) {
380  changed |= update(then->rsc, first, then, node, first_flags,
383 
384  } else if (!pcmk_is_set(first_flags, pcmk_action_runnable)
386 
389  }
390  pcmk__rsc_trace(then->rsc,
391  "%s then %s: %s after pcmk__ar_unrunnable_first_blocks",
392  first->uuid, then->uuid,
393  (changed? "changed" : "unchanged"));
394  }
395 
397  if (then->rsc != NULL) {
398  changed |= update(then->rsc, first, then, node, first_flags,
401  }
402  pcmk__rsc_trace(then->rsc,
403  "%s then %s: %s after "
404  "pcmk__ar_unmigratable_then_blocks",
405  first->uuid, then->uuid,
406  (changed? "changed" : "unchanged"));
407  }
408 
410  if (then->rsc != NULL) {
411  changed |= update(then->rsc, first, then, node, first_flags,
413  scheduler);
414  }
415  pcmk__rsc_trace(then->rsc,
416  "%s then %s: %s after pcmk__ar_first_else_then",
417  first->uuid, then->uuid,
418  (changed? "changed" : "unchanged"));
419  }
420 
421  if (pcmk_is_set(order->type, pcmk__ar_ordered)) {
422  if (then->rsc != NULL) {
423  changed |= update(then->rsc, first, then, node, first_flags,
425  scheduler);
426  }
427  pcmk__rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_ordered",
428  first->uuid, then->uuid,
429  (changed? "changed" : "unchanged"));
430  }
431 
432  if (pcmk_is_set(order->type, pcmk__ar_asymmetric)) {
433  if (then->rsc != NULL) {
434  changed |= update(then->rsc, first, then, node, first_flags,
436  scheduler);
437  }
438  pcmk__rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_asymmetric",
439  first->uuid, then->uuid,
440  (changed? "changed" : "unchanged"));
441  }
442 
445  && !pcmk_is_set(first_flags, pcmk_action_optional)) {
446 
447  pcmk__rsc_trace(then->rsc, "%s will be in graph because %s is required",
448  then->uuid, first->uuid);
450  // Don't bother marking 'then' as changed just for this
451  }
452 
454  && !pcmk_is_set(then_flags, pcmk_action_optional)) {
455 
456  pcmk__rsc_trace(then->rsc, "%s will be in graph because %s is required",
457  first->uuid, then->uuid);
459  // Don't bother marking 'first' as changed just for this
460  }
461 
462  if (pcmk_any_flags_set(order->type, pcmk__ar_first_implies_then
465  && (first->rsc != NULL)
466  && !pcmk_is_set(first->rsc->flags, pcmk_rsc_managed)
469  && pcmk__str_eq(first->task, PCMK_ACTION_STOP, pcmk__str_none)) {
470 
471  if (pcmk_is_set(then->flags, pcmk_action_runnable)) {
474  }
475  pcmk__rsc_trace(then->rsc,
476  "%s then %s: %s after checking whether first "
477  "is blocked, unmanaged, unrunnable stop",
478  first->uuid, then->uuid,
479  (changed? "changed" : "unchanged"));
480  }
481 
482  return changed;
483 }
484 
485 // Convenience macros for logging action properties
486 
487 #define action_type_str(flags) \
488  (pcmk_is_set((flags), pcmk_action_pseudo)? "pseudo-action" : "action")
489 
490 #define action_optional_str(flags) \
491  (pcmk_is_set((flags), pcmk_action_optional)? "optional" : "required")
492 
493 #define action_runnable_str(flags) \
494  (pcmk_is_set((flags), pcmk_action_runnable)? "runnable" : "unrunnable")
495 
496 #define action_node_str(a) \
497  (((a)->node == NULL)? "no node" : (a)->node->details->uname)
498 
506 void
509 {
510  GList *lpc = NULL;
511  uint32_t changed = pcmk__updated_none;
512  int last_flags = then->flags;
513 
514  pcmk__rsc_trace(then->rsc, "Updating %s %s (%s %s) on %s",
515  action_type_str(then->flags), then->uuid,
516  action_optional_str(then->flags),
518 
520  /* Initialize current known "runnable before" actions. As
521  * update_action_for_ordering_flags() is called for each of then's
522  * before actions, this number will increment as runnable 'first'
523  * actions are encountered.
524  */
525  then->runnable_before = 0;
526 
527  if (then->required_runnable_before == 0) {
528  /* @COMPAT This ordering constraint uses the deprecated
529  * PCMK_XA_REQUIRE_ALL=PCMK_VALUE_FALSE attribute. Treat it like
530  * PCMK_META_CLONE_MIN=1.
531  */
532  then->required_runnable_before = 1;
533  }
534 
535  /* The pcmk__ar_min_runnable clause of
536  * update_action_for_ordering_flags() (called below)
537  * will reset runnable if appropriate.
538  */
540  }
541 
542  for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
543  pcmk__related_action_t *other = lpc->data;
544  pcmk_action_t *first = other->action;
545 
546  pcmk_node_t *then_node = then->node;
547  pcmk_node_t *first_node = first->node;
548 
549  if ((first->rsc != NULL)
550  && pcmk__is_group(first->rsc)
551  && pcmk__str_eq(first->task, PCMK_ACTION_START, pcmk__str_none)) {
552 
553  first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
554  if (first_node != NULL) {
555  pcmk__rsc_trace(first->rsc, "Found %s for 'first' %s",
556  pcmk__node_name(first_node), first->uuid);
557  }
558  }
559 
560  if (pcmk__is_group(then->rsc)
561  && pcmk__str_eq(then->task, PCMK_ACTION_START, pcmk__str_none)) {
562 
563  then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
564  if (then_node != NULL) {
565  pcmk__rsc_trace(then->rsc, "Found %s for 'then' %s",
566  pcmk__node_name(then_node), then->uuid);
567  }
568  }
569 
570  // Disable constraint if it only applies when on same node, but isn't
572  && (first_node != NULL) && (then_node != NULL)
573  && !pcmk__same_node(first_node, then_node)) {
574 
575  pcmk__rsc_trace(then->rsc,
576  "Disabled ordering %s on %s then %s on %s: "
577  "not same node",
578  other->action->uuid, pcmk__node_name(first_node),
579  then->uuid, pcmk__node_name(then_node));
580  other->type = (enum pe_ordering) pcmk__ar_none;
581  continue;
582  }
583 
585 
586  if ((first->rsc != NULL)
588  && !pcmk_is_set(then->flags, pcmk_action_optional)) {
589 
590  /* 'then' is required, so we must abandon 'first'
591  * (e.g. a required stop cancels any agent reload).
592  */
594  if (!strcmp(first->task, PCMK_ACTION_RELOAD_AGENT)) {
596  }
597  }
598 
599  if ((first->rsc != NULL) && (then->rsc != NULL)
600  && (first->rsc != then->rsc) && !is_parent(then->rsc, first->rsc)) {
601  first = action_for_ordering(first);
602  }
603  if (first != other->action) {
604  pcmk__rsc_trace(then->rsc, "Ordering %s after %s instead of %s",
605  then->uuid, first->uuid, other->action->uuid);
606  }
607 
608  pcmk__rsc_trace(then->rsc,
609  "%s (%#.6x) then %s (%#.6x): type=%#.6x node=%s",
610  first->uuid, first->flags, then->uuid, then->flags,
611  other->type, action_node_str(first));
612 
613  if (first == other->action) {
614  /* 'first' was not remapped (e.g. from 'start' to 'running'), which
615  * could mean it is a non-resource action, a primitive resource
616  * action, or already expanded.
617  */
618  uint32_t first_flags, then_flags;
619 
620  first_flags = action_flags_for_ordering(first, then_node);
621  then_flags = action_flags_for_ordering(then, first_node);
622 
623  changed |= update_action_for_ordering_flags(first, then,
624  first_flags, then_flags,
625  other, scheduler);
626 
627  /* 'first' was for a complex resource (clone, group, etc),
628  * create a new dependency if necessary
629  */
630  } else if (order_actions(first, then, other->type)) {
631  /* This was the first time 'first' and 'then' were associated,
632  * start again to get the new actions_before list
633  */
635  pcmk__rsc_trace(then->rsc,
636  "Disabled ordering %s then %s in favor of %s "
637  "then %s",
638  other->action->uuid, then->uuid, first->uuid,
639  then->uuid);
640  other->type = (enum pe_ordering) pcmk__ar_none;
641  }
642 
643 
644  if (pcmk_is_set(changed, pcmk__updated_first)) {
645  crm_trace("Re-processing %s and its 'after' actions "
646  "because it changed", first->uuid);
647  for (GList *lpc2 = first->actions_after; lpc2 != NULL;
648  lpc2 = lpc2->next) {
649  pcmk__related_action_t *other = lpc2->data;
650 
652  }
654  }
655  }
656 
658  if (last_flags == then->flags) {
660  } else {
662  }
663  }
664 
665  if (pcmk_is_set(changed, pcmk__updated_then)) {
666  crm_trace("Re-processing %s and its 'after' actions because it changed",
667  then->uuid);
668  if (pcmk_is_set(last_flags, pcmk_action_runnable)
669  && !pcmk_is_set(then->flags, pcmk_action_runnable)) {
671  }
673  for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
674  pcmk__related_action_t *other = lpc->data;
675 
677  }
678  }
679 }
680 
681 static inline bool
682 is_primitive_action(const pcmk_action_t *action)
683 {
684  return (action != NULL) && pcmk__is_primitive(action->rsc);
685 }
686 
695 #define clear_action_flag_because(action, flag, reason) do { \
696  if (pcmk_is_set((action)->flags, (flag))) { \
697  pcmk__clear_action_flags(action, flag); \
698  if ((action)->rsc != (reason)->rsc) { \
699  char *reason_text = pe__action2reason((reason), (flag)); \
700  pe_action_set_reason((action), reason_text, false); \
701  free(reason_text); \
702  } \
703  } \
704  } while (0)
705 
716 static void
717 handle_asymmetric_ordering(const pcmk_action_t *first, pcmk_action_t *then)
718 {
719  /* Only resource actions after an unrunnable 'first' action need updates for
720  * asymmetric ordering.
721  */
722  if ((then->rsc == NULL)
723  || pcmk_is_set(first->flags, pcmk_action_runnable)) {
724  return;
725  }
726 
727  // Certain optional 'then' actions are unaffected by unrunnable 'first'
728  if (pcmk_is_set(then->flags, pcmk_action_optional)) {
729  enum rsc_role_e then_rsc_role = then->rsc->fns->state(then->rsc, TRUE);
730 
731  if ((then_rsc_role == pcmk_role_stopped)
732  && pcmk__str_eq(then->task, PCMK_ACTION_STOP, pcmk__str_none)) {
733  /* If 'then' should stop after 'first' but is already stopped, the
734  * ordering is irrelevant.
735  */
736  return;
737  } else if ((then_rsc_role >= pcmk_role_started)
738  && pcmk__str_eq(then->task, PCMK_ACTION_START, pcmk__str_none)
739  && pe__rsc_running_on_only(then->rsc, then->node)) {
740  /* Similarly if 'then' should start after 'first' but is already
741  * started on a single node.
742  */
743  return;
744  }
745  }
746 
747  // 'First' can't run, so 'then' can't either
750 }
751 
763 static void
764 handle_restart_ordering(pcmk_action_t *first, pcmk_action_t *then,
765  uint32_t filter)
766 {
767  const char *reason = NULL;
768 
769  CRM_ASSERT(is_primitive_action(first));
770  CRM_ASSERT(is_primitive_action(then));
771 
772  // We need to update the action in two cases:
773 
774  // ... if 'then' is required
775  if (pcmk_is_set(filter, pcmk_action_optional)
776  && !pcmk_is_set(then->flags, pcmk_action_optional)) {
777  reason = "restart";
778  }
779 
780  /* ... if 'then' is unrunnable action on same resource (if a resource
781  * should restart but can't start, we still want to stop)
782  */
783  if (pcmk_is_set(filter, pcmk_action_runnable)
786  && (first->rsc == then->rsc)) {
787  reason = "stop";
788  }
789 
790  if (reason == NULL) {
791  return;
792  }
793 
794  pcmk__rsc_trace(first->rsc, "Handling %s -> %s for %s",
795  first->uuid, then->uuid, reason);
796 
797  // Make 'first' required if it is runnable
798  if (pcmk_is_set(first->flags, pcmk_action_runnable)) {
800  }
801 
802  // Make 'first' required if 'then' is required
803  if (!pcmk_is_set(then->flags, pcmk_action_optional)) {
805  }
806 
807  // Make 'first' unmigratable if 'then' is unmigratable
810  }
811 
812  // Make 'then' unrunnable if 'first' is required but unrunnable
814  && !pcmk_is_set(first->flags, pcmk_action_runnable)) {
816  }
817 }
818 
841 uint32_t
843  const pcmk_node_t *node, uint32_t flags,
844  uint32_t filter, uint32_t type,
846 {
847  uint32_t changed = pcmk__updated_none;
848  uint32_t then_flags = 0U;
849  uint32_t first_flags = 0U;
850 
851  CRM_ASSERT((first != NULL) && (then != NULL) && (scheduler != NULL));
852 
853  then_flags = then->flags;
854  first_flags = first->flags;
856  handle_asymmetric_ordering(first, then);
857  }
858 
860  && !pcmk_is_set(then_flags, pcmk_action_optional)) {
861  // Then is required, and implies first should be, too
862 
863  if (pcmk_is_set(filter, pcmk_action_optional)
865  && pcmk_is_set(first_flags, pcmk_action_optional)) {
867  }
868 
872  }
873  }
874 
876  && (then->rsc != NULL) && (then->rsc->role == pcmk_role_promoted)
878  && !pcmk_is_set(then->flags, pcmk_action_optional)) {
879 
881 
885  }
886  }
887 
889  && pcmk_is_set(filter, pcmk_action_optional)) {
890 
891  if (!pcmk_all_flags_set(then->flags, pcmk_action_migratable
894  }
895 
896  if (!pcmk_is_set(then->flags, pcmk_action_optional)) {
898  }
899  }
900 
903  && !pcmk_is_set(first->flags, pcmk_action_runnable)) {
904 
907  }
908 
913 
916  }
917 
923 
925  }
926 
928  handle_restart_ordering(first, then, filter);
929  }
930 
931  if (then_flags != then->flags) {
933  pcmk__rsc_trace(then->rsc,
934  "%s on %s: flags are now %#.6x (was %#.6x) "
935  "because of 'first' %s (%#.6x)",
936  then->uuid, pcmk__node_name(then->node),
937  then->flags, then_flags, first->uuid, first->flags);
938 
939  if ((then->rsc != NULL) && (then->rsc->parent != NULL)) {
940  // Required to handle "X_stop then X_start" for cloned groups
942  }
943  }
944 
945  if (first_flags != first->flags) {
947  pcmk__rsc_trace(first->rsc,
948  "%s on %s: flags are now %#.6x (was %#.6x) "
949  "because of 'then' %s (%#.6x)",
950  first->uuid, pcmk__node_name(first->node),
951  first->flags, first_flags, then->uuid, then->flags);
952  }
953 
954  return changed;
955 }
956 
965 void
966 pcmk__log_action(const char *pre_text, const pcmk_action_t *action,
967  bool details)
968 {
969  const char *node_uname = NULL;
970  const char *node_uuid = NULL;
971  const char *desc = NULL;
972 
973  CRM_CHECK(action != NULL, return);
974 
975  if (!pcmk_is_set(action->flags, pcmk_action_pseudo)) {
976  if (action->node != NULL) {
977  node_uname = action->node->details->uname;
978  node_uuid = action->node->details->id;
979  } else {
980  node_uname = "<none>";
981  }
982  }
983 
984  switch (pcmk_parse_action(action->task)) {
985  case pcmk_action_fence:
987  if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
988  desc = "Pseudo ";
989  } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
990  desc = "Optional ";
991  } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
992  desc = "!!Non-Startable!! ";
993  } else {
994  desc = "(Provisional) ";
995  }
996  crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
997  ((pre_text == NULL)? "" : pre_text),
998  ((pre_text == NULL)? "" : ": "),
999  desc, action->id, action->uuid,
1000  (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1001  (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1002  (node_uuid? ")" : ""));
1003  break;
1004  default:
1005  if (pcmk_is_set(action->flags, pcmk_action_optional)) {
1006  desc = "Optional ";
1007  } else if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
1008  desc = "Pseudo ";
1009  } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
1010  desc = "!!Non-Startable!! ";
1011  } else {
1012  desc = "(Provisional) ";
1013  }
1014  crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
1015  ((pre_text == NULL)? "" : pre_text),
1016  ((pre_text == NULL)? "" : ": "),
1017  desc, action->id, action->uuid,
1018  (action->rsc? action->rsc->id : "<none>"),
1019  (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1020  (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1021  (node_uuid? ")" : ""));
1022  break;
1023  }
1024 
1025  if (details) {
1026  const GList *iter = NULL;
1027  const pcmk__related_action_t *other = NULL;
1028 
1029  crm_trace("\t\t====== Preceding Actions");
1030  for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1031  other = (const pcmk__related_action_t *) iter->data;
1032  pcmk__log_action("\t\t", other->action, false);
1033  }
1034  crm_trace("\t\t====== Subsequent Actions");
1035  for (iter = action->actions_after; iter != NULL; iter = iter->next) {
1036  other = (const pcmk__related_action_t *) iter->data;
1037  pcmk__log_action("\t\t", other->action, false);
1038  }
1039  crm_trace("\t\t====== End");
1040 
1041  } else {
1042  crm_trace("\t\t(before=%d, after=%d)",
1043  g_list_length(action->actions_before),
1044  g_list_length(action->actions_after));
1045  }
1046 }
1047 
1056 pcmk_action_t *
1058 {
1059  char *shutdown_id = NULL;
1060  pcmk_action_t *shutdown_op = NULL;
1061 
1062  CRM_ASSERT(node != NULL);
1063 
1064  shutdown_id = crm_strdup_printf("%s-%s", PCMK_ACTION_DO_SHUTDOWN,
1065  node->details->uname);
1066 
1067  shutdown_op = custom_action(NULL, shutdown_id, PCMK_ACTION_DO_SHUTDOWN,
1068  node, FALSE, node->details->data_set);
1069 
1070  pcmk__order_stops_before_shutdown(node, shutdown_op);
1072  return shutdown_op;
1073 }
1074 
1086 static void
1087 add_op_digest_to_xml(const lrmd_event_data_t *op, xmlNode *update)
1088 {
1089  char *digest = NULL;
1090  xmlNode *args_xml = NULL;
1091 
1092  if (op->params == NULL) {
1093  return;
1094  }
1095  args_xml = pcmk__xe_create(NULL, PCMK_XE_PARAMETERS);
1096  g_hash_table_foreach(op->params, hash2field, args_xml);
1097  pcmk__filter_op_for_digest(args_xml);
1098  digest = calculate_operation_digest(args_xml, NULL);
1099  crm_xml_add(update, PCMK__XA_OP_DIGEST, digest);
1100  free_xml(args_xml);
1101  free(digest);
1102 }
1103 
1104 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1105 
1119 xmlNode *
1121  const char *caller_version, int target_rc,
1122  const char *node, const char *origin)
1123 {
1124  char *key = NULL;
1125  char *magic = NULL;
1126  char *op_id = NULL;
1127  char *op_id_additional = NULL;
1128  char *local_user_data = NULL;
1129  const char *exit_reason = NULL;
1130 
1131  xmlNode *xml_op = NULL;
1132  const char *task = NULL;
1133 
1134  CRM_CHECK(op != NULL, return NULL);
1135  crm_trace("Creating history XML for %s-interval %s action for %s on %s "
1136  "(DC version: %s, origin: %s)",
1138  ((node == NULL)? "no node" : node), caller_version, origin);
1139 
1140  task = op->op_type;
1141 
1142  /* Record a successful agent reload as a start, and a failed one as a
1143  * monitor, to make life easier for the scheduler when determining the
1144  * current state.
1145  *
1146  * @COMPAT We should check "reload" here only if the operation was for a
1147  * pre-OCF-1.1 resource agent, but we don't know that here, and we should
1148  * only ever get results for actions scheduled by us, so we can reasonably
1149  * assume any "reload" is actually a pre-1.1 agent reload.
1150  */
1152  NULL)) {
1153  if (op->op_status == PCMK_EXEC_DONE) {
1154  task = PCMK_ACTION_START;
1155  } else {
1156  task = PCMK_ACTION_MONITOR;
1157  }
1158  }
1159 
1160  key = pcmk__op_key(op->rsc_id, task, op->interval_ms);
1161  if (pcmk__str_eq(task, PCMK_ACTION_NOTIFY, pcmk__str_none)) {
1162  const char *n_type = crm_meta_value(op->params, "notify_type");
1163  const char *n_task = crm_meta_value(op->params, "notify_operation");
1164 
1165  CRM_LOG_ASSERT(n_type != NULL);
1166  CRM_LOG_ASSERT(n_task != NULL);
1167  op_id = pcmk__notify_key(op->rsc_id, n_type, n_task);
1168 
1169  if (op->op_status != PCMK_EXEC_PENDING) {
1170  /* Ignore notify errors.
1171  *
1172  * @TODO It might be better to keep the correct result here, and
1173  * ignore it in process_graph_event().
1174  */
1176  }
1177 
1178  /* Migration history is preserved separately, which usually matters for
1179  * multiple nodes and is important for future cluster transitions.
1180  */
1182  PCMK_ACTION_MIGRATE_FROM, NULL)) {
1183  op_id = strdup(key);
1184 
1185  } else if (did_rsc_op_fail(op, target_rc)) {
1186  op_id = pcmk__op_key(op->rsc_id, "last_failure", 0);
1187  if (op->interval_ms == 0) {
1188  /* Ensure 'last' gets updated, in case PCMK_META_RECORD_PENDING is
1189  * true
1190  */
1191  op_id_additional = pcmk__op_key(op->rsc_id, "last", 0);
1192  }
1193  exit_reason = op->exit_reason;
1194 
1195  } else if (op->interval_ms > 0) {
1196  op_id = strdup(key);
1197 
1198  } else {
1199  op_id = pcmk__op_key(op->rsc_id, "last", 0);
1200  }
1201 
1202  again:
1204  op_id);
1205  if (xml_op == NULL) {
1207  }
1208 
1209  if (op->user_data == NULL) {
1210  crm_debug("Generating fake transition key for: " PCMK__OP_FMT
1211  " %d from %s", op->rsc_id, op->op_type, op->interval_ms,
1212  op->call_id, origin);
1213  local_user_data = pcmk__transition_key(-1, op->call_id, target_rc,
1214  FAKE_TE_ID);
1215  op->user_data = local_user_data;
1216  }
1217 
1218  if (magic == NULL) {
1219  magic = crm_strdup_printf("%d:%d;%s", op->op_status, op->rc,
1220  (const char *) op->user_data);
1221  }
1222 
1223  crm_xml_add(xml_op, PCMK_XA_ID, op_id);
1224  crm_xml_add(xml_op, PCMK__XA_OPERATION_KEY, key);
1225  crm_xml_add(xml_op, PCMK_XA_OPERATION, task);
1226  crm_xml_add(xml_op, PCMK_XA_CRM_DEBUG_ORIGIN, origin);
1227  crm_xml_add(xml_op, PCMK_XA_CRM_FEATURE_SET, caller_version);
1229  crm_xml_add(xml_op, PCMK__XA_TRANSITION_MAGIC, magic);
1230  crm_xml_add(xml_op, PCMK_XA_EXIT_REASON, pcmk__s(exit_reason, ""));
1231  crm_xml_add(xml_op, PCMK__META_ON_NODE, node); // For context during triage
1232 
1234  crm_xml_add_int(xml_op, PCMK__XA_RC_CODE, op->rc);
1237 
1238  if (compare_version("2.1", caller_version) <= 0) {
1239  if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1240  crm_trace("Timing data (" PCMK__OP_FMT
1241  "): last=%u change=%u exec=%u queue=%u",
1242  op->rsc_id, op->op_type, op->interval_ms,
1243  op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1244 
1245  if ((op->interval_ms != 0) && (op->t_rcchange != 0)) {
1246  // Recurring ops may have changed rc after initial run
1248  (long long) op->t_rcchange);
1249  } else {
1251  (long long) op->t_run);
1252  }
1253 
1256  }
1257  }
1258 
1260  PCMK_ACTION_MIGRATE_FROM, NULL)) {
1261  /* Record PCMK__META_MIGRATE_SOURCE and PCMK__META_MIGRATE_TARGET always
1262  * for migrate ops.
1263  */
1264  const char *name = PCMK__META_MIGRATE_SOURCE;
1265 
1266  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1267 
1269  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1270  }
1271 
1272  add_op_digest_to_xml(op, xml_op);
1273 
1274  if (op_id_additional) {
1275  free(op_id);
1276  op_id = op_id_additional;
1277  op_id_additional = NULL;
1278  goto again;
1279  }
1280 
1281  if (local_user_data) {
1282  free(local_user_data);
1283  op->user_data = NULL;
1284  }
1285  free(magic);
1286  free(op_id);
1287  free(key);
1288  return xml_op;
1289 }
1290 
1305 bool
1307 {
1308  // Only resource actions taking place on resource's lock node are locked
1309  if ((action == NULL) || (action->rsc == NULL)
1310  || !pcmk__same_node(action->node, action->rsc->lock_node)) {
1311  return false;
1312  }
1313 
1314  /* During shutdown, only stops are locked (otherwise, another action such as
1315  * a demote would cause the controller to clear the lock)
1316  */
1317  if (action->node->details->shutdown && (action->task != NULL)
1318  && (strcmp(action->task, PCMK_ACTION_STOP) != 0)) {
1319  return false;
1320  }
1321 
1322  return true;
1323 }
1324 
1325 /* lowest to highest */
1326 static gint
1327 sort_action_id(gconstpointer a, gconstpointer b)
1328 {
1329  const pcmk__related_action_t *action_wrapper2 = a;
1330  const pcmk__related_action_t *action_wrapper1 = b;
1331 
1332  if (a == NULL) {
1333  return 1;
1334  }
1335  if (b == NULL) {
1336  return -1;
1337  }
1338  if (action_wrapper1->action->id < action_wrapper2->action->id) {
1339  return 1;
1340  }
1341  if (action_wrapper1->action->id > action_wrapper2->action->id) {
1342  return -1;
1343  }
1344  return 0;
1345 }
1346 
1353 void
1355 {
1356  GList *item = NULL;
1357  GList *next = NULL;
1358  pcmk__related_action_t *last_input = NULL;
1359 
1360  action->actions_before = g_list_sort(action->actions_before,
1361  sort_action_id);
1362  for (item = action->actions_before; item != NULL; item = next) {
1363  pcmk__related_action_t *input = item->data;
1364 
1365  next = item->next;
1366  if ((last_input != NULL)
1367  && (input->action->id == last_input->action->id)) {
1368  crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1369  input->action->uuid, input->action->id,
1370  action->uuid, action->id);
1371 
1372  /* For the purposes of scheduling, the ordering flags no longer
1373  * matter, but crm_simulate looks at certain ones when creating a
1374  * dot graph. Combining the flags is sufficient for that purpose.
1375  */
1376  last_input->type |= input->type;
1377  if (input->state == pe_link_dumped) {
1378  last_input->state = pe_link_dumped;
1379  }
1380 
1381  free(item->data);
1382  action->actions_before = g_list_delete_link(action->actions_before,
1383  item);
1384  } else {
1385  last_input = input;
1386  input->state = pe_link_not_dumped;
1387  }
1388  }
1389 }
1390 
1397 void
1399 {
1400  pcmk__output_t *out = scheduler->priv;
1401 
1402  // Output node (non-resource) actions
1403  for (GList *iter = scheduler->actions; iter != NULL; iter = iter->next) {
1404  char *node_name = NULL;
1405  char *task = NULL;
1406  pcmk_action_t *action = (pcmk_action_t *) iter->data;
1407 
1408  if (action->rsc != NULL) {
1409  continue; // Resource actions will be output later
1410 
1411  } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
1412  continue; // This action was not scheduled
1413  }
1414 
1415  if (pcmk__str_eq(action->task, PCMK_ACTION_DO_SHUTDOWN,
1416  pcmk__str_none)) {
1417  task = strdup("Shutdown");
1418 
1419  } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH,
1420  pcmk__str_none)) {
1421  const char *op = g_hash_table_lookup(action->meta,
1423 
1424  task = crm_strdup_printf("Fence (%s)", op);
1425 
1426  } else {
1427  continue; // Don't display other node action types
1428  }
1429 
1430  if (pcmk__is_guest_or_bundle_node(action->node)) {
1431  const pcmk_resource_t *remote = action->node->details->remote_rsc;
1432 
1433  node_name = crm_strdup_printf("%s (resource: %s)",
1434  pcmk__node_name(action->node),
1435  remote->container->id);
1436  } else if (action->node != NULL) {
1437  node_name = crm_strdup_printf("%s", pcmk__node_name(action->node));
1438  }
1439 
1440  out->message(out, "node-action", task, node_name, action->reason);
1441 
1442  free(node_name);
1443  free(task);
1444  }
1445 
1446  // Output resource actions
1447  for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
1448  pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1449 
1450  rsc->cmds->output_actions(rsc);
1451  }
1452 }
1453 
1463 static const char *
1464 task_for_digest(const char *task, guint interval_ms)
1465 {
1466  /* Certain actions need to be compared against the parameters used to start
1467  * the resource.
1468  */
1469  if ((interval_ms == 0)
1471  PCMK_ACTION_PROMOTE, NULL)) {
1472  task = PCMK_ACTION_START;
1473  }
1474  return task;
1475 }
1476 
1494 static bool
1495 only_sanitized_changed(const xmlNode *xml_op,
1496  const pcmk__op_digest_t *digest_data,
1497  const pcmk_scheduler_t *scheduler)
1498 {
1499  const char *digest_secure = NULL;
1500 
1502  // The scheduler is not being run as a simulation
1503  return false;
1504  }
1505 
1506  digest_secure = crm_element_value(xml_op, PCMK__XA_OP_SECURE_DIGEST);
1507 
1508  return (digest_data->rc != pcmk__digest_match) && (digest_secure != NULL)
1509  && (digest_data->digest_secure_calc != NULL)
1510  && (strcmp(digest_data->digest_secure_calc, digest_secure) == 0);
1511 }
1512 
1522 static void
1523 force_restart(pcmk_resource_t *rsc, const char *task, guint interval_ms,
1524  pcmk_node_t *node)
1525 {
1526  char *key = pcmk__op_key(rsc->id, task, interval_ms);
1527  pcmk_action_t *required = custom_action(rsc, key, task, NULL, FALSE,
1528  rsc->cluster);
1529 
1530  pe_action_set_reason(required, "resource definition change", true);
1531  trigger_unfencing(rsc, node, "Device parameters changed", NULL,
1532  rsc->cluster);
1533 }
1534 
1542 static void
1543 schedule_reload(gpointer data, gpointer user_data)
1544 {
1545  pcmk_resource_t *rsc = data;
1546  const pcmk_node_t *node = user_data;
1547  pcmk_action_t *reload = NULL;
1548 
1549  // For collective resources, just call recursively for children
1550  if (rsc->variant > pcmk_rsc_variant_primitive) {
1551  g_list_foreach(rsc->children, schedule_reload, user_data);
1552  return;
1553  }
1554 
1555  // Skip the reload in certain situations
1556  if ((node == NULL)
1558  || pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
1559  pcmk__rsc_trace(rsc, "Skip reload of %s:%s%s %s",
1560  rsc->id,
1561  pcmk_is_set(rsc->flags, pcmk_rsc_managed)? "" : " unmanaged",
1562  pcmk_is_set(rsc->flags, pcmk_rsc_failed)? " failed" : "",
1563  (node == NULL)? "inactive" : node->details->uname);
1564  return;
1565  }
1566 
1567  /* If a resource's configuration changed while a start was pending,
1568  * force a full restart instead of a reload.
1569  */
1571  pcmk__rsc_trace(rsc,
1572  "%s: preventing agent reload because start pending",
1573  rsc->id);
1574  custom_action(rsc, stop_key(rsc), PCMK_ACTION_STOP, node, FALSE,
1575  rsc->cluster);
1576  return;
1577  }
1578 
1579  // Schedule the reload
1581  reload = custom_action(rsc, reload_key(rsc), PCMK_ACTION_RELOAD_AGENT, node,
1582  FALSE, rsc->cluster);
1583  pe_action_set_reason(reload, "resource definition change", FALSE);
1584 
1585  // Set orderings so that a required stop or demote cancels the reload
1586  pcmk__new_ordering(NULL, NULL, reload, rsc, stop_key(rsc), NULL,
1588  rsc->cluster);
1589  pcmk__new_ordering(NULL, NULL, reload, rsc, demote_key(rsc), NULL,
1591  rsc->cluster);
1592 }
1593 
1608 bool
1610  const xmlNode *xml_op)
1611 {
1612  guint interval_ms = 0;
1613  const char *task = NULL;
1614  const pcmk__op_digest_t *digest_data = NULL;
1615 
1616  CRM_CHECK((rsc != NULL) && (node != NULL) && (xml_op != NULL),
1617  return false);
1618 
1619  task = crm_element_value(xml_op, PCMK_XA_OPERATION);
1620  CRM_CHECK(task != NULL, return false);
1621 
1622  crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
1623 
1624  // If this is a recurring action, check whether it has been orphaned
1625  if (interval_ms > 0) {
1626  if (pcmk__find_action_config(rsc, task, interval_ms, false) != NULL) {
1627  pcmk__rsc_trace(rsc,
1628  "%s-interval %s for %s on %s is in configuration",
1629  pcmk__readable_interval(interval_ms), task, rsc->id,
1630  pcmk__node_name(node));
1631  } else if (pcmk_is_set(rsc->cluster->flags,
1635  task, interval_ms, node, "orphan");
1636  return true;
1637  } else {
1638  pcmk__rsc_debug(rsc, "%s-interval %s for %s on %s is orphaned",
1639  pcmk__readable_interval(interval_ms), task, rsc->id,
1640  pcmk__node_name(node));
1641  return true;
1642  }
1643  }
1644 
1645  crm_trace("Checking %s-interval %s for %s on %s for configuration changes",
1646  pcmk__readable_interval(interval_ms), task, rsc->id,
1647  pcmk__node_name(node));
1648  task = task_for_digest(task, interval_ms);
1649  digest_data = rsc_action_digest_cmp(rsc, xml_op, node, rsc->cluster);
1650 
1651  if (only_sanitized_changed(xml_op, digest_data, rsc->cluster)) {
1652  if (!pcmk__is_daemon && (rsc->cluster->priv != NULL)) {
1653  pcmk__output_t *out = rsc->cluster->priv;
1654 
1655  out->info(out,
1656  "Only 'private' parameters to %s-interval %s for %s "
1657  "on %s changed: %s",
1658  pcmk__readable_interval(interval_ms), task, rsc->id,
1659  pcmk__node_name(node),
1661  }
1662  return false;
1663  }
1664 
1665  switch (digest_data->rc) {
1666  case pcmk__digest_restart:
1667  crm_log_xml_debug(digest_data->params_restart, "params:restart");
1668  force_restart(rsc, task, interval_ms, node);
1669  return true;
1670 
1671  case pcmk__digest_unknown:
1672  case pcmk__digest_mismatch:
1673  // Changes that can potentially be handled by an agent reload
1674 
1675  if (interval_ms > 0) {
1676  /* Recurring actions aren't reloaded per se, they are just
1677  * re-scheduled so the next run uses the new parameters.
1678  * The old instance will be cancelled automatically.
1679  */
1680  crm_log_xml_debug(digest_data->params_all, "params:reschedule");
1681  pcmk__reschedule_recurring(rsc, task, interval_ms, node);
1682 
1683  } else if (crm_element_value(xml_op,
1684  PCMK__XA_OP_RESTART_DIGEST) != NULL) {
1685  // Agent supports reload, so use it
1686  trigger_unfencing(rsc, node,
1687  "Device parameters changed (reload)", NULL,
1688  rsc->cluster);
1689  crm_log_xml_debug(digest_data->params_all, "params:reload");
1690  schedule_reload((gpointer) rsc, (gpointer) node);
1691 
1692  } else {
1693  pcmk__rsc_trace(rsc,
1694  "Restarting %s "
1695  "because agent doesn't support reload",
1696  rsc->id);
1697  crm_log_xml_debug(digest_data->params_restart,
1698  "params:restart");
1699  force_restart(rsc, task, interval_ms, node);
1700  }
1701  return true;
1702 
1703  default:
1704  break;
1705  }
1706  return false;
1707 }
1708 
1717 static GList *
1718 rsc_history_as_list(const xmlNode *rsc_entry, int *start_index, int *stop_index)
1719 {
1720  GList *ops = NULL;
1721 
1722  for (xmlNode *rsc_op = pcmk__xe_first_child(rsc_entry, PCMK__XE_LRM_RSC_OP,
1723  NULL, NULL);
1724  rsc_op != NULL; rsc_op = pcmk__xe_next_same(rsc_op)) {
1725 
1726  ops = g_list_prepend(ops, rsc_op);
1727  }
1728  ops = g_list_sort(ops, sort_op_by_callid);
1729  calculate_active_ops(ops, start_index, stop_index);
1730  return ops;
1731 }
1732 
1747 static void
1748 process_rsc_history(const xmlNode *rsc_entry, pcmk_resource_t *rsc,
1749  pcmk_node_t *node)
1750 {
1751  int offset = -1;
1752  int stop_index = 0;
1753  int start_index = 0;
1754  GList *sorted_op_list = NULL;
1755 
1756  if (pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
1757  if (pcmk__is_anonymous_clone(pe__const_top_resource(rsc, false))) {
1758  pcmk__rsc_trace(rsc,
1759  "Skipping configuration check "
1760  "for orphaned clone instance %s",
1761  rsc->id);
1762  } else {
1763  pcmk__rsc_trace(rsc,
1764  "Skipping configuration check and scheduling "
1765  "clean-up for orphaned resource %s", rsc->id);
1766  pcmk__schedule_cleanup(rsc, node, false);
1767  }
1768  return;
1769  }
1770 
1771  if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
1772  if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, false)) {
1773  pcmk__schedule_cleanup(rsc, node, false);
1774  }
1775  pcmk__rsc_trace(rsc,
1776  "Skipping configuration check for %s "
1777  "because no longer active on %s",
1778  rsc->id, pcmk__node_name(node));
1779  return;
1780  }
1781 
1782  pcmk__rsc_trace(rsc, "Checking for configuration changes for %s on %s",
1783  rsc->id, pcmk__node_name(node));
1784 
1785  if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, true)) {
1786  pcmk__schedule_cleanup(rsc, node, false);
1787  }
1788 
1789  sorted_op_list = rsc_history_as_list(rsc_entry, &start_index, &stop_index);
1790  if (start_index < stop_index) {
1791  return; // Resource is stopped
1792  }
1793 
1794  for (GList *iter = sorted_op_list; iter != NULL; iter = iter->next) {
1795  xmlNode *rsc_op = (xmlNode *) iter->data;
1796  const char *task = NULL;
1797  guint interval_ms = 0;
1798 
1799  if (++offset < start_index) {
1800  // Skip actions that happened before a start
1801  continue;
1802  }
1803 
1804  task = crm_element_value(rsc_op, PCMK_XA_OPERATION);
1805  crm_element_value_ms(rsc_op, PCMK_META_INTERVAL, &interval_ms);
1806 
1807  if ((interval_ms > 0)
1809  || node->details->maintenance)) {
1810  // Maintenance mode cancels recurring operations
1813  task, interval_ms, node, "maintenance mode");
1814 
1815  } else if ((interval_ms > 0)
1819  PCMK_ACTION_MIGRATE_FROM, NULL)) {
1820  /* If a resource operation failed, and the operation's definition
1821  * has changed, clear any fail count so they can be retried fresh.
1822  */
1823 
1824  if (pe__bundle_needs_remote_name(rsc)) {
1825  /* We haven't assigned resources to nodes yet, so if the
1826  * REMOTE_CONTAINER_HACK is used, we may calculate the digest
1827  * based on the literal "#uname" value rather than the properly
1828  * substituted value. That would mistakenly make the action
1829  * definition appear to have been changed. Defer the check until
1830  * later in this case.
1831  */
1832  pe__add_param_check(rsc_op, rsc, node, pcmk__check_active,
1833  rsc->cluster);
1834 
1835  } else if (pcmk__check_action_config(rsc, node, rsc_op)
1836  && (pe_get_failcount(node, rsc, NULL, pcmk__fc_effective,
1837  NULL) != 0)) {
1838  pe__clear_failcount(rsc, node, "action definition changed",
1839  rsc->cluster);
1840  }
1841  }
1842  }
1843  g_list_free(sorted_op_list);
1844 }
1845 
1859 static void
1860 process_node_history(pcmk_node_t *node, const xmlNode *lrm_rscs)
1861 {
1862  crm_trace("Processing node history for %s", pcmk__node_name(node));
1863  for (const xmlNode *rsc_entry = pcmk__xe_first_child(lrm_rscs,
1865  NULL, NULL);
1866  rsc_entry != NULL; rsc_entry = pcmk__xe_next_same(rsc_entry)) {
1867 
1868  if (rsc_entry->children != NULL) {
1869  GList *result = pcmk__rscs_matching_id(pcmk__xe_id(rsc_entry),
1870  node->details->data_set);
1871 
1872  for (GList *iter = result; iter != NULL; iter = iter->next) {
1873  pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1874 
1875  if (pcmk__is_primitive(rsc)) {
1876  process_rsc_history(rsc_entry, rsc, node);
1877  }
1878  }
1879  g_list_free(result);
1880  }
1881  }
1882 }
1883 
1884 // XPath to find a node's resource history
1885 #define XPATH_NODE_HISTORY "/" PCMK_XE_CIB "/" PCMK_XE_STATUS \
1886  "/" PCMK__XE_NODE_STATE \
1887  "[@" PCMK_XA_UNAME "='%s']" \
1888  "/" PCMK__XE_LRM "/" PCMK__XE_LRM_RESOURCES
1889 
1902 void
1904 {
1905  crm_trace("Check resource and action configuration for changes");
1906 
1907  /* Rather than iterate through the status section, iterate through the nodes
1908  * and search for the appropriate status subsection for each. This skips
1909  * orphaned nodes and lets us eliminate some cases before searching the XML.
1910  */
1911  for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
1912  pcmk_node_t *node = (pcmk_node_t *) iter->data;
1913 
1914  /* Don't bother checking actions for a node that can't run actions ...
1915  * unless it's in maintenance mode, in which case we still need to
1916  * cancel any existing recurring monitors.
1917  */
1918  if (node->details->maintenance
1919  || pcmk__node_available(node, false, false)) {
1920 
1921  char *xpath = NULL;
1922  xmlNode *history = NULL;
1923 
1925  history = get_xpath_object(xpath, scheduler->input, LOG_NEVER);
1926  free(xpath);
1927 
1928  process_node_history(node, history);
1929  }
1930  }
1931 }
pcmk_assignment_methods_t * cmds
Definition: resources.h:413
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition: complex.c:1032
#define PCMK__XA_OPERATION_KEY
enum pe_link_state state
Definition: actions.h:320
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
Relation applies only if actions are on same node.
void trigger_unfencing(pcmk_resource_t *rsc, pcmk_node_t *node, const char *reason, pcmk_action_t *dependency, pcmk_scheduler_t *scheduler)
Definition: utils.c:591
&#39;then&#39; is runnable (and migratable) only if &#39;first&#39; is runnable
pcmk_scheduler_t * cluster
Definition: resources.h:408
void(* output_actions)(pcmk_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__schedule_cleanup(pcmk_resource_t *rsc, const pcmk_node_t *node, bool optional)
char data[0]
Definition: cpg.c:58
void pcmk__filter_op_for_digest(xmlNode *param_set)
Definition: digest.c:303
User-configured asymmetric ordering.
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
Definition: resources.h:328
const char * user_data
Definition: lrmd_events.h:45
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:736
int runnable_before
Definition: actions.h:360
enum action_tasks pcmk_parse_action(const char *action_name)
Parse an action type from an action name.
Definition: actions.c:92
const char * rsc_id
Definition: lrmd_events.h:41
#define PCMK__XA_RC_CODE
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value.
Definition: nvpair.c:370
G_GNUC_INTERNAL void pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_task, pcmk_action_t *first_action, pcmk_resource_t *then_rsc, char *then_task, pcmk_action_t *then_action, uint32_t flags, pcmk_scheduler_t *sched)
Stopped.
Definition: roles.h:36
const char * name
Definition: cib.c:26
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1026
int(* message)(pcmk__output_t *out, const char *message_id,...)
#define PCMK__XA_TRANSITION_MAGIC
#define clear_action_flag_because(action, flag, reason)
pcmk_action_t * action
Definition: actions.h:322
enum rsc_role_e role
Definition: resources.h:464
#define PCMK__OP_FMT
printf-style format to create operation key from resource, action, interval
xmlNode * params_restart
GList * children
Definition: resources.h:471
#define pcmk__rsc_trace(rsc, fmt, args...)
pcmk__op_digest_t * rsc_action_digest_cmp(pcmk_resource_t *rsc, const xmlNode *xml_op, pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Definition: pe_digest.c:394
unsigned int queue_time
Definition: lrmd_events.h:81
void pcmk__deduplicate_action_inputs(pcmk_action_t *action)
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition: utils.c:457
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Definition: resources.h:316
pe_ordering
Definition: actions.h:283
If &#39;first&#39; is unrunnable, &#39;then&#39; becomes a real, unmigratable action.
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:348
#define reload_key(rsc)
Definition: internal.h:218
#define pcmk__insert_meta(obj, name, value)
void pcmk__handle_rsc_config_changes(pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL bool pcmk__rsc_agent_changed(pcmk_resource_t *rsc, pcmk_node_t *node, const xmlNode *rsc_entry, bool active_on_node)
#define PCMK_ACTION_MONITOR
Definition: actions.h:60
#define PCMK_XA_EXIT_REASON
Definition: xml_names.h:269
G_GNUC_INTERNAL void pcmk__block_colocation_dependents(pcmk_action_t *action)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:301
void pe_action_set_reason(pcmk_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1602
#define PCMK_XE_PARAMETERS
Definition: xml_names.h:156
#define PCMK_ACTION_MIGRATE_TO
Definition: actions.h:59
#define PCMK_ACTION_DO_SHUTDOWN
Definition: actions.h:51
Promoted.
Definition: roles.h:39
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: pe_actions.c:1782
unsigned int t_rcchange
Definition: lrmd_events.h:75
action_tasks
Definition: actions.h:83
#define PCMK__META_STONITH_ACTION
xmlNode * pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *op, const char *caller_version, int target_rc, const char *node, const char *origin)
#define PCMK_XA_QUEUE_TIME
Definition: xml_names.h:360
GList * actions
Definition: scheduler.h:239
#define PCMK__XA_OP_RESTART_DIGEST
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:228
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
If &#39;first&#39; is required, &#39;then&#39; action for instance on same node is.
#define PCMK_ACTION_RELOAD
Definition: actions.h:69
pcmk_action_t * pe__clear_failcount(pcmk_resource_t *rsc, const pcmk_node_t *node, const char *reason, pcmk_scheduler_t *scheduler)
Schedule a controller operation to clear a fail count.
Definition: failcounts.c:458
enum crm_ais_msg_types type
Definition: cpg.c:51
#define PCMK__META_ON_NODE
#define demote_key(rsc)
Definition: internal.h:229
enum ocf_exitcode rc
Definition: lrmd_events.h:63
pcmk_scheduler_t * data_set
Definition: nodes.h:153
pcmk_resource_t * container
Definition: resources.h:476
#define LOG_NEVER
Definition: logging.h:48
#define PCMK_XA_OPERATION
Definition: xml_names.h:344
#define pcmk__set_relation_flags(ar_flags, flags_to_set)
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
int pe_get_failcount(const pcmk_node_t *node, pcmk_resource_t *rsc, time_t *last_failure, uint32_t flags, const xmlNode *xml_op)
Definition: failcounts.c:361
G_GNUC_INTERNAL bool pcmk__node_available(const pcmk_node_t *node, bool consider_score, bool consider_guest)
const char * action
Definition: pcmk_fence.c:30
GList * resources
Definition: scheduler.h:231
unsigned int exec_time
Definition: lrmd_events.h:78
#define PCMK__META_MIGRATE_TARGET
#define pcmk__rsc_debug(rsc, fmt, args...)
bool pcmk__check_action_config(pcmk_resource_t *rsc, pcmk_node_t *node, const xmlNode *xml_op)
#define PCMK_ACTION_RELOAD_AGENT
Definition: actions.h:70
gboolean did_rsc_op_fail(lrmd_event_data_t *event, int target_rc)
Definition: actions.c:484
#define PCMK__XE_LRM_RESOURCE
#define PCMK__XA_TRANSITION_KEY
pcmk_resource_t * parent
Definition: resources.h:409
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition: digest.c:148
#define crm_warn(fmt, args...)
Definition: logging.h:394
G_GNUC_INTERNAL GList * pcmk__rscs_matching_id(const char *id, const pcmk_scheduler_t *scheduler)
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition: actions.c:404
const char * exit_reason
Definition: lrmd_events.h:96
#define action_type_str(flags)
pcmk_node_t * node
Definition: actions.h:341
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:539
#define action_node_str(a)
#define crm_debug(fmt, args...)
Definition: logging.h:402
Actions are ordered (optionally, if no other flags are set)
#define pcmk__clear_action_flags(action, flags_to_clear)
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:446
pcmk_node_t * pe_find_node_id(const GList *node_list, const char *id)
Find a node by ID in a list of nodes.
Definition: status.c:487
uint32_t pcmk__update_ordered_actions(pcmk_action_t *first, pcmk_action_t *then, const pcmk_node_t *node, uint32_t flags, uint32_t filter, uint32_t type, pcmk_scheduler_t *scheduler)
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:440
#define stop_key(rsc)
Definition: internal.h:213
G_GNUC_INTERNAL void pcmk__schedule_cancel(pcmk_resource_t *rsc, const char *call_id, const char *task, guint interval_ms, const pcmk_node_t *node, const char *reason)
char * task
Definition: actions.h:343
GList * actions_after
Definition: actions.h:371
#define PCMK__XA_OP_DIGEST
#define crm_trace(fmt, args...)
Definition: logging.h:404
void pcmk__update_action_for_orderings(pcmk_action_t *then, pcmk_scheduler_t *scheduler)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:98
struct pe_node_shared_s * details
Definition: nodes.h:167
bool pe__bundle_needs_remote_name(pcmk_resource_t *rsc)
Definition: bundle.c:920
#define crm_log_xml_debug(xml, text)
Definition: logging.h:411
#define pcmk__set_raw_action_flags(action_flags, action_name, to_set)
#define PCMK_ACTION_START
Definition: actions.h:72
bool pcmk__is_daemon
Definition: logging.c:47
unsigned long long flags
Definition: resources.h:428
const char * uname
Definition: nodes.h:73
rsc_role_e
Definition: roles.h:34
Action completed, result is known.
Definition: results.h:333
#define PCMK_ACTION_STOP
Definition: actions.h:75
GList * actions
Definition: resources.h:444
#define PCMK_ACTION_STONITH
Definition: actions.h:74
#define PCMK_XA_ID
Definition: xml_names.h:296
#define PCMK_VALUE_TRUE
Definition: options.h:215
#define pcmk__clear_updated_flags(au_flags, action, flags_to_clear)
pe_action_flags
Definition: actions.h:199
#define pcmk__set_rsc_flags(resource, flags_to_set)
char * uuid
Definition: actions.h:344
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: actions.c:196
void free_xml(xmlNode *child)
Definition: xml.c:867
enum pe_obj_types variant
Definition: resources.h:410
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1050
xmlNode * input
Definition: scheduler.h:196
#define pcmk__str_copy(str)
const char * pcmk_action_text(enum action_tasks action)
Get string equivalent of an action type.
Definition: actions.c:37
const char * id
Definition: nodes.h:72
const char * op_type
Definition: lrmd_events.h:43
pcmk_action_t * custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler)
Create or update an action object.
Definition: pe_actions.c:1129
#define pcmk__clear_relation_flags(ar_flags, flags_to_clear)
const char * crm_xml_add_ll(xmlNode *node, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
Definition: nvpair.c:398
unsigned int t_run
Definition: lrmd_events.h:72
#define PCMK_XA_CRM_FEATURE_SET
Definition: xml_names.h:249
#define PCMK__XA_OP_SECURE_DIGEST
#define action_runnable_str(flags)
#define action_optional_str(flags)
#define PCMK_XA_EXEC_TIME
Definition: xml_names.h:265
xmlNode * pcmk__find_action_config(const pcmk_resource_t *rsc, const char *action_name, guint interval_ms, bool include_disabled)
Definition: pe_actions.c:132
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: actions.c:337
#define PCMK_META_INTERVAL
Definition: options.h:91
#define PCMK_XA_LAST_RC_CHANGE
Definition: xml_names.h:311
If &#39;then&#39; is required, &#39;first&#39; must be added to the transition graph.
pcmk__action_result_t result
Definition: pcmk_fence.c:35
pcmk_rsc_methods_t * fns
Definition: resources.h:412
G_GNUC_INTERNAL void pcmk__reschedule_recurring(pcmk_resource_t *rsc, const char *task, guint interval_ms, pcmk_node_t *node)
#define XPATH_NODE_HISTORY
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
Definition: pe_actions.c:1449
#define pcmk__set_updated_flags(au_flags, action, flags_to_set)
#define crm_err(fmt, args...)
Definition: logging.h:391
pcmk_scheduler_t * scheduler
#define PCMK__XE_LRM_RSC_OP
#define CRM_ASSERT(expr)
Definition: results.h:42
Success.
Definition: results.h:178
If &#39;first&#39; is required and runnable, &#39;then&#39; must be in graph.
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
Definition: lrmd_client.c:2562
xmlNode * input
#define PCMK__META_OP_NO_WAIT
#define PCMK_ACTION_MIGRATE_FROM
Definition: actions.h:58
#define PCMK__XA_OP_STATUS
Started.
Definition: roles.h:37
void calculate_active_ops(const GList *sorted_op_list, int *start_index, int *stop_index)
Definition: unpack.c:2624
This structure contains everything that makes up a single output formatter.
int compare_version(const char *version1, const char *version2)
Definition: utils.c:188
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: actions.c:250
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition: complex.c:990
If &#39;then&#39; action becomes required, &#39;first&#39; becomes optional.
#define PCMK_ACTION_PROMOTE
Definition: actions.h:66
GList * running_on
Definition: resources.h:456
enum pe_action_flags flags
Definition: actions.h:349
gboolean maintenance
Definition: nodes.h:104
#define PCMK__XA_CALL_ID
uint32_t(* update_ordered_actions)(pcmk_action_t *first, pcmk_action_t *then, const pcmk_node_t *node, uint32_t flags, uint32_t filter, uint32_t type, pcmk_scheduler_t *scheduler)
#define pcmk__set_action_flags(action, flags_to_set)
Action is in progress.
Definition: results.h:332
bool pcmk__action_locks_rsc_to_node(const pcmk_action_t *action)
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:2134
pcmk_action_t * pcmk__new_shutdown_action(pcmk_node_t *node)
pcmk_resource_t * rsc
Definition: actions.h:340
G_GNUC_INTERNAL void pcmk__order_stops_before_shutdown(pcmk_node_t *node, pcmk_action_t *shutdown_op)
#define PCMK__META_MIGRATE_SOURCE
unsigned long long flags
Definition: scheduler.h:211
#define FAKE_TE_ID
const char * parent
Definition: cib.c:27
bool pe__rsc_running_on_only(const pcmk_resource_t *rsc, const pcmk_node_t *node)
Definition: utils.c:767
const char * crm_meta_value(GHashTable *hash, const char *field)
Get the value of a meta-attribute.
Definition: nvpair.c:987
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:720
#define PCMK_XA_CRM_DEBUG_ORIGIN
Definition: xml_names.h:248
enum pe_ordering type
Definition: actions.h:317
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition: xml.c:2108
&#39;then&#39; action is runnable if certain number of &#39;first&#39; instances are
void pe__add_param_check(const xmlNode *rsc_op, pcmk_resource_t *rsc, pcmk_node_t *node, enum pcmk__check_parameters, pcmk_scheduler_t *scheduler)
Definition: remote.c:189
void pcmk__log_action(const char *pre_text, const pcmk_action_t *action, bool details)
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
uint64_t flags
Definition: remote.c:215
GList * actions_before
Definition: actions.h:370
int required_runnable_before
Definition: actions.h:367
enum pcmk__digest_result rc
#define PCMK_ACTION_NOTIFY
Definition: actions.h:62
No relation (compare with equality rather than bit set)
void pcmk__output_actions(pcmk_scheduler_t *scheduler)