pacemaker 3.0.1-16e74fc4da
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 pcmk__assert(pcmk__is_group(rsc));
47
49 return rsc->priv->assigned_node; // 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->priv->children == NULL) {
58 // No members to assign
60 return NULL;
61 }
62
64 first_member = (pcmk_resource_t *) rsc->priv->children->data;
65 rsc->priv->orig_role = first_member->priv->orig_role;
66
69 rsc, __func__, rsc->priv->allowed_nodes,
70 rsc->priv->scheduler);
71
72 for (GList *iter = rsc->priv->children;
73 iter != NULL; iter = iter->next) {
74
75 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
76 pcmk_node_t *node = NULL;
77
78 pcmk__rsc_trace(rsc, "Assigning group %s member %s",
79 rsc->id, member->id);
80 node = member->priv->cmds->assign(member, prefer, stop_if_fail);
81 if (first_assigned_node == NULL) {
82 first_assigned_node = node;
83 }
84 }
85
86 pe__set_next_role(rsc, first_member->priv->next_role,
87 "first group member");
89
91 return NULL;
92 }
93 return first_assigned_node;
94}
95
105static pcmk_action_t *
106create_group_pseudo_op(pcmk_resource_t *group, const char *action)
107{
108 pcmk_action_t *op = custom_action(group, pcmk__op_key(group->id, action, 0),
109 action, NULL, TRUE,
110 group->priv->scheduler);
111
113 return op;
114}
115
122void
124{
125 pcmk__assert(pcmk__is_group(rsc));
126
127 pcmk__rsc_trace(rsc, "Creating actions for group %s", rsc->id);
128
129 // Create actions for individual group members
130 for (GList *iter = rsc->priv->children;
131 iter != NULL; iter = iter->next) {
132
133 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
134
135 member->priv->cmds->create_actions(member);
136 }
137
138 // Create pseudo-actions for group itself to serve as ordering points
139 create_group_pseudo_op(rsc, PCMK_ACTION_START);
140 create_group_pseudo_op(rsc, PCMK_ACTION_RUNNING);
141 create_group_pseudo_op(rsc, PCMK_ACTION_STOP);
142 create_group_pseudo_op(rsc, PCMK_ACTION_STOPPED);
143 if (crm_is_true(g_hash_table_lookup(rsc->priv->meta,
145 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTE);
146 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTED);
147 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTE);
148 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTED);
149 }
150}
151
152// User data for member_internal_constraints()
153struct member_data {
154 // These could be derived from member but this avoids some function calls
155 bool ordered;
156 bool colocated;
157 bool promotable;
158
159 pcmk_resource_t *last_active;
160 pcmk_resource_t *previous_member;
161};
162
170static void
171member_internal_constraints(gpointer data, gpointer user_data)
172{
174 struct member_data *member_data = (struct member_data *) user_data;
175
176 // For ordering demote vs demote or stop vs stop
177 uint32_t down_flags = pcmk__ar_then_implies_first_graphed;
178
179 // For ordering demote vs demoted or stop vs stopped
180 uint32_t post_down_flags = pcmk__ar_first_implies_then_graphed;
181
182 // Create the individual member's implicit constraints
183 member->priv->cmds->internal_constraints(member);
184
185 if (member_data->previous_member == NULL) {
186 // This is first member
187 if (member_data->ordered) {
189 post_down_flags = pcmk__ar_first_implies_then;
190 }
191
192 } else if (member_data->colocated) {
193 uint32_t flags = pcmk__coloc_none;
194
195 if (pcmk_is_set(member->flags, pcmk__rsc_critical)) {
197 }
198
199 // Colocate this member with the previous one
200 pcmk__new_colocation("#group-members", NULL, PCMK_SCORE_INFINITY,
201 member, member_data->previous_member, NULL, NULL,
202 flags);
203 }
204
205 if (member_data->promotable) {
206 // Demote group -> demote member -> group is demoted
209 member, PCMK_ACTION_DEMOTE, down_flags);
211 member->priv->parent,
212 PCMK_ACTION_DEMOTED, post_down_flags);
213
214 // Promote group -> promote member -> group is promoted
216 member->priv->parent,
223 member, PCMK_ACTION_PROMOTE,
225 }
226
227 // Stop group -> stop member -> group is stopped
228 pcmk__order_stops(member->priv->parent, member, down_flags);
231 post_down_flags);
232
233 // Start group -> start member -> group is started
234 pcmk__order_starts(member->priv->parent, member,
241
242 if (!member_data->ordered) {
243 pcmk__order_starts(member->priv->parent, member,
247 if (member_data->promotable) {
250 member, PCMK_ACTION_PROMOTE,
254 }
255
256 } else if (member_data->previous_member == NULL) {
257 pcmk__order_starts(member->priv->parent, member, pcmk__ar_none);
258 if (member_data->promotable) {
261 member, PCMK_ACTION_PROMOTE,
263 }
264
265 } else {
266 // Order this member relative to the previous one
267
268 pcmk__order_starts(member_data->previous_member, member,
271 pcmk__order_stops(member, member_data->previous_member,
273
274 /* In unusual circumstances (such as adding a new member to the middle
275 * of a group with unmanaged later members), this member may be active
276 * while the previous (new) member is inactive. In this situation, the
277 * usual restart orderings will be irrelevant, so we need to order this
278 * member's stop before the previous member's start.
279 */
280 if ((member->priv->active_nodes != NULL)
281 && (member_data->previous_member->priv->active_nodes == NULL)) {
283 member_data->previous_member,
287 }
288
289 if (member_data->promotable) {
290 pcmk__order_resource_actions(member_data->previous_member,
291 PCMK_ACTION_PROMOTE, member,
296 member_data->previous_member,
298 }
299 }
300
301 // Make sure partially active groups shut down in sequence
302 if (member->priv->active_nodes != NULL) {
303 if (member_data->ordered && (member_data->previous_member != NULL)
304 && (member_data->previous_member->priv->active_nodes == NULL)
305 && (member_data->last_active != NULL)
306 && (member_data->last_active->priv->active_nodes != NULL)) {
307 pcmk__order_stops(member, member_data->last_active,
309 }
310 member_data->last_active = member;
311 }
312
313 member_data->previous_member = member;
314}
315
322void
324{
325 struct member_data member_data = { false, };
326 const pcmk_resource_t *top = NULL;
327
328 pcmk__assert(pcmk__is_group(rsc));
329
330 /* Order group pseudo-actions relative to each other for restarting:
331 * stop group -> group is stopped -> start group -> group is started
332 */
342
343 top = pe__const_top_resource(rsc, false);
344
345 member_data.ordered = pe__group_flag_is_set(rsc, pcmk__group_ordered);
346 member_data.colocated = pe__group_flag_is_set(rsc, pcmk__group_colocated);
347 member_data.promotable = pcmk_is_set(top->flags, pcmk__rsc_promotable);
348 g_list_foreach(rsc->priv->children, member_internal_constraints,
349 &member_data);
350}
351
366static int
367colocate_group_with(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
368 const pcmk__colocation_t *colocation)
369{
370 int priority_delta = 0;
371
372 if (dependent->priv->children == NULL) {
373 return 0;
374 }
375
376 pcmk__rsc_trace(primary, "Processing %s (group %s with %s) for dependent",
377 colocation->id, dependent->id, primary->id);
378
380 // Colocate first member (internal colocations will handle the rest)
381 pcmk_resource_t *member = dependent->priv->children->data;
382 priority_delta = member->priv->cmds->apply_coloc_score(member, primary,
383 colocation,
384 true);
385
386 } else {
387 if (colocation->score >= PCMK_SCORE_INFINITY) {
388 pcmk__config_err("%s: Cannot perform mandatory colocation between "
389 "non-colocated group and %s",
390 dependent->id, primary->id);
391 return 0;
392 }
393
394 // Colocate each member individually
395 for (GList *iter = dependent->priv->children; iter != NULL;
396 iter = iter->next) {
397
398 int instance_delta = 0;
399 pcmk_resource_t *member = iter->data;
400
401 instance_delta =
402 member->priv->cmds->apply_coloc_score(member, primary,
403 colocation, false);
404
405 /* priority_delta is used for determining which instances of a
406 * promotable clone to promote. It's possible that colocations
407 * involving promotable cloned non-colocated groups may not behave
408 * correctly in all circumstances. Non-colocated groups are
409 * deprecated, and testing focused on colocated groups.
410 */
411 priority_delta = pcmk__add_scores(priority_delta, instance_delta);
412 }
413 }
414
415 if (priority_delta != 0) {
416 dependent->priv->priority =
417 pcmk__add_scores(priority_delta, dependent->priv->priority);
418
419 pcmk__rsc_trace(dependent,
420 "Applied %s to %s promotion priority "
421 "(now %s after %s %d)",
422 colocation->id, dependent->id,
423 pcmk_readable_score(dependent->priv->priority),
424 ((priority_delta > 0)? "adding" : "subtracting"),
425 QB_ABS(priority_delta));
426 }
427 return priority_delta;
428}
429
444static int
445colocate_with_group(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
446 const pcmk__colocation_t *colocation)
447{
448 int priority_delta = 0;
449 const pcmk_resource_t *member = NULL;
450
451 pcmk__rsc_trace(primary,
452 "Processing colocation %s (%s with group %s) for primary",
453 colocation->id, dependent->id, primary->id);
454
455 if (pcmk_is_set(primary->flags, pcmk__rsc_unassigned)) {
456 return 0;
457 }
458
460
461 if (colocation->score >= PCMK_SCORE_INFINITY) {
462 /* For mandatory colocations, the entire group must be assignable
463 * (and in the specified role if any), so apply the colocation based
464 * on the last member.
465 */
466 member = pe__last_group_member(primary);
467 } else if (primary->priv->children != NULL) {
468 /* For optional colocations, whether the group is partially or fully
469 * up doesn't matter, so apply the colocation based on the first
470 * member.
471 */
472 member = (pcmk_resource_t *) primary->priv->children->data;
473 }
474 if (member == NULL) {
475 return 0; // Nothing to colocate with
476 }
477
478 return member->priv->cmds->apply_coloc_score(dependent, member,
479 colocation, false);
480 }
481
482 if (colocation->score >= PCMK_SCORE_INFINITY) {
483 pcmk__config_err("%s: Cannot perform mandatory colocation with"
484 " non-colocated group %s",
485 dependent->id, primary->id);
486 return 0;
487 }
488
489 // Colocate dependent with each member individually
490 for (const GList *iter = primary->priv->children;
491 iter != NULL; iter = iter->next) {
492
493 int instance_delta = 0;
494
495 member = iter->data;
496 instance_delta = member->priv->cmds->apply_coloc_score(dependent,
497 member,
498 colocation,
499 false);
500 priority_delta = pcmk__add_scores(priority_delta, instance_delta);
501 }
502 return priority_delta;
503}
504
520int
522 const pcmk_resource_t *primary,
523 const pcmk__colocation_t *colocation,
524 bool for_dependent)
525{
526 pcmk__assert((dependent != NULL) && (primary != NULL)
527 && (colocation != NULL));
528
529 if (for_dependent) {
530 return colocate_group_with(dependent, primary, colocation);
531
532 } else {
533 // Method should only be called for primitive dependents
534 pcmk__assert(pcmk__is_primitive(dependent));
535
536 return colocate_with_group(dependent, primary, colocation);
537 }
538}
539
549uint32_t
551{
552 // Default flags for a group action
556
557 pcmk__assert(action != NULL);
558
559 // Update flags considering each member's own flags for same action
560 for (GList *iter = action->rsc->priv->children;
561 iter != NULL; iter = iter->next) {
562
563 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
564
565 // Check whether member has the same action
566 enum pcmk__action_type task = get_complex_task(member, action->task);
567 const char *task_s = pcmk__action_text(task);
568 pcmk_action_t *member_action = NULL;
569
570 member_action = find_first_action(member->priv->actions, NULL,
571 task_s, node);
572 if (member_action != NULL) {
573 uint32_t member_flags = 0U;
574
575 member_flags = member->priv->cmds->action_flags(member_action,
576 node);
577
578 // Group action is mandatory if any member action is
580 && !pcmk_is_set(member_flags, pcmk__action_optional)) {
581 pcmk__rsc_trace(action->rsc, "%s is mandatory because %s is",
582 action->uuid, member_action->uuid);
583 pcmk__clear_raw_action_flags(flags, "group action",
586 }
587
588 // Group action is unrunnable if any member action is
589 if (!pcmk__str_eq(task_s, action->task, pcmk__str_none)
591 && !pcmk_is_set(member_flags, pcmk__action_runnable)) {
592
593 pcmk__rsc_trace(action->rsc, "%s is unrunnable because %s is",
594 action->uuid, member_action->uuid);
595 pcmk__clear_raw_action_flags(flags, "group action",
598 }
599
600 /* Group (pseudo-)actions other than stop or demote are unrunnable
601 * unless every member will do it.
602 */
603 } else if ((task != pcmk__action_stop)
604 && (task != pcmk__action_demote)) {
606 "%s is not runnable because %s will not %s",
607 action->uuid, member->id, task_s);
608 pcmk__clear_raw_action_flags(flags, "group action",
610 }
611 }
612
613 return flags;
614}
615
638uint32_t
640 const pcmk_node_t *node, uint32_t flags,
641 uint32_t filter, uint32_t type,
643{
644 uint32_t changed = pcmk__updated_none;
645
646 // Group method can be called only on behalf of "then" action
647 pcmk__assert((first != NULL) && (then != NULL) && (then->rsc != NULL)
648 && (scheduler != NULL));
649
650 // Update the actions for the group itself
651 changed |= pcmk__update_ordered_actions(first, then, node, flags, filter,
652 type, scheduler);
653
654 // Update the actions for each group member
655 for (GList *iter = then->rsc->priv->children;
656 iter != NULL; iter = iter->next) {
657
658 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
659 pcmk_action_t *member_action = NULL;
660
661 member_action = find_first_action(member->priv->actions, NULL,
662 then->task, node);
663 if (member_action == NULL) {
664 continue;
665 }
666 changed |= member->priv->cmds->update_ordered_actions(first,
667 member_action,
668 node, flags,
669 filter, type,
670 scheduler);
671 }
672 return changed;
673}
674
682void
684{
685 GList *node_list_orig = NULL;
686 GList *node_list_copy = NULL;
687
688 pcmk__assert(pcmk__is_group(rsc) && (location != NULL));
689
690 // Save the constraint's original node list (with the constraint score)
691 node_list_orig = location->nodes;
692
693 // Make a copy of the nodes with all zero scores
694 node_list_copy = pcmk__copy_node_list(node_list_orig, true);
695
696 /* Apply the constraint to the group itself. This ensures that any nodes
697 * affected by the constraint are in the group's allowed nodes, with the
698 * constraint score added.
699 */
700 pcmk__apply_location(rsc, location);
701
702 // Apply the constraint for each member
703 for (GList *iter = rsc->priv->children;
704 iter != NULL; iter = iter->next) {
705
706 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
707
709 && (iter != rsc->priv->children)) {
710 /* When apply_location() is called below for the first member (iter
711 * == rsc->priv->children), the constraint score will be added to
712 * the member's affected allowed nodes.
713 *
714 * For subsequent members, we reset the constraint's node table to
715 * the copy with all 0 scores. Otherwise, when assigning the member,
716 * the constraint score would be counted multiple times (once for
717 * each later member) due to internal group colocations. Though the
718 * 0 score will not affect these members' allowed node scores, it
719 * ensures that affected nodes are in each member's allowed nodes,
720 * enabling the member on those nodes in asymmetric clusters.
721 */
722 location->nodes = node_list_copy;
723 }
724
725 member->priv->cmds->apply_location(member, location);
726 }
727
728 location->nodes = node_list_orig;
729 g_list_free_full(node_list_copy, pcmk__free_node_copy);
730}
731
732// Group implementation of pcmk__assignment_methods_t:colocated_resources()
733GList *
735 const pcmk_resource_t *orig_rsc,
736 GList *colocated_rscs)
737{
738 pcmk__assert(pcmk__is_group(rsc));
739
740 if (orig_rsc == NULL) {
741 orig_rsc = rsc;
742 }
743
745 || pcmk__is_clone(rsc->priv->parent)) {
746 /* This group has colocated members and/or is cloned -- either way,
747 * add every child's colocated resources to the list. The first and last
748 * members will include the group's own colocations.
749 */
750 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
751
752 for (const GList *iter = rsc->priv->children;
753 iter != NULL; iter = iter->next) {
754
755 const pcmk_resource_t *member = iter->data;
756
757 colocated_rscs = member->priv->cmds->colocated_resources(member,
758 orig_rsc,
759 colocated_rscs);
760 }
761
762 } else if (rsc->priv->children != NULL) {
763 /* This group's members are not colocated, and the group is not cloned,
764 * so just add the group's own colocations to the list.
765 */
766 colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc,
767 colocated_rscs);
768 }
769
770 return colocated_rscs;
771}
772
773// Group implementation of pcmk__assignment_methods_t:with_this_colocations()
774void
776 const pcmk_resource_t *orig_rsc, GList **list)
777
778{
779 const pcmk_resource_t *parent = NULL;
780
781 pcmk__assert((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
782 parent = rsc->priv->parent;
783
784 // Ignore empty groups
785 if (rsc->priv->children == NULL) {
786 return;
787 }
788
789 /* "With this" colocations are needed only for the group itself and for its
790 * last member. (Previous members will chain via the group internal
791 * colocations.)
792 */
793 if ((orig_rsc != rsc) && (orig_rsc != pe__last_group_member(rsc))) {
794 return;
795 }
796
797 pcmk__rsc_trace(rsc, "Adding 'with %s' colocations to list for %s",
798 rsc->id, orig_rsc->id);
799
800 // Add the group's own colocations
802 orig_rsc);
803
804 // If cloned, add any relevant colocations with the clone
805 if (parent != NULL) {
806 parent->priv->cmds->with_this_colocations(parent, orig_rsc, list);
807 }
808
810 // @COMPAT Non-colocated groups are deprecated
811 return;
812 }
813
814 // Add explicit colocations with the group's (other) children
815 for (const GList *iter = rsc->priv->children;
816 iter != NULL; iter = iter->next) {
817
818 const pcmk_resource_t *member = iter->data;
819
820 if (member == orig_rsc) {
821 continue;
822 }
823 member->priv->cmds->with_this_colocations(member, orig_rsc, list);
824 }
825}
826
827// Group implementation of pcmk__assignment_methods_t:this_with_colocations()
828void
830 const pcmk_resource_t *orig_rsc, GList **list)
831{
832 const pcmk_resource_t *parent = NULL;
833 const pcmk_resource_t *member = NULL;
834
835 pcmk__assert((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
836 parent = rsc->priv->parent;
837
838 // Ignore empty groups
839 if (rsc->priv->children == NULL) {
840 return;
841 }
842
843 /* "This with" colocations are normally needed only for the group itself and
844 * for its first member.
845 */
846 if ((rsc == orig_rsc) || (orig_rsc == rsc->priv->children->data)) {
847 pcmk__rsc_trace(rsc, "Adding '%s with' colocations to list for %s",
848 rsc->id, orig_rsc->id);
849
850 // Add the group's own colocations
852 orig_rsc);
853
854 // If cloned, add any relevant colocations involving the clone
855 if (parent != NULL) {
856 parent->priv->cmds->this_with_colocations(parent, orig_rsc, list);
857 }
858
860 // @COMPAT Non-colocated groups are deprecated
861 return;
862 }
863
864 // Add explicit colocations involving the group's (other) children
865 for (const GList *iter = rsc->priv->children;
866 iter != NULL; iter = iter->next) {
867
868 member = iter->data;
869 if (member == orig_rsc) {
870 continue;
871 }
872 member->priv->cmds->this_with_colocations(member, orig_rsc, list);
873 }
874 return;
875 }
876
877 /* Later group members honor the group's colocations indirectly, due to the
878 * internal group colocations that chain everything from the first member.
879 * However, if an earlier group member is unmanaged, this chaining will not
880 * happen, so the group's mandatory colocations must be explicitly added.
881 */
882 for (const GList *iter = rsc->priv->children;
883 iter != NULL; iter = iter->next) {
884
885 member = iter->data;
886 if (orig_rsc == member) {
887 break; // We've seen all earlier members, and none are unmanaged
888 }
889
890 if (!pcmk_is_set(member->flags, pcmk__rsc_managed)) {
891 crm_trace("Adding mandatory '%s with' colocations to list for "
892 "member %s because earlier member %s is unmanaged",
893 rsc->id, orig_rsc->id, member->id);
894 for (const GList *cons_iter = rsc->priv->this_with_colocations;
895 cons_iter != NULL; cons_iter = cons_iter->next) {
896 const pcmk__colocation_t *colocation = NULL;
897
898 colocation = (const pcmk__colocation_t *) cons_iter->data;
899 if (colocation->score == PCMK_SCORE_INFINITY) {
900 pcmk__add_this_with(list, colocation, orig_rsc);
901 }
902 }
903 // @TODO Add mandatory (or all?) clone constraints if cloned
904 break;
905 }
906 }
907}
908
939void
941 const pcmk_resource_t *target_rsc,
942 const char *log_id, GHashTable **nodes,
943 const pcmk__colocation_t *colocation,
944 float factor, uint32_t flags)
945{
946 pcmk_resource_t *member = NULL;
947
948 pcmk__assert(pcmk__is_group(source_rsc) && (nodes != NULL)
949 && ((colocation != NULL)
950 || ((target_rsc == NULL) && (*nodes == NULL))));
951
952 if (log_id == NULL) {
953 log_id = source_rsc->id;
954 }
955
956 // Avoid infinite recursion
957 if (pcmk_is_set(source_rsc->flags, pcmk__rsc_updating_nodes)) {
958 pcmk__rsc_info(source_rsc, "%s: Breaking dependency loop at %s",
959 log_id, source_rsc->id);
960 return;
961 }
963
964 // Ignore empty groups (only possible with schema validation disabled)
965 if (source_rsc->priv->children == NULL) {
966 return;
967 }
968
969 /* Refer the operation to the first or last member as appropriate.
970 *
971 * cmp_resources() is the only caller that passes a NULL nodes table,
972 * and is also the only caller using pcmk__coloc_select_this_with.
973 * For "this with" colocations, the last member will recursively incorporate
974 * all the other members' "this with" colocations via the internal group
975 * colocations (and via the first member, the group's own colocations).
976 *
977 * For "with this" colocations, the first member works similarly.
978 */
979 if (*nodes == NULL) {
980 member = pe__last_group_member(source_rsc);
981 } else {
982 member = source_rsc->priv->children->data;
983 }
984
985 pcmk__rsc_trace(source_rsc, "%s: Merging scores from group %s using member %s "
986 "(at %.6f)", log_id, source_rsc->id, member->id, factor);
987 member->priv->cmds->add_colocated_node_scores(member, target_rsc, log_id,
988 nodes, colocation, factor,
989 flags);
991}
992
993// Group implementation of pcmk__assignment_methods_t:add_utilization()
994void
996 const pcmk_resource_t *orig_rsc, GList *all_rscs,
997 GHashTable *utilization)
998{
999 pcmk_resource_t *member = NULL;
1000
1001 pcmk__assert((orig_rsc != NULL) && (utilization != NULL)
1002 && pcmk__is_group(rsc));
1003
1005 return;
1006 }
1007
1008 pcmk__rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
1009 orig_rsc->id, rsc->id);
1011 || pcmk__is_clone(rsc->priv->parent)) {
1012
1013 // Every group member will be on same node, so sum all members
1014 for (GList *iter = rsc->priv->children;
1015 iter != NULL; iter = iter->next) {
1016
1017 member = (pcmk_resource_t *) iter->data;
1018
1020 && (g_list_find(all_rscs, member) == NULL)) {
1021 member->priv->cmds->add_utilization(member, orig_rsc, all_rscs,
1022 utilization);
1023 }
1024 }
1025
1026 } else if (rsc->priv->children != NULL) {
1027 // Just add first member's utilization
1028 member = (pcmk_resource_t *) rsc->priv->children->data;
1029 if ((member != NULL)
1031 && (g_list_find(all_rscs, member) == NULL)) {
1032
1033 member->priv->cmds->add_utilization(member, orig_rsc, all_rscs,
1034 utilization);
1035 }
1036 }
1037}
1038
1039void
1041{
1042 pcmk__assert(pcmk__is_group(rsc));
1043
1044 for (GList *iter = rsc->priv->children;
1045 iter != NULL; iter = iter->next) {
1046
1047 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
1048
1049 member->priv->cmds->shutdown_lock(member);
1050 }
1051}
@ 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:58
#define PCMK_ACTION_STOP
Definition actions.h:66
#define PCMK_ACTION_RUNNING
Definition actions.h:62
#define PCMK_ACTION_PROMOTE
Definition actions.h:57
#define PCMK_ACTION_START
Definition actions.h:63
#define PCMK_ACTION_STOPPED
Definition actions.h:67
#define PCMK_ACTION_DEMOTED
Definition actions.h:41
#define PCMK_ACTION_DEMOTE
Definition actions.h:40
#define pcmk__clear_raw_action_flags(action_flags, action_name, to_clear)
@ pcmk__action_runnable
@ pcmk__action_optional
@ pcmk__action_pseudo
#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:225
const char * pcmk__action_text(enum pcmk__action_type action)
Definition actions.c:34
#define pcmk__clear_action_flags(action, flags_to_clear)
pcmk__action_type
@ pcmk__action_stop
@ pcmk__action_demote
const char * parent
Definition cib.c:27
uint64_t flags
Definition remote.c:3
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
char data[0]
Definition cpg.c:10
enum pcmk_ipc_server type
Definition cpg.c:3
@ 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)
#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 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_spec, const char *primary_role_spec, uint32_t flags)
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:370
#define pcmk__config_err(fmt...)
pcmk_scheduler_t * scheduler
void pcmk__free_node_copy(void *data)
Definition nodes.c:64
#define PCMK_META_PROMOTABLE
Definition options.h:102
const char * action
Definition pcmk_fence.c:32
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:1025
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:158
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:1247
enum pcmk__action_type get_complex_task(const pcmk_resource_t *rsc, const char *name)
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.
bool pe__group_flag_is_set(const pcmk_resource_t *group, uint32_t flags)
Definition group.c:59
@ pcmk__rsc_managed
@ pcmk__rsc_assigning
@ pcmk__rsc_unassigned
@ pcmk__rsc_promotable
@ pcmk__rsc_updating_nodes
@ pcmk__rsc_critical
#define pcmk__set_rsc_flags(resource, flags_to_set)
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
#define pcmk__assert(expr)
#define pcmk__rsc_info(rsc, fmt, args...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__rsc_debug(rsc, fmt, args...)
@ pcmk__sched_output_scores
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition scores.c:102
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:26
int pcmk__add_scores(int score1, int score2)
Definition scores.c:159
gboolean crm_is_true(const char *s)
Definition strings.c:490
@ pcmk__str_none
pcmk_resource_t * rsc
uint32_t(* action_flags)(pcmk_action_t *action, const pcmk_node_t *node)
void(* this_with_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
pcmk_node_t *(* assign)(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
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(* create_actions)(pcmk_resource_t *rsc)
int(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void(* internal_constraints)(pcmk_resource_t *rsc)
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)
GList *(* colocated_resources)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *colocated_rscs)
void(* with_this_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
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(* apply_location)(pcmk_resource_t *rsc, pcmk__location_t *location)
Location constraint object.
pcmk_scheduler_t * scheduler
const pcmk__assignment_methods_t * cmds
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
uint64_t flags
Definition scheduler.h:89
Wrappers for and extensions to libxml2.