pacemaker 2.1.7-2.1.7
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-2023 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdio.h>
13#include <sys/param.h>
14#include <glib.h>
15
16#include <crm/lrmd_internal.h>
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) || !pe_rsc_is_clone(action->rsc)) {
48 return flags;
49 }
50
51 /* Otherwise (i.e., for clone resource actions on a specific node), first
52 * remember whether the non-node-specific action is runnable.
53 */
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)) {
69 }
70 return flags;
71}
72
91static char *
92action_uuid_for_ordering(const char *first_uuid,
93 const pcmk_resource_t *first_rsc)
94{
95 guint interval_ms = 0;
96 char *uuid = NULL;
97 char *rid = NULL;
98 char *first_task_str = NULL;
99 enum action_tasks first_task = pcmk_action_unspecified;
100 enum action_tasks remapped_task = pcmk_action_unspecified;
101
102 // Only non-notify actions for collective resources need remapping
103 if ((strstr(first_uuid, PCMK_ACTION_NOTIFY) != NULL)
104 || (first_rsc->variant < pcmk_rsc_variant_group)) {
105 goto done;
106 }
107
108 // Only non-recurring actions need remapping
109 CRM_ASSERT(parse_op_key(first_uuid, &rid, &first_task_str, &interval_ms));
110 if (interval_ms > 0) {
111 goto done;
112 }
113
114 first_task = text2task(first_task_str);
115 switch (first_task) {
116 case pcmk_action_stop:
121 remapped_task = first_task + 1;
122 break;
128 remapped_task = first_task;
129 break;
133 break;
134 default:
135 crm_err("Unknown action '%s' in ordering", first_task_str);
136 break;
137 }
138
139 if (remapped_task != pcmk_action_unspecified) {
140 /* If a clone or bundle has notifications enabled, the ordering will be
141 * relative to when notifications have been sent for the remapped task.
142 */
143 if (pcmk_is_set(first_rsc->flags, pcmk_rsc_notify)
144 && (pe_rsc_is_clone(first_rsc) || pe_rsc_is_bundled(first_rsc))) {
145 uuid = pcmk__notify_key(rid, "confirmed-post",
146 task2text(remapped_task));
147 } else {
148 uuid = pcmk__op_key(rid, task2text(remapped_task), 0);
149 }
150 pe_rsc_trace(first_rsc,
151 "Remapped action UUID %s to %s for ordering purposes",
152 first_uuid, uuid);
153 }
154
155done:
156 if (uuid == NULL) {
157 uuid = strdup(first_uuid);
158 CRM_ASSERT(uuid != NULL);
159 }
160 free(first_task_str);
161 free(rid);
162 return uuid;
163}
164
181static pcmk_action_t *
182action_for_ordering(pcmk_action_t *action)
183{
185 pcmk_resource_t *rsc = action->rsc;
186
187 if ((rsc != NULL) && (rsc->variant >= pcmk_rsc_variant_group)
188 && (action->uuid != NULL)) {
189 char *uuid = action_uuid_for_ordering(action->uuid, rsc);
190
191 result = find_first_action(rsc->actions, uuid, NULL, NULL);
192 if (result == NULL) {
193 crm_warn("Not remapping %s to %s because %s does not have "
194 "remapped action", action->uuid, uuid, rsc->id);
195 result = action;
196 }
197 free(uuid);
198 }
199 return result;
200}
201
221static inline uint32_t
222update(pcmk_resource_t *rsc, pcmk_action_t *first, pcmk_action_t *then,
223 const pcmk_node_t *node, uint32_t flags, uint32_t filter, uint32_t type,
225{
226 return rsc->cmds->update_ordered_actions(first, then, node, flags, filter,
227 type, scheduler);
228}
229
243static uint32_t
244update_action_for_ordering_flags(pcmk_action_t *first, pcmk_action_t *then,
245 uint32_t first_flags, uint32_t then_flags,
248{
249 uint32_t changed = pcmk__updated_none;
250
251 /* The node will only be used for clones. If interleaved, node will be NULL,
252 * otherwise the ordering scope will be limited to the node. Normally, the
253 * whole 'then' clone should restart if 'first' is restarted, so then->node
254 * is needed.
255 */
256 pcmk_node_t *node = then->node;
257
259 /* For unfencing, only instances of 'then' on the same node as 'first'
260 * (the unfencing operation) should restart, so reset node to
261 * first->node, at which point this case is handled like a normal
262 * pcmk__ar_first_implies_then.
263 */
267 node = first->node;
268 pe_rsc_trace(then->rsc,
269 "%s then %s: mapped pcmk__ar_first_implies_same_node_then "
270 "to pcmk__ar_first_implies_then on %s",
271 first->uuid, then->uuid, pe__node_name(node));
272 }
273
275 if (then->rsc != NULL) {
276 changed |= update(then->rsc, first, then, node,
277 first_flags & pcmk_action_optional,
279 scheduler);
280 } else if (!pcmk_is_set(first_flags, pcmk_action_optional)
284 }
285 pe_rsc_trace(then->rsc,
286 "%s then %s: %s after pcmk__ar_first_implies_then",
287 first->uuid, then->uuid,
288 (changed? "changed" : "unchanged"));
289 }
290
292 && (then->rsc != NULL)) {
295
296 changed |= update(then->rsc, first, then, node, first_flags, restart,
298 pe_rsc_trace(then->rsc,
299 "%s then %s: %s after pcmk__ar_intermediate_stop",
300 first->uuid, then->uuid,
301 (changed? "changed" : "unchanged"));
302 }
303
305 if (first->rsc != NULL) {
306 changed |= update(first->rsc, first, then, node, first_flags,
308 scheduler);
309 } else if (!pcmk_is_set(first_flags, pcmk_action_optional)
313 }
314 pe_rsc_trace(then->rsc,
315 "%s then %s: %s after pcmk__ar_then_implies_first",
316 first->uuid, then->uuid,
317 (changed? "changed" : "unchanged"));
318 }
319
321 if (then->rsc != NULL) {
322 changed |= update(then->rsc, first, then, node,
323 first_flags & pcmk_action_optional,
326 }
327 pe_rsc_trace(then->rsc,
328 "%s then %s: %s after pcmk__ar_promoted_then_implies_first",
329 first->uuid, then->uuid,
330 (changed? "changed" : "unchanged"));
331 }
332
334 if (then->rsc != NULL) {
335 changed |= update(then->rsc, first, then, node, first_flags,
337 scheduler);
338
339 } else if (pcmk_is_set(first_flags, pcmk_action_runnable)) {
340 // We have another runnable instance of "first"
341 then->runnable_before++;
342
343 /* Mark "then" as runnable if it requires a certain number of
344 * "before" instances to be runnable, and they now are.
345 */
346 if ((then->runnable_before >= then->required_runnable_before)
348
351 }
352 }
353 pe_rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_min_runnable",
354 first->uuid, then->uuid,
355 (changed? "changed" : "unchanged"));
356 }
357
359 && (then->rsc != NULL)) {
360
361 if (!pcmk_is_set(first_flags, pcmk_action_runnable)
362 && (first->rsc != NULL) && (first->rsc->running_on != NULL)) {
363
364 pe_rsc_trace(then->rsc,
365 "%s then %s: ignoring because first is stopping",
366 first->uuid, then->uuid);
367 order->type = (enum pe_ordering) pcmk__ar_none;
368 } else {
369 changed |= update(then->rsc, first, then, node, first_flags,
372 }
373 pe_rsc_trace(then->rsc,
374 "%s then %s: %s after pcmk__ar_nested_remote_probe",
375 first->uuid, then->uuid,
376 (changed? "changed" : "unchanged"));
377 }
378
380 if (then->rsc != NULL) {
381 changed |= update(then->rsc, first, then, node, first_flags,
384
385 } else if (!pcmk_is_set(first_flags, pcmk_action_runnable)
387
390 }
391 pe_rsc_trace(then->rsc,
392 "%s then %s: %s after pcmk__ar_unrunnable_first_blocks",
393 first->uuid, then->uuid,
394 (changed? "changed" : "unchanged"));
395 }
396
398 if (then->rsc != NULL) {
399 changed |= update(then->rsc, first, then, node, first_flags,
402 }
403 pe_rsc_trace(then->rsc, "%s then %s: %s after "
404 "pcmk__ar_unmigratable_then_blocks",
405 first->uuid, then->uuid,
406 (changed? "changed" : "unchanged"));
407 }
408
410 if (then->rsc != NULL) {
411 changed |= update(then->rsc, first, then, node, first_flags,
413 scheduler);
414 }
415 pe_rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_first_else_then",
416 first->uuid, then->uuid,
417 (changed? "changed" : "unchanged"));
418 }
419
420 if (pcmk_is_set(order->type, pcmk__ar_ordered)) {
421 if (then->rsc != NULL) {
422 changed |= update(then->rsc, first, then, node, first_flags,
424 scheduler);
425 }
426 pe_rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_ordered",
427 first->uuid, then->uuid,
428 (changed? "changed" : "unchanged"));
429 }
430
431 if (pcmk_is_set(order->type, pcmk__ar_asymmetric)) {
432 if (then->rsc != NULL) {
433 changed |= update(then->rsc, first, then, node, first_flags,
435 scheduler);
436 }
437 pe_rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_asymmetric",
438 first->uuid, then->uuid,
439 (changed? "changed" : "unchanged"));
440 }
441
444 && !pcmk_is_set(first_flags, pcmk_action_optional)) {
445
446 pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
447 then->uuid, first->uuid);
449 // Don't bother marking 'then' as changed just for this
450 }
451
453 && !pcmk_is_set(then_flags, pcmk_action_optional)) {
454
455 pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
456 first->uuid, then->uuid);
458 // Don't bother marking 'first' as changed just for this
459 }
460
461 if (pcmk_any_flags_set(order->type, pcmk__ar_first_implies_then
464 && (first->rsc != NULL)
468 && pcmk__str_eq(first->task, PCMK_ACTION_STOP, pcmk__str_none)) {
469
473 }
474 pe_rsc_trace(then->rsc, "%s then %s: %s after checking whether first "
475 "is blocked, unmanaged, unrunnable stop",
476 first->uuid, then->uuid,
477 (changed? "changed" : "unchanged"));
478 }
479
480 return changed;
481}
482
483// Convenience macros for logging action properties
484
485#define action_type_str(flags) \
486 (pcmk_is_set((flags), pcmk_action_pseudo)? "pseudo-action" : "action")
487
488#define action_optional_str(flags) \
489 (pcmk_is_set((flags), pcmk_action_optional)? "optional" : "required")
490
491#define action_runnable_str(flags) \
492 (pcmk_is_set((flags), pcmk_action_runnable)? "runnable" : "unrunnable")
493
494#define action_node_str(a) \
495 (((a)->node == NULL)? "no node" : (a)->node->details->uname)
496
504void
507{
508 GList *lpc = NULL;
509 uint32_t changed = pcmk__updated_none;
510 int last_flags = then->flags;
511
512 pe_rsc_trace(then->rsc, "Updating %s %s (%s %s) on %s",
513 action_type_str(then->flags), then->uuid,
516
518 /* Initialize current known "runnable before" actions. As
519 * update_action_for_ordering_flags() is called for each of then's
520 * before actions, this number will increment as runnable 'first'
521 * actions are encountered.
522 */
523 then->runnable_before = 0;
524
525 if (then->required_runnable_before == 0) {
526 /* @COMPAT This ordering constraint uses the deprecated
527 * "require-all=false" attribute. Treat it like "clone-min=1".
528 */
529 then->required_runnable_before = 1;
530 }
531
532 /* The pcmk__ar_min_runnable clause of
533 * update_action_for_ordering_flags() (called below)
534 * will reset runnable if appropriate.
535 */
537 }
538
539 for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
540 pcmk__related_action_t *other = lpc->data;
541 pcmk_action_t *first = other->action;
542
543 pcmk_node_t *then_node = then->node;
544 pcmk_node_t *first_node = first->node;
545
546 if ((first->rsc != NULL)
547 && (first->rsc->variant == pcmk_rsc_variant_group)
548 && pcmk__str_eq(first->task, PCMK_ACTION_START, pcmk__str_none)) {
549
550 first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
551 if (first_node != NULL) {
552 pe_rsc_trace(first->rsc, "Found %s for 'first' %s",
553 pe__node_name(first_node), first->uuid);
554 }
555 }
556
557 if ((then->rsc != NULL)
558 && (then->rsc->variant == pcmk_rsc_variant_group)
559 && pcmk__str_eq(then->task, PCMK_ACTION_START, pcmk__str_none)) {
560
561 then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
562 if (then_node != NULL) {
563 pe_rsc_trace(then->rsc, "Found %s for 'then' %s",
564 pe__node_name(then_node), then->uuid);
565 }
566 }
567
568 // Disable constraint if it only applies when on same node, but isn't
570 && (first_node != NULL) && (then_node != NULL)
571 && !pe__same_node(first_node, then_node)) {
572
573 pe_rsc_trace(then->rsc,
574 "Disabled ordering %s on %s then %s on %s: "
575 "not same node",
576 other->action->uuid, pe__node_name(first_node),
577 then->uuid, pe__node_name(then_node));
578 other->type = (enum pe_ordering) pcmk__ar_none;
579 continue;
580 }
581
583
584 if ((first->rsc != NULL)
587
588 /* 'then' is required, so we must abandon 'first'
589 * (e.g. a required stop cancels any agent reload).
590 */
592 if (!strcmp(first->task, PCMK_ACTION_RELOAD_AGENT)) {
594 }
595 }
596
597 if ((first->rsc != NULL) && (then->rsc != NULL)
598 && (first->rsc != then->rsc) && !is_parent(then->rsc, first->rsc)) {
599 first = action_for_ordering(first);
600 }
601 if (first != other->action) {
602 pe_rsc_trace(then->rsc, "Ordering %s after %s instead of %s",
603 then->uuid, first->uuid, other->action->uuid);
604 }
605
606 pe_rsc_trace(then->rsc,
607 "%s (%#.6x) then %s (%#.6x): type=%#.6x node=%s",
608 first->uuid, first->flags, then->uuid, then->flags,
609 other->type, action_node_str(first));
610
611 if (first == other->action) {
612 /* 'first' was not remapped (e.g. from 'start' to 'running'), which
613 * could mean it is a non-resource action, a primitive resource
614 * action, or already expanded.
615 */
616 uint32_t first_flags, then_flags;
617
618 first_flags = action_flags_for_ordering(first, then_node);
619 then_flags = action_flags_for_ordering(then, first_node);
620
621 changed |= update_action_for_ordering_flags(first, then,
622 first_flags, then_flags,
623 other, scheduler);
624
625 /* 'first' was for a complex resource (clone, group, etc),
626 * create a new dependency if necessary
627 */
628 } else if (order_actions(first, then, other->type)) {
629 /* This was the first time 'first' and 'then' were associated,
630 * start again to get the new actions_before list
631 */
633 pe_rsc_trace(then->rsc,
634 "Disabled ordering %s then %s in favor of %s then %s",
635 other->action->uuid, then->uuid, first->uuid,
636 then->uuid);
637 other->type = (enum pe_ordering) pcmk__ar_none;
638 }
639
640
641 if (pcmk_is_set(changed, pcmk__updated_first)) {
642 crm_trace("Re-processing %s and its 'after' actions "
643 "because it changed", first->uuid);
644 for (GList *lpc2 = first->actions_after; lpc2 != NULL;
645 lpc2 = lpc2->next) {
646 pcmk__related_action_t *other = lpc2->data;
647
649 }
651 }
652 }
653
655 if (last_flags == then->flags) {
657 } else {
659 }
660 }
661
662 if (pcmk_is_set(changed, pcmk__updated_then)) {
663 crm_trace("Re-processing %s and its 'after' actions because it changed",
664 then->uuid);
665 if (pcmk_is_set(last_flags, pcmk_action_runnable)
668 }
670 for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
671 pcmk__related_action_t *other = lpc->data;
672
674 }
675 }
676}
677
678static inline bool
679is_primitive_action(const pcmk_action_t *action)
680{
681 return (action != NULL) && (action->rsc != NULL)
682 && (action->rsc->variant == pcmk_rsc_variant_primitive);
683}
684
693#define clear_action_flag_because(action, flag, reason) do { \
694 if (pcmk_is_set((action)->flags, (flag))) { \
695 pe__clear_action_flags(action, flag); \
696 if ((action)->rsc != (reason)->rsc) { \
697 char *reason_text = pe__action2reason((reason), (flag)); \
698 pe_action_set_reason((action), reason_text, false); \
699 free(reason_text); \
700 } \
701 } \
702 } while (0)
703
714static void
715handle_asymmetric_ordering(const pcmk_action_t *first, pcmk_action_t *then)
716{
717 /* Only resource actions after an unrunnable 'first' action need updates for
718 * asymmetric ordering.
719 */
720 if ((then->rsc == NULL)
722 return;
723 }
724
725 // Certain optional 'then' actions are unaffected by unrunnable 'first'
727 enum rsc_role_e then_rsc_role = then->rsc->fns->state(then->rsc, TRUE);
728
729 if ((then_rsc_role == pcmk_role_stopped)
730 && pcmk__str_eq(then->task, PCMK_ACTION_STOP, pcmk__str_none)) {
731 /* If 'then' should stop after 'first' but is already stopped, the
732 * ordering is irrelevant.
733 */
734 return;
735 } else if ((then_rsc_role >= pcmk_role_started)
736 && pcmk__str_eq(then->task, PCMK_ACTION_START, pcmk__str_none)
737 && pe__rsc_running_on_only(then->rsc, then->node)) {
738 /* Similarly if 'then' should start after 'first' but is already
739 * started on a single node.
740 */
741 return;
742 }
743 }
744
745 // 'First' can't run, so 'then' can't either
748}
749
761static void
762handle_restart_ordering(pcmk_action_t *first, pcmk_action_t *then,
763 uint32_t filter)
764{
765 const char *reason = NULL;
766
767 CRM_ASSERT(is_primitive_action(first));
768 CRM_ASSERT(is_primitive_action(then));
769
770 // We need to update the action in two cases:
771
772 // ... if 'then' is required
775 reason = "restart";
776 }
777
778 /* ... if 'then' is unrunnable action on same resource (if a resource
779 * should restart but can't start, we still want to stop)
780 */
784 && (first->rsc == then->rsc)) {
785 reason = "stop";
786 }
787
788 if (reason == NULL) {
789 return;
790 }
791
792 pe_rsc_trace(first->rsc, "Handling %s -> %s for %s",
793 first->uuid, then->uuid, reason);
794
795 // Make 'first' required if it is runnable
798 }
799
800 // Make 'first' required if 'then' is required
803 }
804
805 // Make 'first' unmigratable if 'then' is unmigratable
808 }
809
810 // Make 'then' unrunnable if 'first' is required but unrunnable
814 }
815}
816
839uint32_t
841 const pcmk_node_t *node, uint32_t flags,
842 uint32_t filter, uint32_t type,
844{
845 uint32_t changed = pcmk__updated_none;
846 uint32_t then_flags = 0U;
847 uint32_t first_flags = 0U;
848
849 CRM_ASSERT((first != NULL) && (then != NULL) && (scheduler != NULL));
850
851 then_flags = then->flags;
852 first_flags = first->flags;
854 handle_asymmetric_ordering(first, then);
855 }
856
858 && !pcmk_is_set(then_flags, pcmk_action_optional)) {
859 // Then is required, and implies first should be, too
860
863 && pcmk_is_set(first_flags, pcmk_action_optional)) {
865 }
866
870 }
871 }
872
874 && (then->rsc != NULL) && (then->rsc->role == pcmk_role_promoted)
877
879
883 }
884 }
885
887 && pcmk_is_set(filter, pcmk_action_optional)) {
888
889 if (!pcmk_all_flags_set(then->flags, pcmk_action_migratable
892 }
893
896 }
897 }
898
902
905 }
906
911
914 }
915
921
923 }
924
926 handle_restart_ordering(first, then, filter);
927 }
928
929 if (then_flags != then->flags) {
931 pe_rsc_trace(then->rsc,
932 "%s on %s: flags are now %#.6x (was %#.6x) "
933 "because of 'first' %s (%#.6x)",
934 then->uuid, pe__node_name(then->node),
935 then->flags, then_flags, first->uuid, first->flags);
936
937 if ((then->rsc != NULL) && (then->rsc->parent != NULL)) {
938 // Required to handle "X_stop then X_start" for cloned groups
940 }
941 }
942
943 if (first_flags != first->flags) {
945 pe_rsc_trace(first->rsc,
946 "%s on %s: flags are now %#.6x (was %#.6x) "
947 "because of 'then' %s (%#.6x)",
948 first->uuid, pe__node_name(first->node),
949 first->flags, first_flags, then->uuid, then->flags);
950 }
951
952 return changed;
953}
954
963void
964pcmk__log_action(const char *pre_text, const pcmk_action_t *action,
965 bool details)
966{
967 const char *node_uname = NULL;
968 const char *node_uuid = NULL;
969 const char *desc = NULL;
970
971 CRM_CHECK(action != NULL, return);
972
973 if (!pcmk_is_set(action->flags, pcmk_action_pseudo)) {
974 if (action->node != NULL) {
975 node_uname = action->node->details->uname;
976 node_uuid = action->node->details->id;
977 } else {
978 node_uname = "<none>";
979 }
980 }
981
982 switch (text2task(action->task)) {
986 desc = "Pseudo ";
987 } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
988 desc = "Optional ";
989 } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
990 desc = "!!Non-Startable!! ";
991 } else {
992 desc = "(Provisional) ";
993 }
994 crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
995 ((pre_text == NULL)? "" : pre_text),
996 ((pre_text == NULL)? "" : ": "),
997 desc, action->id, action->uuid,
998 (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
999 (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1000 (node_uuid? ")" : ""));
1001 break;
1002 default:
1004 desc = "Optional ";
1005 } else if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
1006 desc = "Pseudo ";
1007 } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
1008 desc = "!!Non-Startable!! ";
1009 } else {
1010 desc = "(Provisional) ";
1011 }
1012 crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
1013 ((pre_text == NULL)? "" : pre_text),
1014 ((pre_text == NULL)? "" : ": "),
1015 desc, action->id, action->uuid,
1016 (action->rsc? action->rsc->id : "<none>"),
1017 (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1018 (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1019 (node_uuid? ")" : ""));
1020 break;
1021 }
1022
1023 if (details) {
1024 const GList *iter = NULL;
1025 const pcmk__related_action_t *other = NULL;
1026
1027 crm_trace("\t\t====== Preceding Actions");
1028 for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1029 other = (const pcmk__related_action_t *) iter->data;
1030 pcmk__log_action("\t\t", other->action, false);
1031 }
1032 crm_trace("\t\t====== Subsequent Actions");
1033 for (iter = action->actions_after; iter != NULL; iter = iter->next) {
1034 other = (const pcmk__related_action_t *) iter->data;
1035 pcmk__log_action("\t\t", other->action, false);
1036 }
1037 crm_trace("\t\t====== End");
1038
1039 } else {
1040 crm_trace("\t\t(before=%d, after=%d)",
1041 g_list_length(action->actions_before),
1042 g_list_length(action->actions_after));
1043 }
1044}
1045
1056{
1057 char *shutdown_id = NULL;
1058 pcmk_action_t *shutdown_op = NULL;
1059
1060 CRM_ASSERT(node != NULL);
1061
1062 shutdown_id = crm_strdup_printf("%s-%s", PCMK_ACTION_DO_SHUTDOWN,
1063 node->details->uname);
1064
1065 shutdown_op = custom_action(NULL, shutdown_id, PCMK_ACTION_DO_SHUTDOWN,
1066 node, FALSE, node->details->data_set);
1067
1068 pcmk__order_stops_before_shutdown(node, shutdown_op);
1070 return shutdown_op;
1071}
1072
1084static void
1085add_op_digest_to_xml(const lrmd_event_data_t *op, xmlNode *update)
1086{
1087 char *digest = NULL;
1088 xmlNode *args_xml = NULL;
1089
1090 if (op->params == NULL) {
1091 return;
1092 }
1093 args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
1094 g_hash_table_foreach(op->params, hash2field, args_xml);
1096 digest = calculate_operation_digest(args_xml, NULL);
1097 crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
1098 free_xml(args_xml);
1099 free(digest);
1100}
1101
1102#define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1103
1117xmlNode *
1119 const char *caller_version, int target_rc,
1120 const char *node, const char *origin)
1121{
1122 char *key = NULL;
1123 char *magic = NULL;
1124 char *op_id = NULL;
1125 char *op_id_additional = NULL;
1126 char *local_user_data = NULL;
1127 const char *exit_reason = NULL;
1128
1129 xmlNode *xml_op = NULL;
1130 const char *task = NULL;
1131
1132 CRM_CHECK(op != NULL, return NULL);
1133 crm_trace("Creating history XML for %s-interval %s action for %s on %s "
1134 "(DC version: %s, origin: %s)",
1136 ((node == NULL)? "no node" : node), caller_version, origin);
1137
1138 task = op->op_type;
1139
1140 /* Record a successful agent reload as a start, and a failed one as a
1141 * monitor, to make life easier for the scheduler when determining the
1142 * current state.
1143 *
1144 * @COMPAT We should check "reload" here only if the operation was for a
1145 * pre-OCF-1.1 resource agent, but we don't know that here, and we should
1146 * only ever get results for actions scheduled by us, so we can reasonably
1147 * assume any "reload" is actually a pre-1.1 agent reload.
1148 */
1150 NULL)) {
1151 if (op->op_status == PCMK_EXEC_DONE) {
1152 task = PCMK_ACTION_START;
1153 } else {
1154 task = PCMK_ACTION_MONITOR;
1155 }
1156 }
1157
1158 key = pcmk__op_key(op->rsc_id, task, op->interval_ms);
1159 if (pcmk__str_eq(task, PCMK_ACTION_NOTIFY, pcmk__str_none)) {
1160 const char *n_type = crm_meta_value(op->params, "notify_type");
1161 const char *n_task = crm_meta_value(op->params, "notify_operation");
1162
1163 CRM_LOG_ASSERT(n_type != NULL);
1164 CRM_LOG_ASSERT(n_task != NULL);
1165 op_id = pcmk__notify_key(op->rsc_id, n_type, n_task);
1166
1167 if (op->op_status != PCMK_EXEC_PENDING) {
1168 /* Ignore notify errors.
1169 *
1170 * @TODO It might be better to keep the correct result here, and
1171 * ignore it in process_graph_event().
1172 */
1174 }
1175
1176 /* Migration history is preserved separately, which usually matters for
1177 * multiple nodes and is important for future cluster transitions.
1178 */
1180 PCMK_ACTION_MIGRATE_FROM, NULL)) {
1181 op_id = strdup(key);
1182
1183 } else if (did_rsc_op_fail(op, target_rc)) {
1184 op_id = pcmk__op_key(op->rsc_id, "last_failure", 0);
1185 if (op->interval_ms == 0) {
1186 // Ensure 'last' gets updated, in case record-pending is true
1187 op_id_additional = pcmk__op_key(op->rsc_id, "last", 0);
1188 }
1189 exit_reason = op->exit_reason;
1190
1191 } else if (op->interval_ms > 0) {
1192 op_id = strdup(key);
1193
1194 } else {
1195 op_id = pcmk__op_key(op->rsc_id, "last", 0);
1196 }
1197
1198 again:
1200 if (xml_op == NULL) {
1202 }
1203
1204 if (op->user_data == NULL) {
1205 crm_debug("Generating fake transition key for: " PCMK__OP_FMT
1206 " %d from %s", op->rsc_id, op->op_type, op->interval_ms,
1207 op->call_id, origin);
1208 local_user_data = pcmk__transition_key(-1, op->call_id, target_rc,
1209 FAKE_TE_ID);
1210 op->user_data = local_user_data;
1211 }
1212
1213 if (magic == NULL) {
1214 magic = crm_strdup_printf("%d:%d;%s", op->op_status, op->rc,
1215 (const char *) op->user_data);
1216 }
1217
1218 crm_xml_add(xml_op, XML_ATTR_ID, op_id);
1219 crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
1220 crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
1221 crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
1222 crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
1224 crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
1225 crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, pcmk__s(exit_reason, ""));
1226 crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); // For context during triage
1227
1229 crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
1232
1233 if (compare_version("2.1", caller_version) <= 0) {
1234 if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1235 crm_trace("Timing data (" PCMK__OP_FMT
1236 "): last=%u change=%u exec=%u queue=%u",
1237 op->rsc_id, op->op_type, op->interval_ms,
1238 op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1239
1240 if ((op->interval_ms != 0) && (op->t_rcchange != 0)) {
1241 // Recurring ops may have changed rc after initial run
1243 (long long) op->t_rcchange);
1244 } else {
1246 (long long) op->t_run);
1247 }
1248
1251 }
1252 }
1253
1255 PCMK_ACTION_MIGRATE_FROM, NULL)) {
1256 /*
1257 * Record migrate_source and migrate_target always for migrate ops.
1258 */
1259 const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
1260
1261 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1262
1264 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1265 }
1266
1267 add_op_digest_to_xml(op, xml_op);
1268
1269 if (op_id_additional) {
1270 free(op_id);
1271 op_id = op_id_additional;
1272 op_id_additional = NULL;
1273 goto again;
1274 }
1275
1276 if (local_user_data) {
1277 free(local_user_data);
1278 op->user_data = NULL;
1279 }
1280 free(magic);
1281 free(op_id);
1282 free(key);
1283 return xml_op;
1284}
1285
1300bool
1302{
1303 // Only resource actions taking place on resource's lock node are locked
1304 if ((action == NULL) || (action->rsc == NULL)
1305 || !pe__same_node(action->node, action->rsc->lock_node)) {
1306 return false;
1307 }
1308
1309 /* During shutdown, only stops are locked (otherwise, another action such as
1310 * a demote would cause the controller to clear the lock)
1311 */
1312 if (action->node->details->shutdown && (action->task != NULL)
1313 && (strcmp(action->task, PCMK_ACTION_STOP) != 0)) {
1314 return false;
1315 }
1316
1317 return true;
1318}
1319
1320/* lowest to highest */
1321static gint
1322sort_action_id(gconstpointer a, gconstpointer b)
1323{
1324 const pcmk__related_action_t *action_wrapper2 = a;
1325 const pcmk__related_action_t *action_wrapper1 = b;
1326
1327 if (a == NULL) {
1328 return 1;
1329 }
1330 if (b == NULL) {
1331 return -1;
1332 }
1333 if (action_wrapper1->action->id < action_wrapper2->action->id) {
1334 return 1;
1335 }
1336 if (action_wrapper1->action->id > action_wrapper2->action->id) {
1337 return -1;
1338 }
1339 return 0;
1340}
1341
1348void
1350{
1351 GList *item = NULL;
1352 GList *next = NULL;
1353 pcmk__related_action_t *last_input = NULL;
1354
1355 action->actions_before = g_list_sort(action->actions_before,
1356 sort_action_id);
1357 for (item = action->actions_before; item != NULL; item = next) {
1358 pcmk__related_action_t *input = item->data;
1359
1360 next = item->next;
1361 if ((last_input != NULL)
1362 && (input->action->id == last_input->action->id)) {
1363 crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1364 input->action->uuid, input->action->id,
1365 action->uuid, action->id);
1366
1367 /* For the purposes of scheduling, the ordering flags no longer
1368 * matter, but crm_simulate looks at certain ones when creating a
1369 * dot graph. Combining the flags is sufficient for that purpose.
1370 */
1371 last_input->type |= input->type;
1372 if (input->state == pe_link_dumped) {
1373 last_input->state = pe_link_dumped;
1374 }
1375
1376 free(item->data);
1377 action->actions_before = g_list_delete_link(action->actions_before,
1378 item);
1379 } else {
1380 last_input = input;
1382 }
1383 }
1384}
1385
1392void
1394{
1396
1397 // Output node (non-resource) actions
1398 for (GList *iter = scheduler->actions; iter != NULL; iter = iter->next) {
1399 char *node_name = NULL;
1400 char *task = NULL;
1401 pcmk_action_t *action = (pcmk_action_t *) iter->data;
1402
1403 if (action->rsc != NULL) {
1404 continue; // Resource actions will be output later
1405
1406 } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
1407 continue; // This action was not scheduled
1408 }
1409
1410 if (pcmk__str_eq(action->task, PCMK_ACTION_DO_SHUTDOWN,
1411 pcmk__str_none)) {
1412 task = strdup("Shutdown");
1413
1414 } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH,
1415 pcmk__str_none)) {
1416 const char *op = g_hash_table_lookup(action->meta,
1417 "stonith_action");
1418
1419 task = crm_strdup_printf("Fence (%s)", op);
1420
1421 } else {
1422 continue; // Don't display other node action types
1423 }
1424
1425 if (pe__is_guest_node(action->node)) {
1426 const pcmk_resource_t *remote = action->node->details->remote_rsc;
1427
1428 node_name = crm_strdup_printf("%s (resource: %s)",
1429 pe__node_name(action->node),
1430 remote->container->id);
1431 } else if (action->node != NULL) {
1432 node_name = crm_strdup_printf("%s", pe__node_name(action->node));
1433 }
1434
1435 out->message(out, "node-action", task, node_name, action->reason);
1436
1437 free(node_name);
1438 free(task);
1439 }
1440
1441 // Output resource actions
1442 for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
1443 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1444
1445 rsc->cmds->output_actions(rsc);
1446 }
1447}
1448
1458static const char *
1459task_for_digest(const char *task, guint interval_ms)
1460{
1461 /* Certain actions need to be compared against the parameters used to start
1462 * the resource.
1463 */
1464 if ((interval_ms == 0)
1466 PCMK_ACTION_PROMOTE, NULL)) {
1467 task = PCMK_ACTION_START;
1468 }
1469 return task;
1470}
1471
1489static bool
1490only_sanitized_changed(const xmlNode *xml_op,
1491 const op_digest_cache_t *digest_data,
1493{
1494 const char *digest_secure = NULL;
1495
1497 // The scheduler is not being run as a simulation
1498 return false;
1499 }
1500
1501 digest_secure = crm_element_value(xml_op, XML_LRM_ATTR_SECURE_DIGEST);
1502
1503 return (digest_data->rc != pcmk__digest_match) && (digest_secure != NULL)
1504 && (digest_data->digest_secure_calc != NULL)
1505 && (strcmp(digest_data->digest_secure_calc, digest_secure) == 0);
1506}
1507
1517static void
1518force_restart(pcmk_resource_t *rsc, const char *task, guint interval_ms,
1519 pcmk_node_t *node)
1520{
1521 char *key = pcmk__op_key(rsc->id, task, interval_ms);
1522 pcmk_action_t *required = custom_action(rsc, key, task, NULL, FALSE,
1523 rsc->cluster);
1524
1525 pe_action_set_reason(required, "resource definition change", true);
1526 trigger_unfencing(rsc, node, "Device parameters changed", NULL,
1527 rsc->cluster);
1528}
1529
1537static void
1538schedule_reload(gpointer data, gpointer user_data)
1539{
1540 pcmk_resource_t *rsc = data;
1541 const pcmk_node_t *node = user_data;
1542 pcmk_action_t *reload = NULL;
1543
1544 // For collective resources, just call recursively for children
1546 g_list_foreach(rsc->children, schedule_reload, user_data);
1547 return;
1548 }
1549
1550 // Skip the reload in certain situations
1551 if ((node == NULL)
1553 || pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
1554 pe_rsc_trace(rsc, "Skip reload of %s:%s%s %s",
1555 rsc->id,
1556 pcmk_is_set(rsc->flags, pcmk_rsc_managed)? "" : " unmanaged",
1557 pcmk_is_set(rsc->flags, pcmk_rsc_failed)? " failed" : "",
1558 (node == NULL)? "inactive" : node->details->uname);
1559 return;
1560 }
1561
1562 /* If a resource's configuration changed while a start was pending,
1563 * force a full restart instead of a reload.
1564 */
1566 pe_rsc_trace(rsc, "%s: preventing agent reload because start pending",
1567 rsc->id);
1568 custom_action(rsc, stop_key(rsc), PCMK_ACTION_STOP, node, FALSE,
1569 rsc->cluster);
1570 return;
1571 }
1572
1573 // Schedule the reload
1575 reload = custom_action(rsc, reload_key(rsc), PCMK_ACTION_RELOAD_AGENT, node,
1576 FALSE, rsc->cluster);
1577 pe_action_set_reason(reload, "resource definition change", FALSE);
1578
1579 // Set orderings so that a required stop or demote cancels the reload
1580 pcmk__new_ordering(NULL, NULL, reload, rsc, stop_key(rsc), NULL,
1582 rsc->cluster);
1583 pcmk__new_ordering(NULL, NULL, reload, rsc, demote_key(rsc), NULL,
1585 rsc->cluster);
1586}
1587
1602bool
1604 const xmlNode *xml_op)
1605{
1606 guint interval_ms = 0;
1607 const char *task = NULL;
1608 const op_digest_cache_t *digest_data = NULL;
1609
1610 CRM_CHECK((rsc != NULL) && (node != NULL) && (xml_op != NULL),
1611 return false);
1612
1613 task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1614 CRM_CHECK(task != NULL, return false);
1615
1616 crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1617
1618 // If this is a recurring action, check whether it has been orphaned
1619 if (interval_ms > 0) {
1620 if (pcmk__find_action_config(rsc, task, interval_ms, false) != NULL) {
1621 pe_rsc_trace(rsc, "%s-interval %s for %s on %s is in configuration",
1622 pcmk__readable_interval(interval_ms), task, rsc->id,
1623 pe__node_name(node));
1624 } else if (pcmk_is_set(rsc->cluster->flags,
1627 crm_element_value(xml_op,
1629 task, interval_ms, node, "orphan");
1630 return true;
1631 } else {
1632 pe_rsc_debug(rsc, "%s-interval %s for %s on %s is orphaned",
1633 pcmk__readable_interval(interval_ms), task, rsc->id,
1634 pe__node_name(node));
1635 return true;
1636 }
1637 }
1638
1639 crm_trace("Checking %s-interval %s for %s on %s for configuration changes",
1640 pcmk__readable_interval(interval_ms), task, rsc->id,
1641 pe__node_name(node));
1642 task = task_for_digest(task, interval_ms);
1643 digest_data = rsc_action_digest_cmp(rsc, xml_op, node, rsc->cluster);
1644
1645 if (only_sanitized_changed(xml_op, digest_data, rsc->cluster)) {
1646 if (!pcmk__is_daemon && (rsc->cluster->priv != NULL)) {
1647 pcmk__output_t *out = rsc->cluster->priv;
1648
1649 out->info(out,
1650 "Only 'private' parameters to %s-interval %s for %s "
1651 "on %s changed: %s",
1652 pcmk__readable_interval(interval_ms), task, rsc->id,
1653 pe__node_name(node),
1655 }
1656 return false;
1657 }
1658
1659 switch (digest_data->rc) {
1661 crm_log_xml_debug(digest_data->params_restart, "params:restart");
1662 force_restart(rsc, task, interval_ms, node);
1663 return true;
1664
1667 // Changes that can potentially be handled by an agent reload
1668
1669 if (interval_ms > 0) {
1670 /* Recurring actions aren't reloaded per se, they are just
1671 * re-scheduled so the next run uses the new parameters.
1672 * The old instance will be cancelled automatically.
1673 */
1674 crm_log_xml_debug(digest_data->params_all, "params:reschedule");
1675 pcmk__reschedule_recurring(rsc, task, interval_ms, node);
1676
1677 } else if (crm_element_value(xml_op,
1678 XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
1679 // Agent supports reload, so use it
1680 trigger_unfencing(rsc, node,
1681 "Device parameters changed (reload)", NULL,
1682 rsc->cluster);
1683 crm_log_xml_debug(digest_data->params_all, "params:reload");
1684 schedule_reload((gpointer) rsc, (gpointer) node);
1685
1686 } else {
1687 pe_rsc_trace(rsc,
1688 "Restarting %s "
1689 "because agent doesn't support reload", rsc->id);
1690 crm_log_xml_debug(digest_data->params_restart,
1691 "params:restart");
1692 force_restart(rsc, task, interval_ms, node);
1693 }
1694 return true;
1695
1696 default:
1697 break;
1698 }
1699 return false;
1700}
1701
1710static GList *
1711rsc_history_as_list(const xmlNode *rsc_entry, int *start_index, int *stop_index)
1712{
1713 GList *ops = NULL;
1714
1715 for (xmlNode *rsc_op = first_named_child(rsc_entry, XML_LRM_TAG_RSC_OP);
1716 rsc_op != NULL; rsc_op = crm_next_same_xml(rsc_op)) {
1717 ops = g_list_prepend(ops, rsc_op);
1718 }
1719 ops = g_list_sort(ops, sort_op_by_callid);
1720 calculate_active_ops(ops, start_index, stop_index);
1721 return ops;
1722}
1723
1738static void
1739process_rsc_history(const xmlNode *rsc_entry, pcmk_resource_t *rsc,
1740 pcmk_node_t *node)
1741{
1742 int offset = -1;
1743 int stop_index = 0;
1744 int start_index = 0;
1745 GList *sorted_op_list = NULL;
1746
1747 if (pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
1748 if (pe_rsc_is_anon_clone(pe__const_top_resource(rsc, false))) {
1749 pe_rsc_trace(rsc,
1750 "Skipping configuration check "
1751 "for orphaned clone instance %s",
1752 rsc->id);
1753 } else {
1754 pe_rsc_trace(rsc,
1755 "Skipping configuration check and scheduling clean-up "
1756 "for orphaned resource %s", rsc->id);
1757 pcmk__schedule_cleanup(rsc, node, false);
1758 }
1759 return;
1760 }
1761
1762 if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
1763 if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, false)) {
1764 pcmk__schedule_cleanup(rsc, node, false);
1765 }
1766 pe_rsc_trace(rsc,
1767 "Skipping configuration check for %s "
1768 "because no longer active on %s",
1769 rsc->id, pe__node_name(node));
1770 return;
1771 }
1772
1773 pe_rsc_trace(rsc, "Checking for configuration changes for %s on %s",
1774 rsc->id, pe__node_name(node));
1775
1776 if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, true)) {
1777 pcmk__schedule_cleanup(rsc, node, false);
1778 }
1779
1780 sorted_op_list = rsc_history_as_list(rsc_entry, &start_index, &stop_index);
1781 if (start_index < stop_index) {
1782 return; // Resource is stopped
1783 }
1784
1785 for (GList *iter = sorted_op_list; iter != NULL; iter = iter->next) {
1786 xmlNode *rsc_op = (xmlNode *) iter->data;
1787 const char *task = NULL;
1788 guint interval_ms = 0;
1789
1790 if (++offset < start_index) {
1791 // Skip actions that happened before a start
1792 continue;
1793 }
1794
1795 task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
1796 crm_element_value_ms(rsc_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1797
1798 if ((interval_ms > 0)
1800 || node->details->maintenance)) {
1801 // Maintenance mode cancels recurring operations
1803 crm_element_value(rsc_op,
1805 task, interval_ms, node, "maintenance mode");
1806
1807 } else if ((interval_ms > 0)
1811 PCMK_ACTION_MIGRATE_FROM, NULL)) {
1812 /* If a resource operation failed, and the operation's definition
1813 * has changed, clear any fail count so they can be retried fresh.
1814 */
1815
1817 /* We haven't assigned resources to nodes yet, so if the
1818 * REMOTE_CONTAINER_HACK is used, we may calculate the digest
1819 * based on the literal "#uname" value rather than the properly
1820 * substituted value. That would mistakenly make the action
1821 * definition appear to have been changed. Defer the check until
1822 * later in this case.
1823 */
1824 pe__add_param_check(rsc_op, rsc, node, pcmk__check_active,
1825 rsc->cluster);
1826
1827 } else if (pcmk__check_action_config(rsc, node, rsc_op)
1828 && (pe_get_failcount(node, rsc, NULL, pcmk__fc_effective,
1829 NULL) != 0)) {
1830 pe__clear_failcount(rsc, node, "action definition changed",
1831 rsc->cluster);
1832 }
1833 }
1834 }
1835 g_list_free(sorted_op_list);
1836}
1837
1851static void
1852process_node_history(pcmk_node_t *node, const xmlNode *lrm_rscs)
1853{
1854 crm_trace("Processing node history for %s", pe__node_name(node));
1855 for (const xmlNode *rsc_entry = first_named_child(lrm_rscs,
1857 rsc_entry != NULL; rsc_entry = crm_next_same_xml(rsc_entry)) {
1858
1859 if (rsc_entry->children != NULL) {
1860 GList *result = pcmk__rscs_matching_id(ID(rsc_entry),
1861 node->details->data_set);
1862
1863 for (GList *iter = result; iter != NULL; iter = iter->next) {
1864 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1865
1866 if (rsc->variant == pcmk_rsc_variant_primitive) {
1867 process_rsc_history(rsc_entry, rsc, node);
1868 }
1869 }
1870 g_list_free(result);
1871 }
1872 }
1873}
1874
1875// XPath to find a node's resource history
1876#define XPATH_NODE_HISTORY "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS \
1877 "/" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']" \
1878 "/" XML_CIB_TAG_LRM "/" XML_LRM_TAG_RESOURCES
1879
1892void
1894{
1895 crm_trace("Check resource and action configuration for changes");
1896
1897 /* Rather than iterate through the status section, iterate through the nodes
1898 * and search for the appropriate status subsection for each. This skips
1899 * orphaned nodes and lets us eliminate some cases before searching the XML.
1900 */
1901 for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
1902 pcmk_node_t *node = (pcmk_node_t *) iter->data;
1903
1904 /* Don't bother checking actions for a node that can't run actions ...
1905 * unless it's in maintenance mode, in which case we still need to
1906 * cancel any existing recurring monitors.
1907 */
1908 if (node->details->maintenance
1909 || pcmk__node_available(node, false, false)) {
1910
1911 char *xpath = NULL;
1912 xmlNode *history = NULL;
1913
1915 history = get_xpath_object(xpath, scheduler->input, LOG_NEVER);
1916 free(xpath);
1917
1918 process_node_history(node, history);
1919 }
1920 }
1921}
@ 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.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition actions.c:96
gboolean did_rsc_op_fail(lrmd_event_data_t *event, int target_rc)
Definition actions.c:391
#define PCMK_ACTION_STOP
Definition actions.h:74
pe_ordering
Definition actions.h:346
#define PCMK_ACTION_PROMOTE
Definition actions.h:65
@ pe_link_not_dumped
Definition actions.h:339
@ pe_link_dumped
Definition actions.h:340
#define PCMK_ACTION_START
Definition actions.h:71
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:57
#define PCMK_ACTION_RELOAD
Definition actions.h:68
pe_action_flags
Action scheduling flags.
Definition actions.h:233
@ pcmk_action_runnable
Whether action is runnable.
Definition actions.h:241
@ pcmk_action_migratable
Whether action is allowed to be part of a live migration.
Definition actions.h:253
@ pcmk_action_pseudo
Whether action does not require invoking an agent.
Definition actions.h:238
@ pcmk_action_optional
Whether action should not be executed.
Definition actions.h:244
@ pcmk_action_min_runnable
Definition actions.h:266
@ pcmk_action_always_in_graph
Whether action should be added to transition graph even if optional.
Definition actions.h:247
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:58
action_tasks
Possible actions (including some pseudo-actions)
Definition actions.h:79
@ pcmk_action_start
Start.
Definition actions.h:88
@ pcmk_action_fence
Fence node.
Definition actions.h:101
@ pcmk_action_demote
Demote.
Definition actions.h:97
@ pcmk_action_stopped
Stop completed.
Definition actions.h:86
@ pcmk_action_promote
Promote.
Definition actions.h:94
@ pcmk_action_started
Start completed.
Definition actions.h:89
@ pcmk_action_notified
Notify completed.
Definition actions.h:92
@ pcmk_action_demoted
Demoted.
Definition actions.h:98
@ pcmk_action_stop
Stop.
Definition actions.h:85
@ pcmk_action_shutdown
Shut down node.
Definition actions.h:100
@ pcmk_action_unspecified
Unspecified or unknown action.
Definition actions.h:80
@ pcmk_action_promoted
Promoted.
Definition actions.h:95
@ pcmk_action_notify
Notify.
Definition actions.h:91
@ pcmk_action_monitor
Monitor.
Definition actions.h:81
#define PCMK_ACTION_MONITOR
Definition actions.h:59
#define PCMK_ACTION_STONITH
Definition actions.h:73
#define PCMK_ACTION_RELOAD_AGENT
Definition actions.h:69
#define PCMK_ACTION_DO_SHUTDOWN
Definition actions.h:51
#define PCMK_ACTION_NOTIFY
Definition actions.h:61
void pcmk__filter_op_for_digest(xmlNode *param_set)
Definition actions.c:344
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition actions.c:183
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:42
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition actions.c:250
#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
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition utils.c:490
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
int compare_version(const char *version1, const char *version2)
Definition utils.c:189
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:99
enum action_tasks text2task(const char *task)
Definition common.c:360
const char * task2text(enum action_tasks task)
Definition common.c:405
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition complex.c:919
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:1926
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:380
#define crm_log_xml_debug(xml, text)
Definition logging.h:392
#define CRM_LOG_ASSERT(expr)
Definition logging.h:222
#define CRM_CHECK(expr, failure_action)
Definition logging.h:238
#define crm_debug(fmt, args...)
Definition logging.h:384
#define crm_err(fmt, args...)
Definition logging.h:379
#define LOG_NEVER
Definition logging.h:48
#define crm_trace(fmt, args...)
Definition logging.h:385
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
#define XML_LRM_TAG_RSC_OP
Definition msg_xml.h:279
#define ID(x)
Definition msg_xml.h:474
#define XML_ATTR_TRANSITION_KEY
Definition msg_xml.h:416
#define XML_ATTR_CRM_VERSION
Definition msg_xml.h:140
#define XML_BOOLEAN_TRUE
Definition msg_xml.h:167
#define XML_ATTR_TE_NOWAIT
Definition msg_xml.h:418
#define XML_LRM_ATTR_OP_DIGEST
Definition msg_xml.h:319
#define XML_LRM_ATTR_SECURE_DIGEST
Definition msg_xml.h:323
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition msg_xml.h:330
#define XML_LRM_ATTR_TASK_KEY
Definition msg_xml.h:307
#define XML_LRM_ATTR_OPSTATUS
Definition msg_xml.h:316
#define XML_ATTR_ID
Definition msg_xml.h:156
#define XML_ATTR_TRANSITION_MAGIC
Definition msg_xml.h:415
#define XML_RSC_OP_T_EXEC
Definition msg_xml.h:327
#define XML_LRM_ATTR_RESTART_DIGEST
Definition msg_xml.h:322
#define XML_LRM_ATTR_EXIT_REASON
Definition msg_xml.h:324
#define XML_ATTR_ORIGIN
Definition msg_xml.h:151
#define XML_LRM_ATTR_TASK
Definition msg_xml.h:306
#define XML_LRM_ATTR_MIGRATE_TARGET
Definition msg_xml.h:331
#define XML_LRM_ATTR_TARGET
Definition msg_xml.h:308
#define XML_RSC_OP_LAST_CHANGE
Definition msg_xml.h:326
#define XML_LRM_ATTR_CALLID
Definition msg_xml.h:318
#define XML_LRM_ATTR_RC
Definition msg_xml.h:317
#define XML_RSC_OP_T_QUEUE
Definition msg_xml.h:328
#define XML_TAG_PARAMS
Definition msg_xml.h:230
#define XML_LRM_ATTR_INTERVAL_MS
Definition msg_xml.h:304
#define XML_LRM_TAG_RESOURCE
Definition msg_xml.h:278
pcmk_scheduler_t * scheduler
xmlNode * input
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:447
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition nvpair.c:700
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:349
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition nvpair.c:540
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:399
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:302
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:371
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:453
#define demote_key(rsc)
Definition internal.h:394
#define reload_key(rsc)
Definition internal.h:383
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:225
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:962
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition utils.c:450
#define pe__set_raw_action_flags(action_flags, action_name, flags_to_set)
Definition internal.h:94
bool pe__rsc_running_on_only(const pcmk_resource_t *rsc, const pcmk_node_t *node)
Definition utils.c:754
#define pe__clear_order_flags(order_flags, flags_to_clear)
Definition internal.h:135
#define stop_key(rsc)
Definition internal.h:378
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition internal.h:70
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:36
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:360
op_digest_cache_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:389
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:37
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)
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:64
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.
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:85
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:581
xmlNode * pcmk__find_action_config(const pcmk_resource_t *rsc, const char *action_name, guint interval_ms, bool include_disabled)
Definition pe_actions.c:129
#define pe__set_order_flags(order_flags, flags_to_set)
Definition internal.h:128
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:76
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:508
bool pe__is_guest_node(const pcmk_node_t *node)
Definition remote.c:33
@ pcmk_rsc_variant_group
Group resource.
Definition resources.h:35
@ pcmk_rsc_variant_primitive
Primitive resource.
Definition resources.h:34
@ pcmk_rsc_maintenance
Whether resource, its node, or entire cluster is in maintenance mode.
Definition resources.h:181
@ pcmk_rsc_removed
Whether resource has been removed from the configuration.
Definition resources.h:103
@ pcmk_rsc_notify
Whether resource has clone notifications enabled.
Definition resources.h:115
@ pcmk_rsc_reload
Whether a reload action has been scheduled for resource.
Definition resources.h:142
@ pcmk_rsc_start_pending
Whether resource has pending start action in history.
Definition resources.h:160
@ pcmk_rsc_blocked
Whether resource is blocked from further action.
Definition resources.h:109
@ pcmk_rsc_managed
Whether resource is managed.
Definition resources.h:106
@ pcmk_rsc_failed
Whether resource is considered failed.
Definition resources.h:151
#define CRM_ASSERT(expr)
Definition results.h:42
@ PCMK_OCF_OK
Success.
Definition results.h:170
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:318
@ PCMK_EXEC_PENDING
Action is in progress.
Definition results.h:317
rsc_role_e
Definition roles.h:27
@ pcmk_role_started
Started.
Definition roles.h:30
@ pcmk_role_promoted
Promoted.
Definition roles.h:32
@ pcmk_role_stopped
Stopped.
Definition roles.h:29
@ pcmk_sched_sanitized
Whether sensitive resource attributes have been masked.
Definition scheduler.h:146
@ pcmk_sched_cancel_removed_actions
Definition scheduler.h:101
@ pcmk__check_active
void calculate_active_ops(const GList *sorted_op_list, int *start_index, int *stop_index)
Definition unpack.c:2532
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:448
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:933
@ pcmk__str_none
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:957
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
Definition internal.h:455
char * digest_secure_calc
Definition internal.h:460
xmlNode * params_restart
Definition internal.h:458
xmlNode * params_all
Definition internal.h:456
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
Implementation of pcmk_action_t.
Definition actions.h:390
pcmk_node_t * node
Node to execute action on, if any.
Definition actions.h:401
int runnable_before
For Pacemaker use only.
Definition actions.h:420
char * uuid
Action key.
Definition actions.h:404
char * task
Action name.
Definition actions.h:403
GList * actions_after
For Pacemaker use only.
Definition actions.h:431
GHashTable * meta
Meta-attributes relevant to action.
Definition actions.h:414
int id
Counter to identify action.
Definition actions.h:391
enum pe_action_flags flags
Group of enum pe_action_flags.
Definition actions.h:409
int required_runnable_before
Definition actions.h:427
pcmk_resource_t * rsc
Resource to apply action to, if any.
Definition actions.h:400
GList * actions_before
For Pacemaker use only.
Definition actions.h:430
enum pe_ordering type
Definition actions.h:380
pcmk_action_t * action
Definition actions.h:385
enum pe_link_state state
Definition actions.h:383
Implementation of pcmk_node_t.
Definition nodes.h:130
struct pe_node_shared_s * details
Basic node information.
Definition nodes.h:134
const char * id
Node ID at the cluster layer.
Definition nodes.h:67
const char * uname
Node name in cluster.
Definition nodes.h:68
pcmk_scheduler_t * data_set
Cluster that node is part of.
Definition nodes.h:126
gboolean maintenance
Whether in maintenance mode.
Definition nodes.h:81
Implementation of pcmk_resource_t.
Definition resources.h:399
pcmk_assignment_methods_t * cmds
Resource assignment methods.
Definition resources.h:417
GList * running_on
Nodes where resource may be active.
Definition resources.h:460
GList * actions
Definition resources.h:447
enum pe_obj_types variant
Resource variant.
Definition resources.h:414
GList * children
Resource's child resources, if any.
Definition resources.h:475
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition resources.h:412
pcmk_resource_t * container
Resource containing this one, if any.
Definition resources.h:480
pcmk_rsc_methods_t * fns
Resource object methods.
Definition resources.h:416
char * id
Resource ID in configuration.
Definition resources.h:400
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition resources.h:429
enum rsc_role_e role
Resource's current role.
Definition resources.h:468
pcmk_resource_t * parent
Resource's parent resource, if any.
Definition resources.h:413
Implementation of pcmk_scheduler_t.
Definition scheduler.h:172
GList * actions
Scheduled actions.
Definition scheduler.h:204
xmlNode * input
CIB XML.
Definition scheduler.h:175
GList * resources
Resources in cluster.
Definition scheduler.h:196
unsigned long long flags
Group of enum pcmk_scheduler_flags.
Definition scheduler.h:183
void * priv
For Pacemaker use only.
Definition scheduler.h:229
GList * nodes
Nodes in cluster.
Definition scheduler.h:195
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)
Get resource's current or assigned role.
Definition resources.h:327
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
List nodes where a resource (or any of its children) is.
Definition resources.h:339
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2484
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:211
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition xml.c:2510
void free_xml(xmlNode *child)
Definition xml.c:783
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:638
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition digest.c:150
xmlNode * pcmk__xe_match(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:429