pacemaker 2.1.8-2.1.8~rc4
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_group.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2024 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdbool.h>
13
14#include <crm/common/xml.h>
15
16#include <pacemaker-internal.h>
18
39 bool stop_if_fail)
40{
41 pcmk_node_t *first_assigned_node = NULL;
42 pcmk_resource_t *first_member = NULL;
43
44 CRM_ASSERT(pcmk__is_group(rsc));
45
47 return rsc->allocated_to; // Assignment already done
48 }
50 pcmk__rsc_debug(rsc, "Assignment dependency loop detected involving %s",
51 rsc->id);
52 return NULL;
53 }
54
55 if (rsc->children == NULL) {
56 // No members to assign
58 return NULL;
59 }
60
62 first_member = (pcmk_resource_t *) rsc->children->data;
63 rsc->role = first_member->role;
64
67 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
68
69 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
70 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
71 pcmk_node_t *node = NULL;
72
73 pcmk__rsc_trace(rsc, "Assigning group %s member %s",
74 rsc->id, member->id);
75 node = member->cmds->assign(member, prefer, stop_if_fail);
76 if (first_assigned_node == NULL) {
77 first_assigned_node = node;
78 }
79 }
80
81 pe__set_next_role(rsc, first_member->next_role, "first group member");
83
85 return NULL;
86 }
87 return first_assigned_node;
88}
89
99static pcmk_action_t *
100create_group_pseudo_op(pcmk_resource_t *group, const char *action)
101{
102 pcmk_action_t *op = custom_action(group, pcmk__op_key(group->id, action, 0),
103 action, NULL, TRUE, group->cluster);
104
106 return op;
107}
108
115void
117{
118 CRM_ASSERT(pcmk__is_group(rsc));
119
120 pcmk__rsc_trace(rsc, "Creating actions for group %s", rsc->id);
121
122 // Create actions for individual group members
123 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
124 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
125
126 member->cmds->create_actions(member);
127 }
128
129 // Create pseudo-actions for group itself to serve as ordering points
130 create_group_pseudo_op(rsc, PCMK_ACTION_START);
131 create_group_pseudo_op(rsc, PCMK_ACTION_RUNNING);
132 create_group_pseudo_op(rsc, PCMK_ACTION_STOP);
133 create_group_pseudo_op(rsc, PCMK_ACTION_STOPPED);
134 if (crm_is_true(g_hash_table_lookup(rsc->meta, PCMK_META_PROMOTABLE))) {
135 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTE);
136 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTED);
137 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTE);
138 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTED);
139 }
140}
141
142// User data for member_internal_constraints()
143struct member_data {
144 // These could be derived from member but this avoids some function calls
145 bool ordered;
146 bool colocated;
147 bool promotable;
148
149 pcmk_resource_t *last_active;
150 pcmk_resource_t *previous_member;
151};
152
160static void
161member_internal_constraints(gpointer data, gpointer user_data)
162{
164 struct member_data *member_data = (struct member_data *) user_data;
165
166 // For ordering demote vs demote or stop vs stop
167 uint32_t down_flags = pcmk__ar_then_implies_first_graphed;
168
169 // For ordering demote vs demoted or stop vs stopped
170 uint32_t post_down_flags = pcmk__ar_first_implies_then_graphed;
171
172 // Create the individual member's implicit constraints
173 member->cmds->internal_constraints(member);
174
175 if (member_data->previous_member == NULL) {
176 // This is first member
177 if (member_data->ordered) {
179 post_down_flags = pcmk__ar_first_implies_then;
180 }
181
182 } else if (member_data->colocated) {
183 uint32_t flags = pcmk__coloc_none;
184
185 if (pcmk_is_set(member->flags, pcmk_rsc_critical)) {
187 }
188
189 // Colocate this member with the previous one
190 pcmk__new_colocation("#group-members", NULL, PCMK_SCORE_INFINITY,
191 member, member_data->previous_member, NULL, NULL,
192 flags);
193 }
194
195 if (member_data->promotable) {
196 // Demote group -> demote member -> group is demoted
198 member, PCMK_ACTION_DEMOTE, down_flags);
201 post_down_flags);
202
203 // Promote group -> promote member -> group is promoted
210 member, PCMK_ACTION_PROMOTE,
212 }
213
214 // Stop group -> stop member -> group is stopped
215 pcmk__order_stops(member->parent, member, down_flags);
218 post_down_flags);
219
220 // Start group -> start member -> group is started
221 pcmk__order_starts(member->parent, member,
228
229 if (!member_data->ordered) {
230 pcmk__order_starts(member->parent, member,
234 if (member_data->promotable) {
236 member, PCMK_ACTION_PROMOTE,
240 }
241
242 } else if (member_data->previous_member == NULL) {
243 pcmk__order_starts(member->parent, member, pcmk__ar_none);
244 if (member_data->promotable) {
246 member, PCMK_ACTION_PROMOTE,
248 }
249
250 } else {
251 // Order this member relative to the previous one
252
253 pcmk__order_starts(member_data->previous_member, member,
256 pcmk__order_stops(member, member_data->previous_member,
258
259 /* In unusual circumstances (such as adding a new member to the middle
260 * of a group with unmanaged later members), this member may be active
261 * while the previous (new) member is inactive. In this situation, the
262 * usual restart orderings will be irrelevant, so we need to order this
263 * member's stop before the previous member's start.
264 */
265 if ((member->running_on != NULL)
266 && (member_data->previous_member->running_on == NULL)) {
268 member_data->previous_member,
272 }
273
274 if (member_data->promotable) {
275 pcmk__order_resource_actions(member_data->previous_member,
276 PCMK_ACTION_PROMOTE, member,
281 member_data->previous_member,
283 }
284 }
285
286 // Make sure partially active groups shut down in sequence
287 if (member->running_on != NULL) {
288 if (member_data->ordered && (member_data->previous_member != NULL)
289 && (member_data->previous_member->running_on == NULL)
290 && (member_data->last_active != NULL)
291 && (member_data->last_active->running_on != NULL)) {
292 pcmk__order_stops(member, member_data->last_active,
294 }
295 member_data->last_active = member;
296 }
297
298 member_data->previous_member = member;
299}
300
307void
309{
310 struct member_data member_data = { false, };
311 const pcmk_resource_t *top = NULL;
312
313 CRM_ASSERT(pcmk__is_group(rsc));
314
315 /* Order group pseudo-actions relative to each other for restarting:
316 * stop group -> group is stopped -> start group -> group is started
317 */
327
328 top = pe__const_top_resource(rsc, false);
329
330 member_data.ordered = pe__group_flag_is_set(rsc, pcmk__group_ordered);
331 member_data.colocated = pe__group_flag_is_set(rsc, pcmk__group_colocated);
332 member_data.promotable = pcmk_is_set(top->flags, pcmk_rsc_promotable);
333 g_list_foreach(rsc->children, member_internal_constraints, &member_data);
334}
335
348static void
349colocate_group_with(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
350 const pcmk__colocation_t *colocation)
351{
352 pcmk_resource_t *member = NULL;
353
354 if (dependent->children == NULL) {
355 return;
356 }
357
358 pcmk__rsc_trace(primary, "Processing %s (group %s with %s) for dependent",
359 colocation->id, dependent->id, primary->id);
360
362 // Colocate first member (internal colocations will handle the rest)
363 member = (pcmk_resource_t *) dependent->children->data;
364 member->cmds->apply_coloc_score(member, primary, colocation, true);
365 return;
366 }
367
368 if (colocation->score >= PCMK_SCORE_INFINITY) {
369 pcmk__config_err("%s: Cannot perform mandatory colocation between "
370 "non-colocated group and %s",
371 dependent->id, primary->id);
372 return;
373 }
374
375 // Colocate each member individually
376 for (GList *iter = dependent->children; iter != NULL; iter = iter->next) {
377 member = (pcmk_resource_t *) iter->data;
378 member->cmds->apply_coloc_score(member, primary, colocation, true);
379 }
380}
381
394static void
395colocate_with_group(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
396 const pcmk__colocation_t *colocation)
397{
398 const pcmk_resource_t *member = NULL;
399
400 pcmk__rsc_trace(primary,
401 "Processing colocation %s (%s with group %s) for primary",
402 colocation->id, dependent->id, primary->id);
403
404 if (pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
405 return;
406 }
407
409
410 if (colocation->score >= PCMK_SCORE_INFINITY) {
411 /* For mandatory colocations, the entire group must be assignable
412 * (and in the specified role if any), so apply the colocation based
413 * on the last member.
414 */
415 member = pe__last_group_member(primary);
416 } else if (primary->children != NULL) {
417 /* For optional colocations, whether the group is partially or fully
418 * up doesn't matter, so apply the colocation based on the first
419 * member.
420 */
421 member = (pcmk_resource_t *) primary->children->data;
422 }
423 if (member == NULL) {
424 return; // Nothing to colocate with
425 }
426
427 member->cmds->apply_coloc_score(dependent, member, colocation, false);
428 return;
429 }
430
431 if (colocation->score >= PCMK_SCORE_INFINITY) {
432 pcmk__config_err("%s: Cannot perform mandatory colocation with"
433 " non-colocated group %s",
434 dependent->id, primary->id);
435 return;
436 }
437
438 // Colocate dependent with each member individually
439 for (const GList *iter = primary->children; iter != NULL;
440 iter = iter->next) {
441 member = iter->data;
442 member->cmds->apply_coloc_score(dependent, member, colocation, false);
443 }
444}
445
459void
461 const pcmk_resource_t *primary,
462 const pcmk__colocation_t *colocation,
463 bool for_dependent)
464{
465 CRM_ASSERT((dependent != NULL) && (primary != NULL)
466 && (colocation != NULL));
467
468 if (for_dependent) {
469 colocate_group_with(dependent, primary, colocation);
470
471 } else {
472 // Method should only be called for primitive dependents
473 CRM_ASSERT(pcmk__is_primitive(dependent));
474
475 colocate_with_group(dependent, primary, colocation);
476 }
477}
478
488uint32_t
490{
491 // Default flags for a group action
492 uint32_t flags = pcmk_action_optional
495
496 CRM_ASSERT(action != NULL);
497
498 // Update flags considering each member's own flags for same action
499 for (GList *iter = action->rsc->children; iter != NULL; iter = iter->next) {
500 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
501
502 // Check whether member has the same action
503 enum action_tasks task = get_complex_task(member, action->task);
504 const char *task_s = pcmk_action_text(task);
505 pcmk_action_t *member_action = find_first_action(member->actions, NULL,
506 task_s, node);
507
508 if (member_action != NULL) {
509 uint32_t member_flags = member->cmds->action_flags(member_action,
510 node);
511
512 // Group action is mandatory if any member action is
514 && !pcmk_is_set(member_flags, pcmk_action_optional)) {
515 pcmk__rsc_trace(action->rsc, "%s is mandatory because %s is",
516 action->uuid, member_action->uuid);
517 pcmk__clear_raw_action_flags(flags, "group action",
520 }
521
522 // Group action is unrunnable if any member action is
523 if (!pcmk__str_eq(task_s, action->task, pcmk__str_none)
525 && !pcmk_is_set(member_flags, pcmk_action_runnable)) {
526
527 pcmk__rsc_trace(action->rsc, "%s is unrunnable because %s is",
528 action->uuid, member_action->uuid);
529 pcmk__clear_raw_action_flags(flags, "group action",
532 }
533
534 /* Group (pseudo-)actions other than stop or demote are unrunnable
535 * unless every member will do it.
536 */
537 } else if ((task != pcmk_action_stop) && (task != pcmk_action_demote)) {
539 "%s is not runnable because %s will not %s",
540 action->uuid, member->id, task_s);
541 pcmk__clear_raw_action_flags(flags, "group action",
543 }
544 }
545
546 return flags;
547}
548
571uint32_t
573 const pcmk_node_t *node, uint32_t flags,
574 uint32_t filter, uint32_t type,
576{
577 uint32_t changed = pcmk__updated_none;
578
579 // Group method can be called only on behalf of "then" action
580 CRM_ASSERT((first != NULL) && (then != NULL) && (then->rsc != NULL)
581 && (scheduler != NULL));
582
583 // Update the actions for the group itself
584 changed |= pcmk__update_ordered_actions(first, then, node, flags, filter,
585 type, scheduler);
586
587 // Update the actions for each group member
588 for (GList *iter = then->rsc->children; iter != NULL; iter = iter->next) {
589 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
590
591 pcmk_action_t *member_action = find_first_action(member->actions, NULL,
592 then->task, node);
593
594 if (member_action != NULL) {
595 changed |= member->cmds->update_ordered_actions(first,
596 member_action, node,
597 flags, filter, type,
598 scheduler);
599 }
600 }
601 return changed;
602}
603
611void
613{
614 GList *node_list_orig = NULL;
615 GList *node_list_copy = NULL;
616
617 CRM_ASSERT(pcmk__is_group(rsc) && (location != NULL));
618
619 // Save the constraint's original node list (with the constraint score)
620 node_list_orig = location->nodes;
621
622 // Make a copy of the nodes with all zero scores
623 node_list_copy = pcmk__copy_node_list(node_list_orig, true);
624
625 /* Apply the constraint to the group itself. This ensures that any nodes
626 * affected by the constraint are in the group's allowed nodes, with the
627 * constraint score added.
628 */
629 pcmk__apply_location(rsc, location);
630
631 // Apply the constraint for each member
632 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
633 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
634
636 && (iter != rsc->children)) {
637 /* When apply_location() is called below for the first member (iter
638 * == rsc->children), the constraint score will be added to
639 * the member's affected allowed nodes.
640 *
641 * For subsequent members, we reset the constraint's node table to
642 * the copy with all 0 scores. Otherwise, when assigning the member,
643 * the constraint score would be counted multiple times (once for
644 * each later member) due to internal group colocations. Though the
645 * 0 score will not affect these members' allowed node scores, it
646 * ensures that affected nodes are in each member's allowed nodes,
647 * enabling the member on those nodes in asymmetric clusters.
648 */
649 location->nodes = node_list_copy;
650 }
651
652 member->cmds->apply_location(member, location);
653 }
654
655 location->nodes = node_list_orig;
656 g_list_free_full(node_list_copy, free);
657}
658
659// Group implementation of pcmk_assignment_methods_t:colocated_resources()
660GList *
662 const pcmk_resource_t *orig_rsc,
663 GList *colocated_rscs)
664{
665 const pcmk_resource_t *member = NULL;
666
667 CRM_ASSERT(pcmk__is_group(rsc));
668
669 if (orig_rsc == NULL) {
670 orig_rsc = rsc;
671 }
672
674 || pcmk__is_clone(rsc->parent)) {
675 /* This group has colocated members and/or is cloned -- either way,
676 * add every child's colocated resources to the list. The first and last
677 * members will include the group's own colocations.
678 */
679 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
680 for (const GList *iter = rsc->children;
681 iter != NULL; iter = iter->next) {
682
683 member = (const pcmk_resource_t *) iter->data;
684 colocated_rscs = member->cmds->colocated_resources(member, orig_rsc,
685 colocated_rscs);
686 }
687
688 } else if (rsc->children != NULL) {
689 /* This group's members are not colocated, and the group is not cloned,
690 * so just add the group's own colocations to the list.
691 */
692 colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc,
693 colocated_rscs);
694 }
695
696 return colocated_rscs;
697}
698
699// Group implementation of pcmk_assignment_methods_t:with_this_colocations()
700void
702 const pcmk_resource_t *orig_rsc, GList **list)
703
704{
705 CRM_ASSERT((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
706
707 // Ignore empty groups
708 if (rsc->children == NULL) {
709 return;
710 }
711
712 /* "With this" colocations are needed only for the group itself and for its
713 * last member. (Previous members will chain via the group internal
714 * colocations.)
715 */
716 if ((orig_rsc != rsc) && (orig_rsc != pe__last_group_member(rsc))) {
717 return;
718 }
719
720 pcmk__rsc_trace(rsc, "Adding 'with %s' colocations to list for %s",
721 rsc->id, orig_rsc->id);
722
723 // Add the group's own colocations
724 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
725
726 // If cloned, add any relevant colocations with the clone
727 if (rsc->parent != NULL) {
728 rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc,
729 list);
730 }
731
733 // @COMPAT Non-colocated groups are deprecated
734 return;
735 }
736
737 // Add explicit colocations with the group's (other) children
738 for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
739 const pcmk_resource_t *member = iter->data;
740
741 if (member != orig_rsc) {
742 member->cmds->with_this_colocations(member, orig_rsc, list);
743 }
744 }
745}
746
747// Group implementation of pcmk_assignment_methods_t:this_with_colocations()
748void
750 const pcmk_resource_t *orig_rsc, GList **list)
751{
752 const pcmk_resource_t *member = NULL;
753
754 CRM_ASSERT((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
755
756 // Ignore empty groups
757 if (rsc->children == NULL) {
758 return;
759 }
760
761 /* "This with" colocations are normally needed only for the group itself and
762 * for its first member.
763 */
764 if ((rsc == orig_rsc)
765 || (orig_rsc == (const pcmk_resource_t *) rsc->children->data)) {
766 pcmk__rsc_trace(rsc, "Adding '%s with' colocations to list for %s",
767 rsc->id, orig_rsc->id);
768
769 // Add the group's own colocations
770 pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
771
772 // If cloned, add any relevant colocations involving the clone
773 if (rsc->parent != NULL) {
774 rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc,
775 list);
776 }
777
779 // @COMPAT Non-colocated groups are deprecated
780 return;
781 }
782
783 // Add explicit colocations involving the group's (other) children
784 for (const GList *iter = rsc->children;
785 iter != NULL; iter = iter->next) {
786 member = iter->data;
787 if (member != orig_rsc) {
788 member->cmds->this_with_colocations(member, orig_rsc, list);
789 }
790 }
791 return;
792 }
793
794 /* Later group members honor the group's colocations indirectly, due to the
795 * internal group colocations that chain everything from the first member.
796 * However, if an earlier group member is unmanaged, this chaining will not
797 * happen, so the group's mandatory colocations must be explicitly added.
798 */
799 for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
800 member = iter->data;
801 if (orig_rsc == member) {
802 break; // We've seen all earlier members, and none are unmanaged
803 }
804
805 if (!pcmk_is_set(member->flags, pcmk_rsc_managed)) {
806 crm_trace("Adding mandatory '%s with' colocations to list for "
807 "member %s because earlier member %s is unmanaged",
808 rsc->id, orig_rsc->id, member->id);
809 for (const GList *cons_iter = rsc->rsc_cons; cons_iter != NULL;
810 cons_iter = cons_iter->next) {
811 const pcmk__colocation_t *colocation = NULL;
812
813 colocation = (const pcmk__colocation_t *) cons_iter->data;
814 if (colocation->score == PCMK_SCORE_INFINITY) {
815 pcmk__add_this_with(list, colocation, orig_rsc);
816 }
817 }
818 // @TODO Add mandatory (or all?) clone constraints if cloned
819 break;
820 }
821 }
822}
823
854void
856 const pcmk_resource_t *target_rsc,
857 const char *log_id, GHashTable **nodes,
858 const pcmk__colocation_t *colocation,
859 float factor, uint32_t flags)
860{
861 pcmk_resource_t *member = NULL;
862
863 CRM_ASSERT(pcmk__is_group(source_rsc) && (nodes != NULL)
864 && ((colocation != NULL)
865 || ((target_rsc == NULL) && (*nodes == NULL))));
866
867 if (log_id == NULL) {
868 log_id = source_rsc->id;
869 }
870
871 // Avoid infinite recursion
872 if (pcmk_is_set(source_rsc->flags, pcmk_rsc_updating_nodes)) {
873 pcmk__rsc_info(source_rsc, "%s: Breaking dependency loop at %s",
874 log_id, source_rsc->id);
875 return;
876 }
878
879 // Ignore empty groups (only possible with schema validation disabled)
880 if (source_rsc->children == NULL) {
881 return;
882 }
883
884 /* Refer the operation to the first or last member as appropriate.
885 *
886 * cmp_resources() is the only caller that passes a NULL nodes table,
887 * and is also the only caller using pcmk__coloc_select_this_with.
888 * For "this with" colocations, the last member will recursively incorporate
889 * all the other members' "this with" colocations via the internal group
890 * colocations (and via the first member, the group's own colocations).
891 *
892 * For "with this" colocations, the first member works similarly.
893 */
894 if (*nodes == NULL) {
895 member = pe__last_group_member(source_rsc);
896 } else {
897 member = source_rsc->children->data;
898 }
899 pcmk__rsc_trace(source_rsc, "%s: Merging scores from group %s using member %s "
900 "(at %.6f)", log_id, source_rsc->id, member->id, factor);
901 member->cmds->add_colocated_node_scores(member, target_rsc, log_id, nodes,
902 colocation, factor, flags);
904}
905
906// Group implementation of pcmk_assignment_methods_t:add_utilization()
907void
909 const pcmk_resource_t *orig_rsc, GList *all_rscs,
910 GHashTable *utilization)
911{
912 pcmk_resource_t *member = NULL;
913
914 CRM_ASSERT((orig_rsc != NULL) && (utilization != NULL)
915 && pcmk__is_group(rsc));
916
918 return;
919 }
920
921 pcmk__rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
922 orig_rsc->id, rsc->id);
924 || pcmk__is_clone(rsc->parent)) {
925 // Every group member will be on same node, so sum all members
926 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
927 member = (pcmk_resource_t *) iter->data;
928
930 && (g_list_find(all_rscs, member) == NULL)) {
931 member->cmds->add_utilization(member, orig_rsc, all_rscs,
932 utilization);
933 }
934 }
935
936 } else if (rsc->children != NULL) {
937 // Just add first member's utilization
938 member = (pcmk_resource_t *) rsc->children->data;
939 if ((member != NULL)
941 && (g_list_find(all_rscs, member) == NULL)) {
942
943 member->cmds->add_utilization(member, orig_rsc, all_rscs,
944 utilization);
945 }
946 }
947}
948
949void
951{
952 CRM_ASSERT(pcmk__is_group(rsc));
953
954 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
955 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
956
957 member->cmds->shutdown_lock(member);
958 }
959}
@ pcmk__ar_first_implies_then
@ pcmk__ar_then_implies_first
@ pcmk__ar_intermediate_stop
@ pcmk__ar_then_implies_first_graphed
If 'then' is required, 'first' must be added to the transition graph.
@ 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)
#define pcmk__set_relation_flags(ar_flags, flags_to_set)
#define PCMK_ACTION_PROMOTED
Definition actions.h:67
#define PCMK_ACTION_STOP
Definition actions.h:75
#define PCMK_ACTION_RUNNING
Definition actions.h:71
#define PCMK_ACTION_PROMOTE
Definition actions.h:66
#define PCMK_ACTION_START
Definition actions.h:72
@ pcmk_action_runnable
Definition actions.h:207
@ pcmk_action_pseudo
Definition actions.h:204
@ pcmk_action_optional
Definition actions.h:210
action_tasks
Definition actions.h:83
@ pcmk_action_demote
Definition actions.h:101
@ pcmk_action_stop
Definition actions.h:89
#define PCMK_ACTION_STOPPED
Definition actions.h:76
const char * pcmk_action_text(enum action_tasks action)
Get string equivalent of an action type.
Definition actions.c:37
#define PCMK_ACTION_DEMOTED
Definition actions.h:50
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
#define pcmk__clear_raw_action_flags(action_flags, action_name, to_clear)
#define pcmk__set_action_flags(action, flags_to_set)
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition actions.c:196
#define pcmk__clear_action_flags(action, flags_to_clear)
uint64_t flags
Definition remote.c:3
gboolean crm_is_true(const char *s)
Definition strings.c:488
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:100
enum crm_ais_msg_types type
Definition cpg.c:3
char data[0]
Definition cpg.c:10
@ pcmk__group_colocated
@ pcmk__group_ordered
G_GNUC_INTERNAL void pcmk__add_this_with_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
#define pcmk__order_starts(rsc1, rsc2, flags)
G_GNUC_INTERNAL void pcmk__new_colocation(const char *id, const char *node_attr, int score, pcmk_resource_t *dependent, pcmk_resource_t *primary, const char *dependent_role, const char *primary_role, uint32_t flags)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL 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)
@ pcmk__coloc_none
@ pcmk__coloc_influence
G_GNUC_INTERNAL void pcmk__add_this_with(GList **list, const pcmk__colocation_t *colocation, const pcmk_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__add_with_this_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
G_GNUC_INTERNAL GList * pcmk__colocated_resources(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *colocated_rscs)
@ pcmk__updated_none
#define pcmk__order_stops(rsc1, rsc2, flags)
G_GNUC_INTERNAL void pcmk__apply_location(pcmk_resource_t *rsc, pcmk__location_t *constraint)
#define crm_trace(fmt, args...)
Definition logging.h:402
#define pcmk__config_err(fmt...)
pcmk_scheduler_t * scheduler
#define PCMK_META_PROMOTABLE
Definition options.h:101
const char * action
Definition pcmk_fence.c:30
void pcmk__group_add_colocated_node_scores(pcmk_resource_t *source_rsc, const pcmk_resource_t *target_rsc, const char *log_id, GHashTable **nodes, const pcmk__colocation_t *colocation, float factor, uint32_t flags)
void pcmk__with_group_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
void pcmk__group_internal_constraints(pcmk_resource_t *rsc)
pcmk_node_t * pcmk__group_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
void pcmk__group_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
GList * pcmk__group_colocated_resources(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *colocated_rscs)
void pcmk__group_shutdown_lock(pcmk_resource_t *rsc)
uint32_t pcmk__group_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)
void pcmk__group_add_utilization(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void pcmk__group_with_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
void pcmk__group_create_actions(pcmk_resource_t *rsc)
uint32_t pcmk__group_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
void pcmk__group_apply_coloc_score(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
GList * pcmk__copy_node_list(const GList *list, bool reset)
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1032
pcmk_resource_t * pe__last_group_member(const pcmk_resource_t *group)
Definition group.c:37
#define pe__show_node_scores(level, rsc, text, nodes, scheduler)
Definition internal.h:176
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
void pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition complex.c:1253
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.
enum action_tasks get_complex_task(const pcmk_resource_t *rsc, const char *name)
bool pe__group_flag_is_set(const pcmk_resource_t *group, uint32_t flags)
Definition group.c:57
@ pcmk_rsc_promotable
Definition resources.h:106
@ pcmk_rsc_unassigned
Definition resources.h:109
@ pcmk_rsc_assigning
Definition resources.h:112
@ pcmk_rsc_critical
Definition resources.h:130
@ pcmk_rsc_updating_nodes
Definition resources.h:115
@ pcmk_rsc_managed
Definition resources.h:88
#define CRM_ASSERT(expr)
Definition results.h:42
#define pcmk__set_rsc_flags(resource, flags_to_set)
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
@ pcmk_sched_output_scores
Definition scheduler.h:173
#define pcmk__rsc_info(rsc, fmt, args...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__rsc_debug(rsc, fmt, args...)
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:24
@ pcmk__str_none
Location constraint object.
char * uuid
Definition actions.h:344
char * task
Definition actions.h:343
pcmk_resource_t * rsc
Definition actions.h:340
pcmk_assignment_methods_t * cmds
Definition resources.h:413
GList * running_on
Definition resources.h:456
GList * actions
Definition resources.h:444
GHashTable * meta
Definition resources.h:467
GList * rsc_cons
Definition resources.h:442
GList * rsc_cons_lhs
Definition resources.h:441
GList * children
Definition resources.h:471
pcmk_scheduler_t * cluster
Definition resources.h:408
pcmk_node_t * allocated_to
Definition resources.h:447
GHashTable * allowed_nodes
Definition resources.h:462
unsigned long long flags
Definition resources.h:428
enum rsc_role_e next_role
Definition resources.h:465
enum rsc_role_e role
Definition resources.h:464
pcmk_resource_t * parent
Definition resources.h:409
unsigned long long flags
Definition scheduler.h:211
void(* create_actions)(pcmk_resource_t *rsc)
void(* add_utilization)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void(* shutdown_lock)(pcmk_resource_t *rsc)
void(* this_with_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
GList *(* colocated_resources)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *colocated_rscs)
uint32_t(* action_flags)(pcmk_action_t *action, const pcmk_node_t *node)
void(* with_this_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
void(* internal_constraints)(pcmk_resource_t *rsc)
pcmk_node_t *(* assign)(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
void(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void(* add_colocated_node_scores)(pcmk_resource_t *source_rsc, const pcmk_resource_t *target_rsc, const char *log_id, GHashTable **nodes, const pcmk__colocation_t *colocation, float factor, uint32_t flags)
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)
void(* apply_location)(pcmk_resource_t *rsc, pcmk__location_t *location)
Wrappers for and extensions to libxml2.