pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_ordering.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 <inttypes.h> // PRIx32
13#include <stdbool.h>
14#include <glib.h>
15
16#include <crm/crm.h>
17#include <pacemaker-internal.h>
19
25
27 ordering_asymmetric, // the only relation in an asymmetric ordering
28 ordering_symmetric, // the normal relation in a symmetric ordering
29 ordering_symmetric_inverse, // the inverse relation in a symmetric ordering
30};
31
32#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name) do { \
33 __rsc = pcmk__find_constraint_resource(scheduler->resources, \
34 __name); \
35 if (__rsc == NULL) { \
36 pcmk__config_err("%s: No resource found for %s", __set, __name);\
37 return pcmk_rc_unpack_error; \
38 } \
39 } while (0)
40
41static const char *
42invert_action(const char *action)
43{
44 if (pcmk__str_eq(action, PCMK_ACTION_START, pcmk__str_none)) {
45 return PCMK_ACTION_STOP;
46
47 } else if (pcmk__str_eq(action, PCMK_ACTION_STOP, pcmk__str_none)) {
48 return PCMK_ACTION_START;
49
50 } else if (pcmk__str_eq(action, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
51 return PCMK_ACTION_DEMOTE;
52
53 } else if (pcmk__str_eq(action, PCMK_ACTION_DEMOTE, pcmk__str_none)) {
55
56 } else if (pcmk__str_eq(action, PCMK_ACTION_PROMOTED, pcmk__str_none)) {
58
59 } else if (pcmk__str_eq(action, PCMK_ACTION_DEMOTED, pcmk__str_none)) {
61
62 } else if (pcmk__str_eq(action, PCMK_ACTION_RUNNING, pcmk__str_none)) {
64
65 } else if (pcmk__str_eq(action, PCMK_ACTION_STOPPED, pcmk__str_none)) {
67 }
68 crm_warn("Unknown action '%s' specified in order constraint", action);
69 return NULL;
70}
71
72static enum pe_order_kind
73get_ordering_type(const xmlNode *xml_obj)
74{
76 const char *kind = crm_element_value(xml_obj, XML_ORDER_ATTR_KIND);
77
78 if (kind == NULL) {
79 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
80
82
83 if (score) {
84 // @COMPAT deprecated informally since 1.0.7, formally since 2.0.1
85 int score_i = char2score(score);
86
87 if (score_i == 0) {
89 }
91 "Support for 'score' in rsc_order is deprecated "
92 "and will be removed in a future release "
93 "(use 'kind' instead)");
94 }
95
96 } else if (pcmk__str_eq(kind, "Mandatory", pcmk__str_none)) {
98
99 } else if (pcmk__str_eq(kind, "Optional", pcmk__str_none)) {
100 kind_e = pe_order_kind_optional;
101
102 } else if (pcmk__str_eq(kind, "Serialize", pcmk__str_none)) {
104
105 } else {
106 pcmk__config_err("Resetting '" XML_ORDER_ATTR_KIND "' for constraint "
107 "%s to 'Mandatory' because '%s' is not valid",
108 pcmk__s(ID(xml_obj), "missing ID"), kind);
109 }
110 return kind_e;
111}
112
124static enum ordering_symmetry
125get_ordering_symmetry(const xmlNode *xml_obj, enum pe_order_kind parent_kind,
126 const char *parent_symmetrical_s)
127{
128 int rc = pcmk_rc_ok;
129 bool symmetric = false;
130 enum pe_order_kind kind = parent_kind; // Default to parent's kind
131
132 // Check ordering XML for explicit kind
133 if ((crm_element_value(xml_obj, XML_ORDER_ATTR_KIND) != NULL)
134 || (crm_element_value(xml_obj, XML_RULE_ATTR_SCORE) != NULL)) {
135 kind = get_ordering_type(xml_obj);
136 }
137
138 // Check ordering XML (and parent) for explicit symmetrical setting
139 rc = pcmk__xe_get_bool_attr(xml_obj, XML_CONS_ATTR_SYMMETRICAL, &symmetric);
140
141 if (rc != pcmk_rc_ok && parent_symmetrical_s != NULL) {
142 symmetric = crm_is_true(parent_symmetrical_s);
143 rc = pcmk_rc_ok;
144 }
145
146 if (rc == pcmk_rc_ok) {
147 if (symmetric) {
148 if (kind == pe_order_kind_serialize) {
150 " for '%s' because not valid with "
151 XML_ORDER_ATTR_KIND " of 'Serialize'",
152 ID(xml_obj));
153 } else {
154 return ordering_symmetric;
155 }
156 }
157 return ordering_asymmetric;
158 }
159
160 // Use default symmetry
161 if (kind == pe_order_kind_serialize) {
162 return ordering_asymmetric;
163 }
164 return ordering_symmetric;
165}
166
177static uint32_t
178ordering_flags_for_kind(enum pe_order_kind kind, const char *first,
179 enum ordering_symmetry symmetry)
180{
181 uint32_t flags = pcmk__ar_none; // so we trace-log all flags set
182
183 switch (kind) {
186 break;
187
189 /* This flag is not used anywhere directly but means the relation
190 * will not match an equality comparison against pcmk__ar_none or
191 * pcmk__ar_ordered.
192 */
194 break;
195
198 switch (symmetry) {
201 break;
202
206 PCMK_ACTION_PROMOTE, NULL)) {
209 }
210 break;
211
214 break;
215 }
216 break;
217 }
218 return flags;
219}
220
234static pcmk_resource_t *
235get_ordering_resource(const xmlNode *xml, const char *resource_attr,
236 const char *instance_attr,
238{
239 // @COMPAT: instance_attr and instance_id variables deprecated since 2.1.5
240 pcmk_resource_t *rsc = NULL;
241 const char *rsc_id = crm_element_value(xml, resource_attr);
242 const char *instance_id = crm_element_value(xml, instance_attr);
243
244 if (rsc_id == NULL) {
245 pcmk__config_err("Ignoring constraint '%s' without %s",
246 ID(xml), resource_attr);
247 return NULL;
248 }
249
251 if (rsc == NULL) {
252 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
253 "does not exist", ID(xml), rsc_id);
254 return NULL;
255 }
256
257 if (instance_id != NULL) {
259 "Support for " XML_ORDER_ATTR_FIRST_INSTANCE " and "
260 XML_ORDER_ATTR_THEN_INSTANCE " is deprecated and will be "
261 "removed in a future release.");
262
263 if (!pe_rsc_is_clone(rsc)) {
264 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
265 "is not a clone but instance '%s' was requested",
266 ID(xml), rsc_id, instance_id);
267 return NULL;
268 }
269 rsc = find_clone_instance(rsc, instance_id);
270 if (rsc == NULL) {
271 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
272 "does not have an instance '%s'",
273 "'%s'", ID(xml), rsc_id, instance_id);
274 return NULL;
275 }
276 }
277 return rsc;
278}
279
289static int
290get_minimum_first_instances(const pcmk_resource_t *rsc, const xmlNode *xml)
291{
292 const char *clone_min = NULL;
293 bool require_all = false;
294
295 if (!pe_rsc_is_clone(rsc)) {
296 return 0;
297 }
298
299 clone_min = g_hash_table_lookup(rsc->meta, PCMK_META_CLONE_MIN);
300 if (clone_min != NULL) {
301 int clone_min_int = 0;
302
303 pcmk__scan_min_int(clone_min, &clone_min_int, 0);
304 return clone_min_int;
305 }
306
307 /* @COMPAT 1.1.13:
308 * require-all=false is deprecated equivalent of clone-min=1
309 */
310 if (pcmk__xe_get_bool_attr(xml, "require-all", &require_all) != ENODATA) {
312 "Support for require-all in ordering constraints "
313 "is deprecated and will be removed in a future release"
314 " (use clone-min clone meta-attribute instead)");
315 if (!require_all) {
316 return 1;
317 }
318 }
319
320 return 0;
321}
322
335static void
336clone_min_ordering(const char *id,
337 pcmk_resource_t *rsc_first, const char *action_first,
338 pcmk_resource_t *rsc_then, const char *action_then,
339 uint32_t flags, int clone_min)
340{
341 // Create a pseudo-action for when the minimum instances are active
342 char *task = crm_strdup_printf(PCMK_ACTION_CLONE_ONE_OR_MORE ":%s", id);
343 pcmk_action_t *clone_min_met = get_pseudo_op(task, rsc_first->cluster);
344
345 free(task);
346
347 /* Require the pseudo-action to have the required number of actions to be
348 * considered runnable before allowing the pseudo-action to be runnable.
349 */
350 clone_min_met->required_runnable_before = clone_min;
352
353 // Order the actions for each clone instance before the pseudo-action
354 for (GList *iter = rsc_first->children; iter != NULL; iter = iter->next) {
355 pcmk_resource_t *child = iter->data;
356
357 pcmk__new_ordering(child, pcmk__op_key(child->id, action_first, 0),
358 NULL, NULL, NULL, clone_min_met,
361 rsc_first->cluster);
362 }
363
364 // Order "then" action after the pseudo-action (if runnable)
365 pcmk__new_ordering(NULL, NULL, clone_min_met, rsc_then,
366 pcmk__op_key(rsc_then->id, action_then, 0),
368 rsc_first->cluster);
369}
370
384#define handle_restart_type(rsc, kind, flag, flags) do { \
385 if (((kind) == pe_order_kind_optional) \
386 && ((rsc)->restart_type == pe_restart_restart)) { \
387 pe__set_order_flags((flags), (flag)); \
388 } \
389 } while (0)
390
402static void
403inverse_ordering(const char *id, enum pe_order_kind kind,
404 pcmk_resource_t *rsc_first, const char *action_first,
405 pcmk_resource_t *rsc_then, const char *action_then)
406{
407 action_then = invert_action(action_then);
408 action_first = invert_action(action_first);
409 if ((action_then == NULL) || (action_first == NULL)) {
410 pcmk__config_warn("Cannot invert constraint '%s' "
411 "(please specify inverse manually)", id);
412 } else {
413 uint32_t flags = ordering_flags_for_kind(kind, action_first,
415
417 pcmk__order_resource_actions(rsc_then, action_then, rsc_first,
418 action_first, flags);
419 }
420}
421
422static void
423unpack_simple_rsc_order(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
424{
425 pcmk_resource_t *rsc_then = NULL;
426 pcmk_resource_t *rsc_first = NULL;
427 int min_required_before = 0;
429 uint32_t flags = pcmk__ar_none;
430 enum ordering_symmetry symmetry;
431
432 const char *action_then = NULL;
433 const char *action_first = NULL;
434 const char *id = NULL;
435
436 CRM_CHECK(xml_obj != NULL, return);
437
438 id = crm_element_value(xml_obj, XML_ATTR_ID);
439 if (id == NULL) {
440 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
441 xml_obj->name);
442 return;
443 }
444
445 rsc_first = get_ordering_resource(xml_obj, XML_ORDER_ATTR_FIRST,
447 scheduler);
448 if (rsc_first == NULL) {
449 return;
450 }
451
452 rsc_then = get_ordering_resource(xml_obj, XML_ORDER_ATTR_THEN,
454 scheduler);
455 if (rsc_then == NULL) {
456 return;
457 }
458
459 action_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_ACTION);
460 if (action_first == NULL) {
461 action_first = PCMK_ACTION_START;
462 }
463
464 action_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_ACTION);
465 if (action_then == NULL) {
466 action_then = action_first;
467 }
468
469 kind = get_ordering_type(xml_obj);
470
471 symmetry = get_ordering_symmetry(xml_obj, kind, NULL);
472 flags = ordering_flags_for_kind(kind, action_first, symmetry);
473
475
476 /* If there is a minimum number of instances that must be runnable before
477 * the 'then' action is runnable, we use a pseudo-action for convenience:
478 * minimum number of clone instances have runnable actions ->
479 * pseudo-action is runnable -> dependency is runnable.
480 */
481 min_required_before = get_minimum_first_instances(rsc_first, xml_obj);
482 if (min_required_before > 0) {
483 clone_min_ordering(id, rsc_first, action_first, rsc_then, action_then,
484 flags, min_required_before);
485 } else {
486 pcmk__order_resource_actions(rsc_first, action_first, rsc_then,
487 action_then, flags);
488 }
489
490 if (symmetry == ordering_symmetric) {
491 inverse_ordering(id, kind, rsc_first, action_first,
492 rsc_then, action_then);
493 }
494}
495
524void
525pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_action_task,
526 pcmk_action_t *first_action, pcmk_resource_t *then_rsc,
527 char *then_action_task, pcmk_action_t *then_action,
528 uint32_t flags, pcmk_scheduler_t *sched)
529{
530 pe__ordering_t *order = NULL;
531
532 // One of action or resource must be specified for each side
533 CRM_CHECK(((first_action != NULL) || (first_rsc != NULL))
534 && ((then_action != NULL) || (then_rsc != NULL)),
535 free(first_action_task); free(then_action_task); return);
536
537 if ((first_rsc == NULL) && (first_action != NULL)) {
538 first_rsc = first_action->rsc;
539 }
540 if ((then_rsc == NULL) && (then_action != NULL)) {
541 then_rsc = then_action->rsc;
542 }
543
544 order = calloc(1, sizeof(pe__ordering_t));
545 CRM_ASSERT(order != NULL);
546
547 order->id = sched->order_id++;
548 order->flags = flags;
549 order->lh_rsc = first_rsc;
550 order->rh_rsc = then_rsc;
551 order->lh_action = first_action;
552 order->rh_action = then_action;
553 order->lh_action_task = first_action_task;
554 order->rh_action_task = then_action_task;
555
556 if ((order->lh_action_task == NULL) && (first_action != NULL)) {
557 order->lh_action_task = strdup(first_action->uuid);
558 }
559
560 if ((order->rh_action_task == NULL) && (then_action != NULL)) {
561 order->rh_action_task = strdup(then_action->uuid);
562 }
563
564 if ((order->lh_rsc == NULL) && (first_action != NULL)) {
565 order->lh_rsc = first_action->rsc;
566 }
567
568 if ((order->rh_rsc == NULL) && (then_action != NULL)) {
569 order->rh_rsc = then_action->rsc;
570 }
571
572 pe_rsc_trace(first_rsc, "Created ordering %d for %s then %s",
573 (sched->order_id - 1),
574 pcmk__s(order->lh_action_task, "an underspecified action"),
575 pcmk__s(order->rh_action_task, "an underspecified action"));
576
577 sched->ordering_constraints = g_list_prepend(sched->ordering_constraints,
578 order);
580}
581
592static int
593unpack_order_set(const xmlNode *set, enum pe_order_kind parent_kind,
594 const char *parent_symmetrical_s, pcmk_scheduler_t *scheduler)
595{
596 GList *set_iter = NULL;
597 GList *resources = NULL;
598
599 pcmk_resource_t *last = NULL;
600 pcmk_resource_t *resource = NULL;
601
602 int local_kind = parent_kind;
603 bool sequential = false;
604 uint32_t flags = pcmk__ar_ordered;
605 enum ordering_symmetry symmetry;
606
607 char *key = NULL;
608 const char *id = ID(set);
609 const char *action = crm_element_value(set, "action");
610 const char *sequential_s = crm_element_value(set, "sequential");
611 const char *kind_s = crm_element_value(set, XML_ORDER_ATTR_KIND);
612
613 if (action == NULL) {
615 }
616
617 if (kind_s) {
618 local_kind = get_ordering_type(set);
619 }
620 if (sequential_s == NULL) {
621 sequential_s = "1";
622 }
623
624 sequential = crm_is_true(sequential_s);
625
626 symmetry = get_ordering_symmetry(set, parent_kind, parent_symmetrical_s);
627 flags = ordering_flags_for_kind(local_kind, action, symmetry);
628
629 for (const xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
630 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
631
632 EXPAND_CONSTRAINT_IDREF(id, resource, ID(xml_rsc));
633 resources = g_list_append(resources, resource);
634 }
635
636 if (pcmk__list_of_1(resources)) {
637 crm_trace("Single set: %s", id);
638 goto done;
639 }
640
641 set_iter = resources;
642 while (set_iter != NULL) {
643 resource = (pcmk_resource_t *) set_iter->data;
644 set_iter = set_iter->next;
645
646 key = pcmk__op_key(resource->id, action, 0);
647
648 if (local_kind == pe_order_kind_serialize) {
649 /* Serialize before everything that comes after */
650
651 for (GList *iter = set_iter; iter != NULL; iter = iter->next) {
652 pcmk_resource_t *then_rsc = iter->data;
653 char *then_key = pcmk__op_key(then_rsc->id, action, 0);
654
655 pcmk__new_ordering(resource, strdup(key), NULL, then_rsc,
656 then_key, NULL, flags, scheduler);
657 }
658
659 } else if (sequential) {
660 if (last != NULL) {
662 flags);
663 }
664 last = resource;
665 }
666 free(key);
667 }
668
669 if (symmetry == ordering_asymmetric) {
670 goto done;
671 }
672
673 last = NULL;
674 action = invert_action(action);
675
676 flags = ordering_flags_for_kind(local_kind, action,
678
679 set_iter = resources;
680 while (set_iter != NULL) {
681 resource = (pcmk_resource_t *) set_iter->data;
682 set_iter = set_iter->next;
683
684 if (sequential) {
685 if (last != NULL) {
687 flags);
688 }
689 last = resource;
690 }
691 }
692
693 done:
694 g_list_free(resources);
695 return pcmk_rc_ok;
696}
697
710static int
711order_rsc_sets(const char *id, const xmlNode *set1, const xmlNode *set2,
713 enum ordering_symmetry symmetry)
714{
715
716 const xmlNode *xml_rsc = NULL;
717 const xmlNode *xml_rsc_2 = NULL;
718
719 pcmk_resource_t *rsc_1 = NULL;
720 pcmk_resource_t *rsc_2 = NULL;
721
722 const char *action_1 = crm_element_value(set1, "action");
723 const char *action_2 = crm_element_value(set2, "action");
724
725 uint32_t flags = pcmk__ar_none;
726
727 bool require_all = true;
728
729 (void) pcmk__xe_get_bool_attr(set1, "require-all", &require_all);
730
731 if (action_1 == NULL) {
732 action_1 = PCMK_ACTION_START;
733 }
734
735 if (action_2 == NULL) {
736 action_2 = PCMK_ACTION_START;
737 }
738
739 if (symmetry == ordering_symmetric_inverse) {
740 action_1 = invert_action(action_1);
741 action_2 = invert_action(action_2);
742 }
743
744 if (pcmk__str_eq(PCMK_ACTION_STOP, action_1, pcmk__str_none)
745 || pcmk__str_eq(PCMK_ACTION_DEMOTE, action_1, pcmk__str_none)) {
746 /* Assuming: A -> ( B || C) -> D
747 * The one-or-more logic only applies during the start/promote phase.
748 * During shutdown neither B nor can shutdown until D is down, so simply
749 * turn require_all back on.
750 */
751 require_all = true;
752 }
753
754 flags = ordering_flags_for_kind(kind, action_1, symmetry);
755
756 /* If we have an unordered set1, whether it is sequential or not is
757 * irrelevant in regards to set2.
758 */
759 if (!require_all) {
760 char *task = crm_strdup_printf(PCMK_ACTION_ONE_OR_MORE ":%s", ID(set1));
761 pcmk_action_t *unordered_action = get_pseudo_op(task, scheduler);
762
763 free(task);
765
766 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
767 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
768
769 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
770
771 /* Add an ordering constraint between every element in set1 and the
772 * pseudo action. If any action in set1 is runnable the pseudo
773 * action will be runnable.
774 */
775 pcmk__new_ordering(rsc_1, pcmk__op_key(rsc_1->id, action_1, 0),
776 NULL, NULL, NULL, unordered_action,
779 scheduler);
780 }
781 for (xml_rsc_2 = first_named_child(set2, XML_TAG_RESOURCE_REF);
782 xml_rsc_2 != NULL; xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
783
784 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
785
786 /* Add an ordering constraint between the pseudo-action and every
787 * element in set2. If the pseudo-action is runnable, every action
788 * in set2 will be runnable.
789 */
790 pcmk__new_ordering(NULL, NULL, unordered_action,
791 rsc_2, pcmk__op_key(rsc_2->id, action_2, 0),
793 scheduler);
794 }
795
796 return pcmk_rc_ok;
797 }
798
799 if (pcmk__xe_attr_is_true(set1, "sequential")) {
800 if (symmetry == ordering_symmetric_inverse) {
801 // Get the first one
803 if (xml_rsc != NULL) {
804 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
805 }
806
807 } else {
808 // Get the last one
809 const char *rid = NULL;
810
811 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
812 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
813
814 rid = ID(xml_rsc);
815 }
816 EXPAND_CONSTRAINT_IDREF(id, rsc_1, rid);
817 }
818 }
819
820 if (pcmk__xe_attr_is_true(set2, "sequential")) {
821 if (symmetry == ordering_symmetric_inverse) {
822 // Get the last one
823 const char *rid = NULL;
824
825 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
826 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
827
828 rid = ID(xml_rsc);
829 }
830 EXPAND_CONSTRAINT_IDREF(id, rsc_2, rid);
831
832 } else {
833 // Get the first one
835 if (xml_rsc != NULL) {
836 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
837 }
838 }
839 }
840
841 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
842 pcmk__order_resource_actions(rsc_1, action_1, rsc_2, action_2, flags);
843
844 } else if (rsc_1 != NULL) {
845 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
846 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
847
848 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
849 pcmk__order_resource_actions(rsc_1, action_1, rsc_2, action_2,
850 flags);
851 }
852
853 } else if (rsc_2 != NULL) {
854 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
855 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
856
857 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
858 pcmk__order_resource_actions(rsc_1, action_1, rsc_2, action_2,
859 flags);
860 }
861
862 } else {
863 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
864 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
865
866 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
867
868 for (xmlNode *xml_rsc_2 = first_named_child(set2,
870 xml_rsc_2 != NULL; xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
871
872 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
873 pcmk__order_resource_actions(rsc_1, action_1, rsc_2,
874 action_2, flags);
875 }
876 }
877 }
878
879 return pcmk_rc_ok;
880}
881
893static int
894unpack_order_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
896{
897 const char *id_first = NULL;
898 const char *id_then = NULL;
899 const char *action_first = NULL;
900 const char *action_then = NULL;
901
902 pcmk_resource_t *rsc_first = NULL;
903 pcmk_resource_t *rsc_then = NULL;
904 pcmk_tag_t *tag_first = NULL;
905 pcmk_tag_t *tag_then = NULL;
906
907 xmlNode *rsc_set_first = NULL;
908 xmlNode *rsc_set_then = NULL;
909 bool any_sets = false;
910
911 // Check whether there are any resource sets with template or tag references
912 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
913 if (*expanded_xml != NULL) {
914 crm_log_xml_trace(*expanded_xml, "Expanded rsc_order");
915 return pcmk_rc_ok;
916 }
917
918 id_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST);
919 id_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN);
920 if ((id_first == NULL) || (id_then == NULL)) {
921 return pcmk_rc_ok;
922 }
923
924 if (!pcmk__valid_resource_or_tag(scheduler, id_first, &rsc_first,
925 &tag_first)) {
926 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
927 "valid resource or tag", ID(xml_obj), id_first);
929 }
930
931 if (!pcmk__valid_resource_or_tag(scheduler, id_then, &rsc_then,
932 &tag_then)) {
933 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
934 "valid resource or tag", ID(xml_obj), id_then);
936 }
937
938 if ((rsc_first != NULL) && (rsc_then != NULL)) {
939 // Neither side references a template or tag
940 return pcmk_rc_ok;
941 }
942
943 action_first = crm_element_value(xml_obj, XML_ORDER_ATTR_FIRST_ACTION);
944 action_then = crm_element_value(xml_obj, XML_ORDER_ATTR_THEN_ACTION);
945
946 *expanded_xml = copy_xml(xml_obj);
947
948 // Convert template/tag reference in "first" into constraint resource_set
949 if (!pcmk__tag_to_set(*expanded_xml, &rsc_set_first, XML_ORDER_ATTR_FIRST,
950 true, scheduler)) {
951 free_xml(*expanded_xml);
952 *expanded_xml = NULL;
954 }
955
956 if (rsc_set_first != NULL) {
957 if (action_first != NULL) {
958 // Move "first-action" into converted resource_set as "action"
959 crm_xml_add(rsc_set_first, "action", action_first);
961 }
962 any_sets = true;
963 }
964
965 // Convert template/tag reference in "then" into constraint resource_set
966 if (!pcmk__tag_to_set(*expanded_xml, &rsc_set_then, XML_ORDER_ATTR_THEN,
967 true, scheduler)) {
968 free_xml(*expanded_xml);
969 *expanded_xml = NULL;
971 }
972
973 if (rsc_set_then != NULL) {
974 if (action_then != NULL) {
975 // Move "then-action" into converted resource_set as "action"
976 crm_xml_add(rsc_set_then, "action", action_then);
978 }
979 any_sets = true;
980 }
981
982 if (any_sets) {
983 crm_log_xml_trace(*expanded_xml, "Expanded rsc_order");
984 } else {
985 free_xml(*expanded_xml);
986 *expanded_xml = NULL;
987 }
988
989 return pcmk_rc_ok;
990}
991
999void
1001{
1002 xmlNode *set = NULL;
1003 xmlNode *last = NULL;
1004
1005 xmlNode *orig_xml = NULL;
1006 xmlNode *expanded_xml = NULL;
1007
1008 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
1009 const char *invert = crm_element_value(xml_obj, XML_CONS_ATTR_SYMMETRICAL);
1010 enum pe_order_kind kind = get_ordering_type(xml_obj);
1011
1012 enum ordering_symmetry symmetry = get_ordering_symmetry(xml_obj, kind,
1013 NULL);
1014
1015 // Expand any resource tags in the constraint XML
1016 if (unpack_order_tags(xml_obj, &expanded_xml, scheduler) != pcmk_rc_ok) {
1017 return;
1018 }
1019 if (expanded_xml != NULL) {
1020 orig_xml = xml_obj;
1021 xml_obj = expanded_xml;
1022 }
1023
1024 // If the constraint has resource sets, unpack them
1025 for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET);
1026 set != NULL; set = crm_next_same_xml(set)) {
1027
1028 set = expand_idref(set, scheduler->input);
1029 if ((set == NULL) // Configuration error, message already logged
1030 || (unpack_order_set(set, kind, invert, scheduler) != pcmk_rc_ok)) {
1031
1032 if (expanded_xml != NULL) {
1033 free_xml(expanded_xml);
1034 }
1035 return;
1036 }
1037
1038 if (last != NULL) {
1039
1040 if (order_rsc_sets(id, last, set, kind, scheduler,
1041 symmetry) != pcmk_rc_ok) {
1042 if (expanded_xml != NULL) {
1043 free_xml(expanded_xml);
1044 }
1045 return;
1046 }
1047
1048 if ((symmetry == ordering_symmetric)
1049 && (order_rsc_sets(id, set, last, kind, scheduler,
1051 if (expanded_xml != NULL) {
1052 free_xml(expanded_xml);
1053 }
1054 return;
1055 }
1056
1057 }
1058 last = set;
1059 }
1060
1061 if (expanded_xml) {
1062 free_xml(expanded_xml);
1063 xml_obj = orig_xml;
1064 }
1065
1066 // If the constraint has no resource sets, unpack it as a simple ordering
1067 if (last == NULL) {
1068 return unpack_simple_rsc_order(xml_obj, scheduler);
1069 }
1070}
1071
1072static bool
1073ordering_is_invalid(pcmk_action_t *action, pcmk__related_action_t *input)
1074{
1075 /* Prevent user-defined ordering constraints between resources
1076 * running in a guest node and the resource that defines that node.
1077 */
1079 && (input->action->rsc != NULL)
1080 && pcmk__rsc_corresponds_to_guest(action->rsc, input->action->node)) {
1081
1082 crm_warn("Invalid ordering constraint between %s and %s",
1083 input->action->rsc->id, action->rsc->id);
1084 return true;
1085 }
1086
1087 /* If there's an order like
1088 * "rscB_stop node2"-> "load_stopped_node2" -> "rscA_migrate_to node1"
1089 *
1090 * then rscA is being migrated from node1 to node2, while rscB is being
1091 * migrated from node2 to node1. If there would be a graph loop,
1092 * break the order "load_stopped_node2" -> "rscA_migrate_to node1".
1093 */
1094 if (((uint32_t) input->type == pcmk__ar_if_on_same_node_or_target)
1095 && (action->rsc != NULL)
1096 && pcmk__str_eq(action->task, PCMK_ACTION_MIGRATE_TO, pcmk__str_none)
1098 return true;
1099 }
1100
1101 return false;
1102}
1103
1104void
1106{
1107 for (GList *iter = scheduler->actions; iter != NULL; iter = iter->next) {
1108 pcmk_action_t *action = (pcmk_action_t *) iter->data;
1110
1111 for (GList *input_iter = action->actions_before;
1112 input_iter != NULL; input_iter = input_iter->next) {
1113
1114 input = input_iter->data;
1115 if (ordering_is_invalid(action, input)) {
1117 }
1118 }
1119 }
1120}
1121
1129void
1131{
1132 for (GList *iter = node->details->data_set->actions;
1133 iter != NULL; iter = iter->next) {
1134
1135 pcmk_action_t *action = (pcmk_action_t *) iter->data;
1136
1137 // Only stops on the node shutting down are relevant
1138 if (!pe__same_node(action->node, node)
1139 || !pcmk__str_eq(action->task, PCMK_ACTION_STOP, pcmk__str_none)) {
1140 continue;
1141 }
1142
1143 // Resources and nodes in maintenance mode won't be touched
1144
1145 if (pcmk_is_set(action->rsc->flags, pcmk_rsc_maintenance)) {
1146 pe_rsc_trace(action->rsc,
1147 "Not ordering %s before shutdown of %s because "
1148 "resource in maintenance mode",
1149 action->uuid, pe__node_name(node));
1150 continue;
1151
1152 } else if (node->details->maintenance) {
1153 pe_rsc_trace(action->rsc,
1154 "Not ordering %s before shutdown of %s because "
1155 "node in maintenance mode",
1156 action->uuid, pe__node_name(node));
1157 continue;
1158 }
1159
1160 /* Don't touch a resource that is unmanaged or blocked, to avoid
1161 * blocking the shutdown (though if another action depends on this one,
1162 * we may still end up blocking)
1163 */
1164 if (!pcmk_any_flags_set(action->rsc->flags,
1166 pe_rsc_trace(action->rsc,
1167 "Not ordering %s before shutdown of %s because "
1168 "resource is unmanaged or blocked",
1169 action->uuid, pe__node_name(node));
1170 continue;
1171 }
1172
1173 pe_rsc_trace(action->rsc, "Ordering %s before shutdown of %s",
1174 action->uuid, pe__node_name(node));
1176 pcmk__new_ordering(action->rsc, NULL, action, NULL,
1177 strdup(PCMK_ACTION_DO_SHUTDOWN), shutdown_op,
1179 node->details->data_set);
1180 }
1181}
1182
1193static GList *
1194find_actions_by_task(const pcmk_resource_t *rsc, const char *original_key)
1195{
1196 // Search under given task key directly
1197 GList *list = find_actions(rsc->actions, original_key, NULL);
1198
1199 if (list == NULL) {
1200 // Search again using this resource's ID
1201 char *key = NULL;
1202 char *task = NULL;
1203 guint interval_ms = 0;
1204
1205 if (parse_op_key(original_key, NULL, &task, &interval_ms)) {
1206 key = pcmk__op_key(rsc->id, task, interval_ms);
1207 list = find_actions(rsc->actions, key, NULL);
1208 free(key);
1209 free(task);
1210 } else {
1211 crm_err("Invalid operation key (bug?): %s", original_key);
1212 }
1213 }
1214 return list;
1215}
1216
1225static void
1226order_resource_actions_after(pcmk_action_t *first_action,
1227 const pcmk_resource_t *rsc, pe__ordering_t *order)
1228{
1229 GList *then_actions = NULL;
1230 uint32_t flags = pcmk__ar_none;
1231
1232 CRM_CHECK((rsc != NULL) && (order != NULL), return);
1233
1234 flags = order->flags;
1235 pe_rsc_trace(rsc, "Applying ordering %d for 'then' resource %s",
1236 order->id, rsc->id);
1237
1238 if (order->rh_action != NULL) {
1239 then_actions = g_list_prepend(NULL, order->rh_action);
1240
1241 } else {
1242 then_actions = find_actions_by_task(rsc, order->rh_action_task);
1243 }
1244
1245 if (then_actions == NULL) {
1246 pe_rsc_trace(rsc, "Ignoring ordering %d: no %s actions found for %s",
1247 order->id, order->rh_action_task, rsc->id);
1248 return;
1249 }
1250
1251 if ((first_action != NULL) && (first_action->rsc == rsc)
1252 && pcmk_is_set(first_action->flags, pcmk_action_migration_abort)) {
1253
1254 pe_rsc_trace(rsc,
1255 "Detected dangling migration ordering (%s then %s %s)",
1256 first_action->uuid, order->rh_action_task, rsc->id);
1258 }
1259
1260 if ((first_action == NULL)
1262
1263 pe_rsc_debug(rsc,
1264 "Ignoring ordering %d for %s: No first action found",
1265 order->id, rsc->id);
1266 g_list_free(then_actions);
1267 return;
1268 }
1269
1270 for (GList *iter = then_actions; iter != NULL; iter = iter->next) {
1271 pcmk_action_t *then_action_iter = (pcmk_action_t *) iter->data;
1272
1273 if (first_action != NULL) {
1274 order_actions(first_action, then_action_iter, flags);
1275 } else {
1277 crm_warn("%s of %s is unrunnable because there is no %s of %s "
1278 "to order it after", then_action_iter->task, rsc->id,
1279 order->lh_action_task, order->lh_rsc->id);
1280 }
1281 }
1282
1283 g_list_free(then_actions);
1284}
1285
1286static void
1287rsc_order_first(pcmk_resource_t *first_rsc, pe__ordering_t *order)
1288{
1289 GList *first_actions = NULL;
1290 pcmk_action_t *first_action = order->lh_action;
1291 pcmk_resource_t *then_rsc = order->rh_rsc;
1292
1293 CRM_ASSERT(first_rsc != NULL);
1294 pe_rsc_trace(first_rsc, "Applying ordering constraint %d (first: %s)",
1295 order->id, first_rsc->id);
1296
1297 if (first_action != NULL) {
1298 first_actions = g_list_prepend(NULL, first_action);
1299
1300 } else {
1301 first_actions = find_actions_by_task(first_rsc, order->lh_action_task);
1302 }
1303
1304 if ((first_actions == NULL) && (first_rsc == then_rsc)) {
1305 pe_rsc_trace(first_rsc,
1306 "Ignoring constraint %d: first (%s for %s) not found",
1307 order->id, order->lh_action_task, first_rsc->id);
1308
1309 } else if (first_actions == NULL) {
1310 char *key = NULL;
1311 char *op_type = NULL;
1312 guint interval_ms = 0;
1313
1314 parse_op_key(order->lh_action_task, NULL, &op_type, &interval_ms);
1315 key = pcmk__op_key(first_rsc->id, op_type, interval_ms);
1316
1317 if ((first_rsc->fns->state(first_rsc, TRUE) == pcmk_role_stopped)
1318 && pcmk__str_eq(op_type, PCMK_ACTION_STOP, pcmk__str_none)) {
1319 free(key);
1320 pe_rsc_trace(first_rsc,
1321 "Ignoring constraint %d: first (%s for %s) not found",
1322 order->id, order->lh_action_task, first_rsc->id);
1323
1324 } else if ((first_rsc->fns->state(first_rsc,
1325 TRUE) == pcmk_role_unpromoted)
1326 && pcmk__str_eq(op_type, PCMK_ACTION_DEMOTE,
1327 pcmk__str_none)) {
1328 free(key);
1329 pe_rsc_trace(first_rsc,
1330 "Ignoring constraint %d: first (%s for %s) not found",
1331 order->id, order->lh_action_task, first_rsc->id);
1332
1333 } else {
1334 pe_rsc_trace(first_rsc,
1335 "Creating first (%s for %s) for constraint %d ",
1336 order->lh_action_task, first_rsc->id, order->id);
1337 first_action = custom_action(first_rsc, key, op_type, NULL, TRUE,
1338 first_rsc->cluster);
1339 first_actions = g_list_prepend(NULL, first_action);
1340 }
1341
1342 free(op_type);
1343 }
1344
1345 if (then_rsc == NULL) {
1346 if (order->rh_action == NULL) {
1347 pe_rsc_trace(first_rsc, "Ignoring constraint %d: then not found",
1348 order->id);
1349 return;
1350 }
1351 then_rsc = order->rh_action->rsc;
1352 }
1353 for (GList *iter = first_actions; iter != NULL; iter = iter->next) {
1354 first_action = iter->data;
1355
1356 if (then_rsc == NULL) {
1357 order_actions(first_action, order->rh_action, order->flags);
1358
1359 } else {
1360 order_resource_actions_after(first_action, then_rsc, order);
1361 }
1362 }
1363
1364 g_list_free(first_actions);
1365}
1366
1367// GFunc to call pcmk__block_colocation_dependents()
1368static void
1369block_colocation_dependents(gpointer data, gpointer user_data)
1370{
1372}
1373
1374// GFunc to call pcmk__update_action_for_orderings()
1375static void
1376update_action_for_orderings(gpointer data, gpointer user_data)
1377{
1379 (pcmk_scheduler_t *) user_data);
1380}
1381
1388void
1390{
1391 crm_trace("Applying ordering constraints");
1392
1393 /* Ordering constraints need to be processed in the order they were created.
1394 * rsc_order_first() and order_resource_actions_after() require the relevant
1395 * actions to already exist in some cases, but rsc_order_first() will create
1396 * the 'first' action in certain cases. Thus calling rsc_order_first() can
1397 * change the behavior of later-created orderings.
1398 *
1399 * Also, g_list_append() should be avoided for performance reasons, so we
1400 * prepend orderings when creating them and reverse the list here.
1401 *
1402 * @TODO This is brittle and should be carefully redesigned so that the
1403 * order of creation doesn't matter, and the reverse becomes unneeded.
1404 */
1405 sched->ordering_constraints = g_list_reverse(sched->ordering_constraints);
1406
1407 for (GList *iter = sched->ordering_constraints;
1408 iter != NULL; iter = iter->next) {
1409
1410 pe__ordering_t *order = iter->data;
1411 pcmk_resource_t *rsc = order->lh_rsc;
1412
1413 if (rsc != NULL) {
1414 rsc_order_first(rsc, order);
1415 continue;
1416 }
1417
1418 rsc = order->rh_rsc;
1419 if (rsc != NULL) {
1420 order_resource_actions_after(order->lh_action, rsc, order);
1421
1422 } else {
1423 crm_trace("Applying ordering constraint %d (non-resource actions)",
1424 order->id);
1425 order_actions(order->lh_action, order->rh_action, order->flags);
1426 }
1427 }
1428
1429 g_list_foreach(sched->actions, block_colocation_dependents, NULL);
1430
1431 crm_trace("Ordering probes");
1432 pcmk__order_probes(sched);
1433
1434 crm_trace("Updating %d actions", g_list_length(sched->actions));
1435 g_list_foreach(sched->actions, update_action_for_orderings, sched);
1436
1438}
1439
1447void
1449{
1450 const char *after_desc = (after->task == NULL)? after->uuid : after->task;
1451
1452 for (GList *iter = list; iter != NULL; iter = iter->next) {
1453 pcmk_action_t *before = (pcmk_action_t *) iter->data;
1454 const char *before_desc = before->task? before->task : before->uuid;
1455
1456 crm_debug("Ordering %s on %s before %s on %s",
1457 before_desc, pe__node_name(before->node),
1458 after_desc, pe__node_name(after->node));
1459 order_actions(before, after, pcmk__ar_ordered);
1460 }
1461}
1462
1469void
1471{
1472 // Order start and promote after all instances are stopped
1474 rsc, PCMK_ACTION_START,
1479
1480 // Order stop, start, and promote after all instances are demoted
1482 rsc, PCMK_ACTION_STOP,
1485 rsc, PCMK_ACTION_START,
1490
1491 // Order promote after all instances are started
1495
1496 // Order demote after all instances are demoted
1500}
@ pcmk__ar_first_implies_then
@ pcmk__ar_asymmetric
User-configured asymmetric ordering.
@ pcmk__ar_then_implies_first
@ 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_unrunnable_first_blocks
'then' is runnable (and migratable) only if 'first' is runnable
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
@ pcmk__ar_if_on_same_node_or_target
Actions are ordered if on same node (or migration target for migrate_to)
@ pcmk__ar_guest_allowed
Ordering applies even if 'first' runs on guest node created by 'then'.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition actions.c:96
#define PCMK_ACTION_PROMOTED
Definition actions.h:66
#define PCMK_ACTION_STOP
Definition actions.h:74
#define PCMK_ACTION_RUNNING
Definition actions.h:70
pe_ordering
Definition actions.h:346
#define PCMK_ACTION_ONE_OR_MORE
Definition actions.h:64
#define PCMK_ACTION_PROMOTE
Definition actions.h:65
#define PCMK_ACTION_START
Definition actions.h:71
@ pcmk_action_runnable
Whether action is runnable.
Definition actions.h:241
@ pcmk_action_optional
Whether action should not be executed.
Definition actions.h:244
@ pcmk_action_migration_abort
Whether action is a stop to abort a dangling migration.
Definition actions.h:259
@ pcmk_action_min_runnable
Definition actions.h:266
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:58
#define PCMK_ACTION_STOPPED
Definition actions.h:75
#define PCMK_ACTION_CLONE_ONE_OR_MORE
Definition actions.h:47
#define PCMK_ACTION_DEMOTED
Definition actions.h:50
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
#define PCMK_ACTION_DO_SHUTDOWN
Definition actions.h:51
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
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition nvpair.c:878
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition nvpair.c:905
uint64_t flags
Definition remote.c:3
int char2score(const char *score)
Get the integer value of a score string.
Definition scores.c:36
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition strings.c:416
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:99
char data[0]
Definition cpg.c:10
A dumping ground.
G_GNUC_INTERNAL bool pcmk__valid_resource_or_tag(const pcmk_scheduler_t *scheduler, const char *id, pcmk_resource_t **rsc, pcmk_tag_t **tag)
void pcmk__order_migration_equivalents(pe__ordering_t *order)
G_GNUC_INTERNAL void pcmk__block_colocation_dependents(pcmk_action_t *action)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL void pcmk__update_action_for_orderings(pcmk_action_t *action, pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, const pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL bool pcmk__graph_has_loop(const pcmk_action_t *init_action, const pcmk_action_t *action, pcmk__related_action_t *input)
G_GNUC_INTERNAL bool pcmk__rsc_corresponds_to_guest(const pcmk_resource_t *rsc, const pcmk_node_t *node)
G_GNUC_INTERNAL void pcmk__order_probes(pcmk_scheduler_t *scheduler)
#define crm_warn(fmt, args...)
Definition logging.h:380
#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 crm_log_xml_trace(xml, text)
Definition logging.h:393
#define crm_trace(fmt, args...)
Definition logging.h:385
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
#define XML_TAG_RESOURCE_REF
Definition msg_xml.h:234
#define ID(x)
Definition msg_xml.h:474
#define XML_ORDER_ATTR_THEN_INSTANCE
Definition msg_xml.h:388
#define XML_RULE_ATTR_SCORE
Definition msg_xml.h:341
#define XML_CONS_TAG_RSC_SET
Definition msg_xml.h:357
#define XML_ATTR_ID
Definition msg_xml.h:156
#define XML_ORDER_ATTR_THEN_ACTION
Definition msg_xml.h:381
#define XML_ORDER_ATTR_FIRST_INSTANCE
Definition msg_xml.h:385
#define XML_ORDER_ATTR_FIRST
Definition msg_xml.h:378
#define XML_ORDER_ATTR_FIRST_ACTION
Definition msg_xml.h:380
#define XML_ORDER_ATTR_KIND
Definition msg_xml.h:382
#define XML_CONS_ATTR_SYMMETRICAL
Definition msg_xml.h:358
#define XML_ORDER_ATTR_THEN
Definition msg_xml.h:379
#define PCMK_META_CLONE_MIN
Definition msg_xml.h:65
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
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 * action
Definition pcmk_fence.c:30
void pcmk__order_stops_before_shutdown(pcmk_node_t *node, pcmk_action_t *shutdown_op)
void pcmk__apply_orderings(pcmk_scheduler_t *sched)
void pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_action_task, pcmk_action_t *first_action, pcmk_resource_t *then_rsc, char *then_action_task, pcmk_action_t *then_action, uint32_t flags, pcmk_scheduler_t *sched)
#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name)
void pcmk__disable_invalid_orderings(pcmk_scheduler_t *scheduler)
#define handle_restart_type(rsc, kind, flag, flags)
@ pe_order_kind_optional
@ pe_order_kind_mandatory
@ pe_order_kind_serialize
void pcmk__order_after_each(pcmk_action_t *after, GList *list)
ordering_symmetry
@ ordering_symmetric
@ ordering_symmetric_inverse
@ ordering_asymmetric
void pcmk__unpack_ordering(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
void pcmk__promotable_restart_ordering(pcmk_resource_t *rsc)
#define pe_warn_once(pe_wo_bit, fmt...)
Definition internal.h:142
pcmk_action_t * get_pseudo_op(const char *name, pcmk_scheduler_t *scheduler)
GList * find_actions(GList *input, const char *key, const pcmk_node_t *on_node)
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition utils.c:450
pcmk_resource_t * find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
Definition clone.c:227
#define pe__clear_order_flags(order_flags, flags_to_clear)
Definition internal.h:135
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:36
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:37
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
#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
#define ENODATA
@ pcmk_rsc_maintenance
Whether resource, its node, or entire cluster is in maintenance mode.
Definition resources.h:181
@ 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
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_ok
Definition results.h:154
@ pcmk_rc_unpack_error
Definition results.h:118
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:31
@ pcmk_role_stopped
Stopped.
Definition roles.h:29
@ pcmk__wo_order_inst
@ pcmk__wo_require_all
@ pcmk__wo_order_score
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition strings.c:127
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:933
@ pcmk__str_none
pcmk_resource_t * lh_rsc
Definition internal.h:171
pcmk_action_t * lh_action
Definition internal.h:172
pcmk_resource_t * rh_rsc
Definition internal.h:176
pcmk_action_t * rh_action
Definition internal.h:177
Implementation of pcmk_action_t.
Definition actions.h:390
pcmk_node_t * node
Node to execute action on, if any.
Definition actions.h:401
char * uuid
Action key.
Definition actions.h:404
char * task
Action name.
Definition actions.h:403
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
enum pe_ordering type
Definition actions.h:380
Implementation of pcmk_node_t.
Definition nodes.h:130
struct pe_node_shared_s * details
Basic node information.
Definition nodes.h:134
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
GList * actions
Definition resources.h:447
GHashTable * meta
Resource's meta-attributes.
Definition resources.h:471
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_rsc_methods_t * fns
Resource object methods.
Definition resources.h:416
char * id
Resource ID in configuration.
Definition resources.h:400
Configuration tag object.
Definition tags.h:26
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
GList * ordering_constraints
Ordering constraints.
Definition scheduler.h:198
int order_id
ID to use for next created ordering.
Definition scheduler.h:210
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Get resource's current or assigned role.
Definition resources.h:327
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition xml.c:2555
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2484
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 * copy_xml(xmlNode *src_node)
Definition xml.c:789
void xml_remove_prop(xmlNode *obj, const char *name)
Definition xml.c:1696