pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
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>
20
31static uint32_t
32action_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
92static char *
93action_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:
122 remapped_task = first_task + 1;
123 break;
129 remapped_task = first_task;
130 break;
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
156done:
157 free(first_task_str);
158 free(rid);
159 return (uuid != NULL)? uuid : pcmk__str_copy(first_uuid);
160}
161
178static pcmk_action_t *
179action_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
218static inline uint32_t
219update(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
240static uint32_t
241update_action_for_ordering_flags(pcmk_action_t *first, pcmk_action_t *then,
242 uint32_t first_flags, uint32_t then_flags,
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)
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
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)
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)
469 && pcmk__str_eq(first->task, PCMK_ACTION_STOP, pcmk__str_none)) {
470
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
506void
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,
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)
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)
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
681static inline bool
682is_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
716static void
717handle_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)
724 return;
725 }
726
727 // Certain optional 'then' actions are unaffected by unrunnable 'first'
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
763static void
764handle_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
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 */
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
800 }
801
802 // Make 'first' required if 'then' is required
805 }
806
807 // Make 'first' unmigratable if 'then' is unmigratable
810 }
811
812 // Make 'then' unrunnable if 'first' is required but unrunnable
816 }
817}
818
841uint32_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
865 && pcmk_is_set(first_flags, pcmk_action_optional)) {
867 }
868
872 }
873 }
874
876 && (then->rsc != NULL) && (then->rsc->role == pcmk_role_promoted)
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
898 }
899 }
900
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
965void
966pcmk__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)) {
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:
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
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
1086static void
1087add_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);
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
1119xmlNode *
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
1305bool
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 */
1326static gint
1327sort_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
1353void
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;
1387 }
1388 }
1389}
1390
1397void
1399{
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
1463static const char *
1464task_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
1494static bool
1495only_sanitized_changed(const xmlNode *xml_op,
1496 const pcmk__op_digest_t *digest_data,
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
1522static void
1523force_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
1542static void
1543schedule_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
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
1608bool
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) {
1667 crm_log_xml_debug(digest_data->params_restart, "params:restart");
1668 force_restart(rsc, task, interval_ms, node);
1669 return true;
1670
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
1717static GList *
1718rsc_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
1747static void
1748process_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
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
1859static void
1860process_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
1902void
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__ar_if_on_same_node
Relation applies only if actions are on same node.
@ pcmk__ar_first_else_then
If 'first' is unrunnable, 'then' becomes a real, unmigratable action.
@ pcmk__ar_first_implies_then
@ pcmk__ar_asymmetric
User-configured asymmetric ordering.
@ pcmk__ar_first_implies_same_node_then
If 'first' is required, 'then' action for instance on same node is.
@ pcmk__ar_then_implies_first
@ pcmk__ar_intermediate_stop
@ pcmk__ar_promoted_then_implies_first
@ pcmk__ar_then_implies_first_graphed
If 'then' is required, 'first' must be added to the transition graph.
@ pcmk__ar_min_runnable
'then' action is runnable if certain number of 'first' instances are
@ pcmk__ar_none
No relation (compare with equality rather than bit set)
@ pcmk__ar_first_implies_then_graphed
If 'first' is required and runnable, 'then' must be in graph.
@ pcmk__ar_nested_remote_probe
@ pcmk__ar_unrunnable_first_blocks
'then' is runnable (and migratable) only if 'first' is runnable
@ pcmk__ar_unmigratable_then_blocks
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
@ pcmk__ar_then_cancels_first
If 'then' action becomes required, 'first' becomes optional.
#define pcmk__clear_relation_flags(ar_flags, flags_to_clear)
#define pcmk__set_relation_flags(ar_flags, flags_to_set)
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition actions.c:250
gboolean did_rsc_op_fail(lrmd_event_data_t *event, int target_rc)
Definition actions.c:484
#define PCMK_ACTION_STOP
Definition actions.h:75
pe_ordering
Definition actions.h:283
#define PCMK_ACTION_PROMOTE
Definition actions.h:66
@ pe_link_not_dumped
Definition actions.h:276
@ pe_link_dumped
Definition actions.h:277
#define PCMK_ACTION_START
Definition actions.h:72
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:58
#define PCMK_ACTION_RELOAD
Definition actions.h:69
pe_action_flags
Definition actions.h:199
@ pcmk_action_runnable
Definition actions.h:207
@ pcmk_action_migratable
Definition actions.h:219
@ pcmk_action_pseudo
Definition actions.h:204
@ pcmk_action_optional
Definition actions.h:210
@ pcmk_action_min_runnable
Definition actions.h:233
@ pcmk_action_always_in_graph
Definition actions.h:213
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:59
action_tasks
Definition actions.h:83
@ pcmk_action_start
Definition actions.h:92
@ pcmk_action_fence
Definition actions.h:105
@ pcmk_action_demote
Definition actions.h:101
@ pcmk_action_stopped
Definition actions.h:90
@ pcmk_action_promote
Definition actions.h:98
@ pcmk_action_started
Definition actions.h:93
@ pcmk_action_notified
Definition actions.h:96
@ pcmk_action_demoted
Definition actions.h:102
@ pcmk_action_stop
Definition actions.h:89
@ pcmk_action_shutdown
Definition actions.h:104
@ pcmk_action_unspecified
Definition actions.h:84
@ pcmk_action_promoted
Definition actions.h:99
@ pcmk_action_notify
Definition actions.h:95
@ pcmk_action_monitor
Definition actions.h:85
#define PCMK_ACTION_MONITOR
Definition actions.h:60
const char * pcmk_action_text(enum action_tasks action)
Get string equivalent of an action type.
Definition actions.c:37
enum action_tasks pcmk_parse_action(const char *action_name)
Parse an action type from an action name.
Definition actions.c:92
#define PCMK_ACTION_STONITH
Definition actions.h:74
#define PCMK_ACTION_RELOAD_AGENT
Definition actions.h:70
#define PCMK_ACTION_DO_SHUTDOWN
Definition actions.h:51
#define PCMK_ACTION_NOTIFY
Definition actions.h:62
void pcmk__filter_op_for_digest(xmlNode *param_set)
Definition digest.c:303
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition actions.c:337
#define pcmk__set_action_flags(action, flags_to_set)
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
#define pcmk__clear_action_flags(action, flags_to_clear)
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition actions.c:404
#define pcmk__set_raw_action_flags(action_flags, action_name, to_set)
#define PCMK__OP_FMT
printf-style format to create operation key from resource, action, interval
const char * parent
Definition cib.c:27
const char * name
Definition cib.c:26
bool pcmk__is_daemon
Definition logging.c:47
uint64_t flags
Definition remote.c:3
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
int compare_version(const char *version1, const char *version2)
Definition utils.c:188
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:98
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition complex.c:990
enum crm_ais_msg_types type
Definition cpg.c:3
char uname[MAX_NAME]
Definition cpg.c:5
char data[0]
Definition cpg.c:10
@ pcmk__digest_match
@ pcmk__digest_restart
@ pcmk__digest_mismatch
@ pcmk__digest_unknown
@ pcmk__fc_effective
const char * pcmk__readable_interval(guint interval_ms)
Definition iso8601.c:2134
G_GNUC_INTERNAL void pcmk__block_colocation_dependents(pcmk_action_t *action)
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)
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)
#define pcmk__set_updated_flags(au_flags, action, flags_to_set)
G_GNUC_INTERNAL GList * pcmk__rscs_matching_id(const char *id, const pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL void pcmk__order_stops_before_shutdown(pcmk_node_t *node, pcmk_action_t *shutdown_op)
G_GNUC_INTERNAL void pcmk__schedule_cleanup(pcmk_resource_t *rsc, const pcmk_node_t *node, bool optional)
#define pcmk__clear_updated_flags(au_flags, action, flags_to_clear)
@ pcmk__updated_none
@ pcmk__updated_first
@ pcmk__updated_then
G_GNUC_INTERNAL void pcmk__reschedule_recurring(pcmk_resource_t *rsc, const char *task, guint interval_ms, pcmk_node_t *node)
G_GNUC_INTERNAL bool pcmk__rsc_agent_changed(pcmk_resource_t *rsc, pcmk_node_t *node, const xmlNode *rsc_entry, bool active_on_node)
G_GNUC_INTERNAL bool pcmk__node_available(const pcmk_node_t *node, bool consider_score, bool consider_guest)
#define crm_warn(fmt, args...)
Definition logging.h:392
#define crm_log_xml_debug(xml, text)
Definition logging.h:409
#define CRM_LOG_ASSERT(expr)
Definition logging.h:228
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_err(fmt, args...)
Definition logging.h:389
#define LOG_NEVER
Definition logging.h:48
#define crm_trace(fmt, args...)
Definition logging.h:402
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
pcmk_scheduler_t * scheduler
xmlNode * input
const char * crm_meta_value(GHashTable *hash, const char *field)
Get the value of a meta-attribute.
Definition nvpair.c:987
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition nvpair.c:736
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
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
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
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
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
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_INTERVAL
Definition options.h:91
#define PCMK_VALUE_TRUE
Definition options.h:215
#define PCMK__META_MIGRATE_SOURCE
#define PCMK__META_ON_NODE
#define PCMK__META_MIGRATE_TARGET
#define PCMK__META_OP_NO_WAIT
#define PCMK__META_STONITH_ACTION
const char * action
Definition pcmk_fence.c:30
pcmk__action_result_t result
Definition pcmk_fence.c:35
void pcmk__log_action(const char *pre_text, const pcmk_action_t *action, bool details)
#define XPATH_NODE_HISTORY
pcmk_action_t * pcmk__new_shutdown_action(pcmk_node_t *node)
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 action_type_str(flags)
void pcmk__update_action_for_orderings(pcmk_action_t *then, pcmk_scheduler_t *scheduler)
void pcmk__handle_rsc_config_changes(pcmk_scheduler_t *scheduler)
#define action_node_str(a)
#define action_runnable_str(flags)
void pcmk__output_actions(pcmk_scheduler_t *scheduler)
#define clear_action_flag_because(action, flag, reason)
bool pcmk__check_action_config(pcmk_resource_t *rsc, pcmk_node_t *node, const xmlNode *xml_op)
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)
#define FAKE_TE_ID
bool pcmk__action_locks_rsc_to_node(const pcmk_action_t *action)
#define action_optional_str(flags)
void pcmk__deduplicate_action_inputs(pcmk_action_t *action)
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
#define demote_key(rsc)
Definition internal.h:229
#define reload_key(rsc)
Definition internal.h:218
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
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1032
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
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition utils.c:457
bool pe__rsc_running_on_only(const pcmk_resource_t *rsc, const pcmk_node_t *node)
Definition utils.c:767
#define stop_key(rsc)
Definition internal.h:213
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
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
void pe_action_set_reason(pcmk_action_t *action, const char *reason, bool overwrite)
bool pe__bundle_needs_remote_name(pcmk_resource_t *rsc)
Definition bundle.c:920
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
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.
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
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
@ pcmk_rsc_variant_group
Definition resources.h:38
@ pcmk_rsc_variant_primitive
Definition resources.h:37
@ pcmk_rsc_maintenance
Definition resources.h:166
@ pcmk_rsc_removed
Definition resources.h:85
@ pcmk_rsc_notify
Definition resources.h:97
@ pcmk_rsc_reload
Definition resources.h:124
@ pcmk_rsc_start_pending
Definition resources.h:142
@ pcmk_rsc_blocked
Definition resources.h:91
@ pcmk_rsc_managed
Definition resources.h:88
@ pcmk_rsc_failed
Definition resources.h:133
#define CRM_ASSERT(expr)
Definition results.h:42
@ PCMK_OCF_OK
Success.
Definition results.h:178
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:333
@ PCMK_EXEC_PENDING
Action is in progress.
Definition results.h:332
rsc_role_e
Definition roles.h:34
@ pcmk_role_started
Started.
Definition roles.h:37
@ pcmk_role_promoted
Promoted.
Definition roles.h:39
@ pcmk_role_stopped
Stopped.
Definition roles.h:36
#define pcmk__set_rsc_flags(resource, flags_to_set)
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
@ pcmk_sched_sanitized
Definition scheduler.h:161
@ pcmk_sched_cancel_removed_actions
Definition scheduler.h:114
#define pcmk__rsc_trace(rsc, fmt, args...)
@ pcmk__check_active
#define pcmk__rsc_debug(rsc, fmt, args...)
void calculate_active_ops(const GList *sorted_op_list, int *start_index, int *stop_index)
Definition unpack.c:2624
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
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1026
@ pcmk__str_none
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1050
#define pcmk__str_copy(str)
const char * op_type
Definition lrmd_events.h:43
unsigned int t_run
Definition lrmd_events.h:72
unsigned int t_rcchange
Definition lrmd_events.h:75
const char * exit_reason
Definition lrmd_events.h:96
const char * user_data
Definition lrmd_events.h:45
unsigned int exec_time
Definition lrmd_events.h:78
enum ocf_exitcode rc
Definition lrmd_events.h:63
unsigned int queue_time
Definition lrmd_events.h:81
const char * rsc_id
Definition lrmd_events.h:41
enum pcmk__digest_result rc
This structure contains everything that makes up a single output formatter.
int(* message)(pcmk__output_t *out, const char *message_id,...)
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
pcmk_node_t * node
Definition actions.h:341
int runnable_before
Definition actions.h:360
char * uuid
Definition actions.h:344
char * task
Definition actions.h:343
GList * actions_after
Definition actions.h:371
enum pe_action_flags flags
Definition actions.h:349
int required_runnable_before
Definition actions.h:367
pcmk_resource_t * rsc
Definition actions.h:340
GList * actions_before
Definition actions.h:370
enum pe_ordering type
Definition actions.h:317
pcmk_action_t * action
Definition actions.h:322
enum pe_link_state state
Definition actions.h:320
struct pe_node_shared_s * details
Definition nodes.h:167
const char * id
Definition nodes.h:72
const char * uname
Definition nodes.h:73
pcmk_scheduler_t * data_set
Definition nodes.h:153
gboolean maintenance
Definition nodes.h:104
pcmk_assignment_methods_t * cmds
Definition resources.h:413
GList * running_on
Definition resources.h:456
GList * actions
Definition resources.h:444
enum pe_obj_types variant
Definition resources.h:410
GList * children
Definition resources.h:471
pcmk_scheduler_t * cluster
Definition resources.h:408
pcmk_resource_t * container
Definition resources.h:476
pcmk_rsc_methods_t * fns
Definition resources.h:412
unsigned long long flags
Definition resources.h:428
enum rsc_role_e role
Definition resources.h:464
pcmk_resource_t * parent
Definition resources.h:409
xmlNode * input
Definition scheduler.h:196
GList * resources
Definition scheduler.h:231
unsigned long long flags
Definition scheduler.h:211
void(* output_actions)(pcmk_resource_t *rsc)
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)
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Definition resources.h:316
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
Definition resources.h:328
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:189
void free_xml(xmlNode *child)
Definition xml.c:867
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition digest.c:148
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition xml.c:2108
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
#define PCMK_XA_QUEUE_TIME
Definition xml_names.h:360
#define PCMK_XA_OPERATION
Definition xml_names.h:344
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XA_LAST_RC_CHANGE
Definition xml_names.h:311
#define PCMK_XA_EXEC_TIME
Definition xml_names.h:265
#define PCMK_XA_CRM_FEATURE_SET
Definition xml_names.h:249
#define PCMK_XE_PARAMETERS
Definition xml_names.h:156
#define PCMK_XA_EXIT_REASON
Definition xml_names.h:269
#define PCMK_XA_CRM_DEBUG_ORIGIN
Definition xml_names.h:248
#define PCMK__XE_LRM_RSC_OP
#define PCMK__XE_LRM_RESOURCE
#define PCMK__XA_OP_DIGEST
#define PCMK__XA_CALL_ID
#define PCMK__XA_TRANSITION_MAGIC
#define PCMK__XA_OP_RESTART_DIGEST
#define PCMK__XA_OPERATION_KEY
#define PCMK__XA_OP_STATUS
#define PCMK__XA_OP_SECURE_DIGEST
#define PCMK__XA_TRANSITION_KEY
#define PCMK__XA_RC_CODE