pacemaker 2.1.8-2.1.8
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 <qb/qbdefs.h> // QB_ABS()
15
16#include <crm/common/xml.h>
17
18#include <pacemaker-internal.h>
20
41 bool stop_if_fail)
42{
43 pcmk_node_t *first_assigned_node = NULL;
44 pcmk_resource_t *first_member = NULL;
45
46 CRM_ASSERT(pcmk__is_group(rsc));
47
49 return rsc->allocated_to; // Assignment already done
50 }
52 pcmk__rsc_debug(rsc, "Assignment dependency loop detected involving %s",
53 rsc->id);
54 return NULL;
55 }
56
57 if (rsc->children == NULL) {
58 // No members to assign
60 return NULL;
61 }
62
64 first_member = (pcmk_resource_t *) rsc->children->data;
65 rsc->role = first_member->role;
66
69 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
70
71 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
72 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
73 pcmk_node_t *node = NULL;
74
75 pcmk__rsc_trace(rsc, "Assigning group %s member %s",
76 rsc->id, member->id);
77 node = member->cmds->assign(member, prefer, stop_if_fail);
78 if (first_assigned_node == NULL) {
79 first_assigned_node = node;
80 }
81 }
82
83 pe__set_next_role(rsc, first_member->next_role, "first group member");
85
87 return NULL;
88 }
89 return first_assigned_node;
90}
91
101static pcmk_action_t *
102create_group_pseudo_op(pcmk_resource_t *group, const char *action)
103{
104 pcmk_action_t *op = custom_action(group, pcmk__op_key(group->id, action, 0),
105 action, NULL, TRUE, group->cluster);
106
108 return op;
109}
110
117void
119{
120 CRM_ASSERT(pcmk__is_group(rsc));
121
122 pcmk__rsc_trace(rsc, "Creating actions for group %s", rsc->id);
123
124 // Create actions for individual group members
125 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
126 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
127
128 member->cmds->create_actions(member);
129 }
130
131 // Create pseudo-actions for group itself to serve as ordering points
132 create_group_pseudo_op(rsc, PCMK_ACTION_START);
133 create_group_pseudo_op(rsc, PCMK_ACTION_RUNNING);
134 create_group_pseudo_op(rsc, PCMK_ACTION_STOP);
135 create_group_pseudo_op(rsc, PCMK_ACTION_STOPPED);
136 if (crm_is_true(g_hash_table_lookup(rsc->meta, PCMK_META_PROMOTABLE))) {
137 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTE);
138 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTED);
139 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTE);
140 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTED);
141 }
142}
143
144// User data for member_internal_constraints()
145struct member_data {
146 // These could be derived from member but this avoids some function calls
147 bool ordered;
148 bool colocated;
149 bool promotable;
150
151 pcmk_resource_t *last_active;
152 pcmk_resource_t *previous_member;
153};
154
162static void
163member_internal_constraints(gpointer data, gpointer user_data)
164{
166 struct member_data *member_data = (struct member_data *) user_data;
167
168 // For ordering demote vs demote or stop vs stop
169 uint32_t down_flags = pcmk__ar_then_implies_first_graphed;
170
171 // For ordering demote vs demoted or stop vs stopped
172 uint32_t post_down_flags = pcmk__ar_first_implies_then_graphed;
173
174 // Create the individual member's implicit constraints
175 member->cmds->internal_constraints(member);
176
177 if (member_data->previous_member == NULL) {
178 // This is first member
179 if (member_data->ordered) {
181 post_down_flags = pcmk__ar_first_implies_then;
182 }
183
184 } else if (member_data->colocated) {
185 uint32_t flags = pcmk__coloc_none;
186
187 if (pcmk_is_set(member->flags, pcmk_rsc_critical)) {
189 }
190
191 // Colocate this member with the previous one
192 pcmk__new_colocation("#group-members", NULL, PCMK_SCORE_INFINITY,
193 member, member_data->previous_member, NULL, NULL,
194 flags);
195 }
196
197 if (member_data->promotable) {
198 // Demote group -> demote member -> group is demoted
200 member, PCMK_ACTION_DEMOTE, down_flags);
203 post_down_flags);
204
205 // Promote group -> promote member -> group is promoted
212 member, PCMK_ACTION_PROMOTE,
214 }
215
216 // Stop group -> stop member -> group is stopped
217 pcmk__order_stops(member->parent, member, down_flags);
220 post_down_flags);
221
222 // Start group -> start member -> group is started
223 pcmk__order_starts(member->parent, member,
230
231 if (!member_data->ordered) {
232 pcmk__order_starts(member->parent, member,
236 if (member_data->promotable) {
238 member, PCMK_ACTION_PROMOTE,
242 }
243
244 } else if (member_data->previous_member == NULL) {
245 pcmk__order_starts(member->parent, member, pcmk__ar_none);
246 if (member_data->promotable) {
248 member, PCMK_ACTION_PROMOTE,
250 }
251
252 } else {
253 // Order this member relative to the previous one
254
255 pcmk__order_starts(member_data->previous_member, member,
258 pcmk__order_stops(member, member_data->previous_member,
260
261 /* In unusual circumstances (such as adding a new member to the middle
262 * of a group with unmanaged later members), this member may be active
263 * while the previous (new) member is inactive. In this situation, the
264 * usual restart orderings will be irrelevant, so we need to order this
265 * member's stop before the previous member's start.
266 */
267 if ((member->running_on != NULL)
268 && (member_data->previous_member->running_on == NULL)) {
270 member_data->previous_member,
274 }
275
276 if (member_data->promotable) {
277 pcmk__order_resource_actions(member_data->previous_member,
278 PCMK_ACTION_PROMOTE, member,
283 member_data->previous_member,
285 }
286 }
287
288 // Make sure partially active groups shut down in sequence
289 if (member->running_on != NULL) {
290 if (member_data->ordered && (member_data->previous_member != NULL)
291 && (member_data->previous_member->running_on == NULL)
292 && (member_data->last_active != NULL)
293 && (member_data->last_active->running_on != NULL)) {
294 pcmk__order_stops(member, member_data->last_active,
296 }
297 member_data->last_active = member;
298 }
299
300 member_data->previous_member = member;
301}
302
309void
311{
312 struct member_data member_data = { false, };
313 const pcmk_resource_t *top = NULL;
314
315 CRM_ASSERT(pcmk__is_group(rsc));
316
317 /* Order group pseudo-actions relative to each other for restarting:
318 * stop group -> group is stopped -> start group -> group is started
319 */
329
330 top = pe__const_top_resource(rsc, false);
331
332 member_data.ordered = pe__group_flag_is_set(rsc, pcmk__group_ordered);
333 member_data.colocated = pe__group_flag_is_set(rsc, pcmk__group_colocated);
334 member_data.promotable = pcmk_is_set(top->flags, pcmk_rsc_promotable);
335 g_list_foreach(rsc->children, member_internal_constraints, &member_data);
336}
337
352static int
353colocate_group_with(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
354 const pcmk__colocation_t *colocation)
355{
356 int priority_delta = 0;
357
358 if (dependent->children == NULL) {
359 return 0;
360 }
361
362 pcmk__rsc_trace(primary, "Processing %s (group %s with %s) for dependent",
363 colocation->id, dependent->id, primary->id);
364
366 // Colocate first member (internal colocations will handle the rest)
367 pcmk_resource_t *member = dependent->children->data;
368
369 priority_delta = member->cmds->apply_coloc_score(member, primary,
370 colocation, true);
371
372 } else {
373 if (colocation->score >= PCMK_SCORE_INFINITY) {
374 pcmk__config_err("%s: Cannot perform mandatory colocation between "
375 "non-colocated group and %s",
376 dependent->id, primary->id);
377 return 0;
378 }
379
380 // Colocate each member individually
381 for (GList *iter = dependent->children; iter != NULL;
382 iter = iter->next) {
383
384 pcmk_resource_t *member = iter->data;
385 int instance_delta = member->cmds->apply_coloc_score(member,
386 primary,
387 colocation,
388 false);
389
390 /* priority_delta is used for determining which instances of a
391 * promotable clone to promote. It's possible that colocations
392 * involving promotable cloned non-colocated groups may not behave
393 * correctly in all circumstances. Non-colocated groups are
394 * deprecated, and testing focused on colocated groups.
395 */
396 priority_delta = pcmk__add_scores(priority_delta, instance_delta);
397 }
398 }
399
400 if (priority_delta != 0) {
401 dependent->priority = pcmk__add_scores(priority_delta,
402 dependent->priority);
403
404 pcmk__rsc_trace(dependent,
405 "Applied %s to %s promotion priority "
406 "(now %s after %s %d)",
407 colocation->id, dependent->id,
408 pcmk_readable_score(dependent->priority),
409 ((priority_delta > 0)? "adding" : "subtracting"),
410 QB_ABS(priority_delta));
411 }
412 return priority_delta;
413}
414
429static int
430colocate_with_group(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
431 const pcmk__colocation_t *colocation)
432{
433 int priority_delta = 0;
434 const pcmk_resource_t *member = NULL;
435
436 pcmk__rsc_trace(primary,
437 "Processing colocation %s (%s with group %s) for primary",
438 colocation->id, dependent->id, primary->id);
439
440 if (pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
441 return 0;
442 }
443
445
446 if (colocation->score >= PCMK_SCORE_INFINITY) {
447 /* For mandatory colocations, the entire group must be assignable
448 * (and in the specified role if any), so apply the colocation based
449 * on the last member.
450 */
451 member = pe__last_group_member(primary);
452 } else if (primary->children != NULL) {
453 /* For optional colocations, whether the group is partially or fully
454 * up doesn't matter, so apply the colocation based on the first
455 * member.
456 */
457 member = (pcmk_resource_t *) primary->children->data;
458 }
459 if (member == NULL) {
460 return 0; // Nothing to colocate with
461 }
462
463 return member->cmds->apply_coloc_score(dependent, member, colocation,
464 false);
465 }
466
467 if (colocation->score >= PCMK_SCORE_INFINITY) {
468 pcmk__config_err("%s: Cannot perform mandatory colocation with"
469 " non-colocated group %s",
470 dependent->id, primary->id);
471 return 0;
472 }
473
474 // Colocate dependent with each member individually
475 for (const GList *iter = primary->children; iter != NULL;
476 iter = iter->next) {
477
478 int instance_delta = 0;
479
480 member = iter->data;
481 instance_delta = member->cmds->apply_coloc_score(dependent, member,
482 colocation, false);
483 priority_delta = pcmk__add_scores(priority_delta, instance_delta);
484 }
485 return priority_delta;
486}
487
503int
505 const pcmk_resource_t *primary,
506 const pcmk__colocation_t *colocation,
507 bool for_dependent)
508{
509 CRM_ASSERT((dependent != NULL) && (primary != NULL)
510 && (colocation != NULL));
511
512 if (for_dependent) {
513 return colocate_group_with(dependent, primary, colocation);
514
515 } else {
516 // Method should only be called for primitive dependents
517 CRM_ASSERT(pcmk__is_primitive(dependent));
518
519 return colocate_with_group(dependent, primary, colocation);
520 }
521}
522
532uint32_t
534{
535 // Default flags for a group action
536 uint32_t flags = pcmk_action_optional
539
540 CRM_ASSERT(action != NULL);
541
542 // Update flags considering each member's own flags for same action
543 for (GList *iter = action->rsc->children; iter != NULL; iter = iter->next) {
544 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
545
546 // Check whether member has the same action
547 enum action_tasks task = get_complex_task(member, action->task);
548 const char *task_s = pcmk_action_text(task);
549 pcmk_action_t *member_action = find_first_action(member->actions, NULL,
550 task_s, node);
551
552 if (member_action != NULL) {
553 uint32_t member_flags = member->cmds->action_flags(member_action,
554 node);
555
556 // Group action is mandatory if any member action is
558 && !pcmk_is_set(member_flags, pcmk_action_optional)) {
559 pcmk__rsc_trace(action->rsc, "%s is mandatory because %s is",
560 action->uuid, member_action->uuid);
561 pcmk__clear_raw_action_flags(flags, "group action",
564 }
565
566 // Group action is unrunnable if any member action is
567 if (!pcmk__str_eq(task_s, action->task, pcmk__str_none)
569 && !pcmk_is_set(member_flags, pcmk_action_runnable)) {
570
571 pcmk__rsc_trace(action->rsc, "%s is unrunnable because %s is",
572 action->uuid, member_action->uuid);
573 pcmk__clear_raw_action_flags(flags, "group action",
576 }
577
578 /* Group (pseudo-)actions other than stop or demote are unrunnable
579 * unless every member will do it.
580 */
581 } else if ((task != pcmk_action_stop) && (task != pcmk_action_demote)) {
583 "%s is not runnable because %s will not %s",
584 action->uuid, member->id, task_s);
585 pcmk__clear_raw_action_flags(flags, "group action",
587 }
588 }
589
590 return flags;
591}
592
615uint32_t
617 const pcmk_node_t *node, uint32_t flags,
618 uint32_t filter, uint32_t type,
620{
621 uint32_t changed = pcmk__updated_none;
622
623 // Group method can be called only on behalf of "then" action
624 CRM_ASSERT((first != NULL) && (then != NULL) && (then->rsc != NULL)
625 && (scheduler != NULL));
626
627 // Update the actions for the group itself
628 changed |= pcmk__update_ordered_actions(first, then, node, flags, filter,
629 type, scheduler);
630
631 // Update the actions for each group member
632 for (GList *iter = then->rsc->children; iter != NULL; iter = iter->next) {
633 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
634
635 pcmk_action_t *member_action = find_first_action(member->actions, NULL,
636 then->task, node);
637
638 if (member_action != NULL) {
639 changed |= member->cmds->update_ordered_actions(first,
640 member_action, node,
641 flags, filter, type,
642 scheduler);
643 }
644 }
645 return changed;
646}
647
655void
657{
658 GList *node_list_orig = NULL;
659 GList *node_list_copy = NULL;
660
661 CRM_ASSERT(pcmk__is_group(rsc) && (location != NULL));
662
663 // Save the constraint's original node list (with the constraint score)
664 node_list_orig = location->nodes;
665
666 // Make a copy of the nodes with all zero scores
667 node_list_copy = pcmk__copy_node_list(node_list_orig, true);
668
669 /* Apply the constraint to the group itself. This ensures that any nodes
670 * affected by the constraint are in the group's allowed nodes, with the
671 * constraint score added.
672 */
673 pcmk__apply_location(rsc, location);
674
675 // Apply the constraint for each member
676 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
677 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
678
680 && (iter != rsc->children)) {
681 /* When apply_location() is called below for the first member (iter
682 * == rsc->children), the constraint score will be added to
683 * the member's affected allowed nodes.
684 *
685 * For subsequent members, we reset the constraint's node table to
686 * the copy with all 0 scores. Otherwise, when assigning the member,
687 * the constraint score would be counted multiple times (once for
688 * each later member) due to internal group colocations. Though the
689 * 0 score will not affect these members' allowed node scores, it
690 * ensures that affected nodes are in each member's allowed nodes,
691 * enabling the member on those nodes in asymmetric clusters.
692 */
693 location->nodes = node_list_copy;
694 }
695
696 member->cmds->apply_location(member, location);
697 }
698
699 location->nodes = node_list_orig;
700 g_list_free_full(node_list_copy, free);
701}
702
703// Group implementation of pcmk_assignment_methods_t:colocated_resources()
704GList *
706 const pcmk_resource_t *orig_rsc,
707 GList *colocated_rscs)
708{
709 const pcmk_resource_t *member = NULL;
710
711 CRM_ASSERT(pcmk__is_group(rsc));
712
713 if (orig_rsc == NULL) {
714 orig_rsc = rsc;
715 }
716
718 || pcmk__is_clone(rsc->parent)) {
719 /* This group has colocated members and/or is cloned -- either way,
720 * add every child's colocated resources to the list. The first and last
721 * members will include the group's own colocations.
722 */
723 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
724 for (const GList *iter = rsc->children;
725 iter != NULL; iter = iter->next) {
726
727 member = (const pcmk_resource_t *) iter->data;
728 colocated_rscs = member->cmds->colocated_resources(member, orig_rsc,
729 colocated_rscs);
730 }
731
732 } else if (rsc->children != NULL) {
733 /* This group's members are not colocated, and the group is not cloned,
734 * so just add the group's own colocations to the list.
735 */
736 colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc,
737 colocated_rscs);
738 }
739
740 return colocated_rscs;
741}
742
743// Group implementation of pcmk_assignment_methods_t:with_this_colocations()
744void
746 const pcmk_resource_t *orig_rsc, GList **list)
747
748{
749 CRM_ASSERT((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
750
751 // Ignore empty groups
752 if (rsc->children == NULL) {
753 return;
754 }
755
756 /* "With this" colocations are needed only for the group itself and for its
757 * last member. (Previous members will chain via the group internal
758 * colocations.)
759 */
760 if ((orig_rsc != rsc) && (orig_rsc != pe__last_group_member(rsc))) {
761 return;
762 }
763
764 pcmk__rsc_trace(rsc, "Adding 'with %s' colocations to list for %s",
765 rsc->id, orig_rsc->id);
766
767 // Add the group's own colocations
768 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
769
770 // If cloned, add any relevant colocations with the clone
771 if (rsc->parent != NULL) {
772 rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc,
773 list);
774 }
775
777 // @COMPAT Non-colocated groups are deprecated
778 return;
779 }
780
781 // Add explicit colocations with the group's (other) children
782 for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
783 const pcmk_resource_t *member = iter->data;
784
785 if (member != orig_rsc) {
786 member->cmds->with_this_colocations(member, orig_rsc, list);
787 }
788 }
789}
790
791// Group implementation of pcmk_assignment_methods_t:this_with_colocations()
792void
794 const pcmk_resource_t *orig_rsc, GList **list)
795{
796 const pcmk_resource_t *member = NULL;
797
798 CRM_ASSERT((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
799
800 // Ignore empty groups
801 if (rsc->children == NULL) {
802 return;
803 }
804
805 /* "This with" colocations are normally needed only for the group itself and
806 * for its first member.
807 */
808 if ((rsc == orig_rsc)
809 || (orig_rsc == (const pcmk_resource_t *) rsc->children->data)) {
810 pcmk__rsc_trace(rsc, "Adding '%s with' colocations to list for %s",
811 rsc->id, orig_rsc->id);
812
813 // Add the group's own colocations
814 pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
815
816 // If cloned, add any relevant colocations involving the clone
817 if (rsc->parent != NULL) {
818 rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc,
819 list);
820 }
821
823 // @COMPAT Non-colocated groups are deprecated
824 return;
825 }
826
827 // Add explicit colocations involving the group's (other) children
828 for (const GList *iter = rsc->children;
829 iter != NULL; iter = iter->next) {
830 member = iter->data;
831 if (member != orig_rsc) {
832 member->cmds->this_with_colocations(member, orig_rsc, list);
833 }
834 }
835 return;
836 }
837
838 /* Later group members honor the group's colocations indirectly, due to the
839 * internal group colocations that chain everything from the first member.
840 * However, if an earlier group member is unmanaged, this chaining will not
841 * happen, so the group's mandatory colocations must be explicitly added.
842 */
843 for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
844 member = iter->data;
845 if (orig_rsc == member) {
846 break; // We've seen all earlier members, and none are unmanaged
847 }
848
849 if (!pcmk_is_set(member->flags, pcmk_rsc_managed)) {
850 crm_trace("Adding mandatory '%s with' colocations to list for "
851 "member %s because earlier member %s is unmanaged",
852 rsc->id, orig_rsc->id, member->id);
853 for (const GList *cons_iter = rsc->rsc_cons; cons_iter != NULL;
854 cons_iter = cons_iter->next) {
855 const pcmk__colocation_t *colocation = NULL;
856
857 colocation = (const pcmk__colocation_t *) cons_iter->data;
858 if (colocation->score == PCMK_SCORE_INFINITY) {
859 pcmk__add_this_with(list, colocation, orig_rsc);
860 }
861 }
862 // @TODO Add mandatory (or all?) clone constraints if cloned
863 break;
864 }
865 }
866}
867
898void
900 const pcmk_resource_t *target_rsc,
901 const char *log_id, GHashTable **nodes,
902 const pcmk__colocation_t *colocation,
903 float factor, uint32_t flags)
904{
905 pcmk_resource_t *member = NULL;
906
907 CRM_ASSERT(pcmk__is_group(source_rsc) && (nodes != NULL)
908 && ((colocation != NULL)
909 || ((target_rsc == NULL) && (*nodes == NULL))));
910
911 if (log_id == NULL) {
912 log_id = source_rsc->id;
913 }
914
915 // Avoid infinite recursion
916 if (pcmk_is_set(source_rsc->flags, pcmk_rsc_updating_nodes)) {
917 pcmk__rsc_info(source_rsc, "%s: Breaking dependency loop at %s",
918 log_id, source_rsc->id);
919 return;
920 }
922
923 // Ignore empty groups (only possible with schema validation disabled)
924 if (source_rsc->children == NULL) {
925 return;
926 }
927
928 /* Refer the operation to the first or last member as appropriate.
929 *
930 * cmp_resources() is the only caller that passes a NULL nodes table,
931 * and is also the only caller using pcmk__coloc_select_this_with.
932 * For "this with" colocations, the last member will recursively incorporate
933 * all the other members' "this with" colocations via the internal group
934 * colocations (and via the first member, the group's own colocations).
935 *
936 * For "with this" colocations, the first member works similarly.
937 */
938 if (*nodes == NULL) {
939 member = pe__last_group_member(source_rsc);
940 } else {
941 member = source_rsc->children->data;
942 }
943 pcmk__rsc_trace(source_rsc, "%s: Merging scores from group %s using member %s "
944 "(at %.6f)", log_id, source_rsc->id, member->id, factor);
945 member->cmds->add_colocated_node_scores(member, target_rsc, log_id, nodes,
946 colocation, factor, flags);
948}
949
950// Group implementation of pcmk_assignment_methods_t:add_utilization()
951void
953 const pcmk_resource_t *orig_rsc, GList *all_rscs,
954 GHashTable *utilization)
955{
956 pcmk_resource_t *member = NULL;
957
958 CRM_ASSERT((orig_rsc != NULL) && (utilization != NULL)
959 && pcmk__is_group(rsc));
960
962 return;
963 }
964
965 pcmk__rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
966 orig_rsc->id, rsc->id);
968 || pcmk__is_clone(rsc->parent)) {
969 // Every group member will be on same node, so sum all members
970 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
971 member = (pcmk_resource_t *) iter->data;
972
974 && (g_list_find(all_rscs, member) == NULL)) {
975 member->cmds->add_utilization(member, orig_rsc, all_rscs,
976 utilization);
977 }
978 }
979
980 } else if (rsc->children != NULL) {
981 // Just add first member's utilization
982 member = (pcmk_resource_t *) rsc->children->data;
983 if ((member != NULL)
985 && (g_list_find(all_rscs, member) == NULL)) {
986
987 member->cmds->add_utilization(member, orig_rsc, all_rscs,
988 utilization);
989 }
990 }
991}
992
993void
995{
996 CRM_ASSERT(pcmk__is_group(rsc));
997
998 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
999 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
1000
1001 member->cmds->shutdown_lock(member);
1002 }
1003}
@ 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:98
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)
int pcmk__group_apply_coloc_score(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
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)
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...)
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition scores.c:86
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:24
int pcmk__add_scores(int score1, int score2)
Definition scores.c:116
@ 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)
int(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
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(* 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.