pacemaker 2.1.7-2.1.7
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-2023 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdbool.h>
13
14#include <crm/msg_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((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group));
45
47 return rsc->allocated_to; // Assignment already done
48 }
50 pe_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 pe_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);
105 return op;
106}
107
114void
116{
117 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group));
118
119 pe_rsc_trace(rsc, "Creating actions for group %s", rsc->id);
120
121 // Create actions for individual group members
122 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
123 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
124
125 member->cmds->create_actions(member);
126 }
127
128 // Create pseudo-actions for group itself to serve as ordering points
129 create_group_pseudo_op(rsc, PCMK_ACTION_START);
130 create_group_pseudo_op(rsc, PCMK_ACTION_RUNNING);
131 create_group_pseudo_op(rsc, PCMK_ACTION_STOP);
132 create_group_pseudo_op(rsc, PCMK_ACTION_STOPPED);
133 if (crm_is_true(g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_PROMOTABLE))) {
134 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTE);
135 create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTED);
136 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTE);
137 create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTED);
138 }
139}
140
141// User data for member_internal_constraints()
142struct member_data {
143 // These could be derived from member but this avoids some function calls
144 bool ordered;
145 bool colocated;
146 bool promotable;
147
148 pcmk_resource_t *last_active;
149 pcmk_resource_t *previous_member;
150};
151
159static void
160member_internal_constraints(gpointer data, gpointer user_data)
161{
163 struct member_data *member_data = (struct member_data *) user_data;
164
165 // For ordering demote vs demote or stop vs stop
166 uint32_t down_flags = pcmk__ar_then_implies_first_graphed;
167
168 // For ordering demote vs demoted or stop vs stopped
169 uint32_t post_down_flags = pcmk__ar_first_implies_then_graphed;
170
171 // Create the individual member's implicit constraints
172 member->cmds->internal_constraints(member);
173
174 if (member_data->previous_member == NULL) {
175 // This is first member
176 if (member_data->ordered) {
178 post_down_flags = pcmk__ar_first_implies_then;
179 }
180
181 } else if (member_data->colocated) {
182 uint32_t flags = pcmk__coloc_none;
183
184 if (pcmk_is_set(member->flags, pcmk_rsc_critical)) {
186 }
187
188 // Colocate this member with the previous one
189 pcmk__new_colocation("#group-members", NULL, INFINITY, member,
190 member_data->previous_member, NULL, NULL, flags);
191 }
192
193 if (member_data->promotable) {
194 // Demote group -> demote member -> group is demoted
196 member, PCMK_ACTION_DEMOTE, down_flags);
199 post_down_flags);
200
201 // Promote group -> promote member -> group is promoted
208 member, PCMK_ACTION_PROMOTE,
210 }
211
212 // Stop group -> stop member -> group is stopped
213 pcmk__order_stops(member->parent, member, down_flags);
216 post_down_flags);
217
218 // Start group -> start member -> group is started
219 pcmk__order_starts(member->parent, member,
226
227 if (!member_data->ordered) {
228 pcmk__order_starts(member->parent, member,
232 if (member_data->promotable) {
234 member, PCMK_ACTION_PROMOTE,
238 }
239
240 } else if (member_data->previous_member == NULL) {
241 pcmk__order_starts(member->parent, member, pcmk__ar_none);
242 if (member_data->promotable) {
244 member, PCMK_ACTION_PROMOTE,
246 }
247
248 } else {
249 // Order this member relative to the previous one
250
251 pcmk__order_starts(member_data->previous_member, member,
254 pcmk__order_stops(member, member_data->previous_member,
256
257 /* In unusual circumstances (such as adding a new member to the middle
258 * of a group with unmanaged later members), this member may be active
259 * while the previous (new) member is inactive. In this situation, the
260 * usual restart orderings will be irrelevant, so we need to order this
261 * member's stop before the previous member's start.
262 */
263 if ((member->running_on != NULL)
264 && (member_data->previous_member->running_on == NULL)) {
266 member_data->previous_member,
270 }
271
272 if (member_data->promotable) {
273 pcmk__order_resource_actions(member_data->previous_member,
274 PCMK_ACTION_PROMOTE, member,
279 member_data->previous_member,
281 }
282 }
283
284 // Make sure partially active groups shut down in sequence
285 if (member->running_on != NULL) {
286 if (member_data->ordered && (member_data->previous_member != NULL)
287 && (member_data->previous_member->running_on == NULL)
288 && (member_data->last_active != NULL)
289 && (member_data->last_active->running_on != NULL)) {
290 pcmk__order_stops(member, member_data->last_active,
292 }
293 member_data->last_active = member;
294 }
295
296 member_data->previous_member = member;
297}
298
305void
307{
308 struct member_data member_data = { false, };
309 const pcmk_resource_t *top = NULL;
310
311 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group));
312
313 /* Order group pseudo-actions relative to each other for restarting:
314 * stop group -> group is stopped -> start group -> group is started
315 */
325
326 top = pe__const_top_resource(rsc, false);
327
328 member_data.ordered = pe__group_flag_is_set(rsc, pcmk__group_ordered);
329 member_data.colocated = pe__group_flag_is_set(rsc, pcmk__group_colocated);
330 member_data.promotable = pcmk_is_set(top->flags, pcmk_rsc_promotable);
331 g_list_foreach(rsc->children, member_internal_constraints, &member_data);
332}
333
346static void
347colocate_group_with(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
348 const pcmk__colocation_t *colocation)
349{
350 pcmk_resource_t *member = NULL;
351
352 if (dependent->children == NULL) {
353 return;
354 }
355
356 pe_rsc_trace(primary, "Processing %s (group %s with %s) for dependent",
357 colocation->id, dependent->id, primary->id);
358
360 // Colocate first member (internal colocations will handle the rest)
361 member = (pcmk_resource_t *) dependent->children->data;
362 member->cmds->apply_coloc_score(member, primary, colocation, true);
363 return;
364 }
365
366 if (colocation->score >= INFINITY) {
367 pcmk__config_err("%s: Cannot perform mandatory colocation between "
368 "non-colocated group and %s",
369 dependent->id, primary->id);
370 return;
371 }
372
373 // Colocate each member individually
374 for (GList *iter = dependent->children; iter != NULL; iter = iter->next) {
375 member = (pcmk_resource_t *) iter->data;
376 member->cmds->apply_coloc_score(member, primary, colocation, true);
377 }
378}
379
392static void
393colocate_with_group(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
394 const pcmk__colocation_t *colocation)
395{
396 const pcmk_resource_t *member = NULL;
397
398 pe_rsc_trace(primary,
399 "Processing colocation %s (%s with group %s) for primary",
400 colocation->id, dependent->id, primary->id);
401
402 if (pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
403 return;
404 }
405
407
408 if (colocation->score >= INFINITY) {
409 /* For mandatory colocations, the entire group must be assignable
410 * (and in the specified role if any), so apply the colocation based
411 * on the last member.
412 */
413 member = pe__last_group_member(primary);
414 } else if (primary->children != NULL) {
415 /* For optional colocations, whether the group is partially or fully
416 * up doesn't matter, so apply the colocation based on the first
417 * member.
418 */
419 member = (pcmk_resource_t *) primary->children->data;
420 }
421 if (member == NULL) {
422 return; // Nothing to colocate with
423 }
424
425 member->cmds->apply_coloc_score(dependent, member, colocation, false);
426 return;
427 }
428
429 if (colocation->score >= INFINITY) {
430 pcmk__config_err("%s: Cannot perform mandatory colocation with"
431 " non-colocated group %s",
432 dependent->id, primary->id);
433 return;
434 }
435
436 // Colocate dependent with each member individually
437 for (const GList *iter = primary->children; iter != NULL;
438 iter = iter->next) {
439 member = iter->data;
440 member->cmds->apply_coloc_score(dependent, member, colocation, false);
441 }
442}
443
457void
459 const pcmk_resource_t *primary,
460 const pcmk__colocation_t *colocation,
461 bool for_dependent)
462{
463 CRM_ASSERT((dependent != NULL) && (primary != NULL)
464 && (colocation != NULL));
465
466 if (for_dependent) {
467 colocate_group_with(dependent, primary, colocation);
468
469 } else {
470 // Method should only be called for primitive dependents
472
473 colocate_with_group(dependent, primary, colocation);
474 }
475}
476
486uint32_t
488{
489 // Default flags for a group action
490 uint32_t flags = pcmk_action_optional
493
494 CRM_ASSERT(action != NULL);
495
496 // Update flags considering each member's own flags for same action
497 for (GList *iter = action->rsc->children; iter != NULL; iter = iter->next) {
498 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
499
500 // Check whether member has the same action
501 enum action_tasks task = get_complex_task(member, action->task);
502 const char *task_s = task2text(task);
503 pcmk_action_t *member_action = find_first_action(member->actions, NULL,
504 task_s, node);
505
506 if (member_action != NULL) {
507 uint32_t member_flags = member->cmds->action_flags(member_action,
508 node);
509
510 // Group action is mandatory if any member action is
512 && !pcmk_is_set(member_flags, pcmk_action_optional)) {
513 pe_rsc_trace(action->rsc, "%s is mandatory because %s is",
514 action->uuid, member_action->uuid);
515 pe__clear_raw_action_flags(flags, "group action",
518 }
519
520 // Group action is unrunnable if any member action is
521 if (!pcmk__str_eq(task_s, action->task, pcmk__str_none)
523 && !pcmk_is_set(member_flags, pcmk_action_runnable)) {
524
525 pe_rsc_trace(action->rsc, "%s is unrunnable because %s is",
526 action->uuid, member_action->uuid);
527 pe__clear_raw_action_flags(flags, "group action",
530 }
531
532 /* Group (pseudo-)actions other than stop or demote are unrunnable
533 * unless every member will do it.
534 */
535 } else if ((task != pcmk_action_stop) && (task != pcmk_action_demote)) {
536 pe_rsc_trace(action->rsc,
537 "%s is not runnable because %s will not %s",
538 action->uuid, member->id, task_s);
539 pe__clear_raw_action_flags(flags, "group action",
541 }
542 }
543
544 return flags;
545}
546
569uint32_t
571 const pcmk_node_t *node, uint32_t flags,
572 uint32_t filter, uint32_t type,
574{
575 uint32_t changed = pcmk__updated_none;
576
577 // Group method can be called only on behalf of "then" action
578 CRM_ASSERT((first != NULL) && (then != NULL) && (then->rsc != NULL)
579 && (scheduler != NULL));
580
581 // Update the actions for the group itself
582 changed |= pcmk__update_ordered_actions(first, then, node, flags, filter,
583 type, scheduler);
584
585 // Update the actions for each group member
586 for (GList *iter = then->rsc->children; iter != NULL; iter = iter->next) {
587 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
588
589 pcmk_action_t *member_action = find_first_action(member->actions, NULL,
590 then->task, node);
591
592 if (member_action != NULL) {
593 changed |= member->cmds->update_ordered_actions(first,
594 member_action, node,
595 flags, filter, type,
596 scheduler);
597 }
598 }
599 return changed;
600}
601
609void
611{
612 GList *node_list_orig = NULL;
613 GList *node_list_copy = NULL;
614 bool reset_scores = true;
615
616 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group)
617 && (location != NULL));
618
619 node_list_orig = location->node_list_rh;
620 node_list_copy = pcmk__copy_node_list(node_list_orig, true);
621 reset_scores = pe__group_flag_is_set(rsc, pcmk__group_colocated);
622
623 // Apply the constraint for the group itself (updates node scores)
624 pcmk__apply_location(rsc, location);
625
626 // Apply the constraint for each member
627 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
628 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
629
630 member->cmds->apply_location(member, location);
631
632 if (reset_scores) {
633 /* The first member of colocated groups needs to use the original
634 * node scores, but subsequent members should work on a copy, since
635 * the first member's scores already incorporate theirs.
636 */
637 reset_scores = false;
638 location->node_list_rh = node_list_copy;
639 }
640 }
641
642 location->node_list_rh = node_list_orig;
643 g_list_free_full(node_list_copy, free);
644}
645
646// Group implementation of pcmk_assignment_methods_t:colocated_resources()
647GList *
649 const pcmk_resource_t *orig_rsc,
650 GList *colocated_rscs)
651{
652 const pcmk_resource_t *member = NULL;
653
654 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group));
655
656 if (orig_rsc == NULL) {
657 orig_rsc = rsc;
658 }
659
661 || pe_rsc_is_clone(rsc->parent)) {
662 /* This group has colocated members and/or is cloned -- either way,
663 * add every child's colocated resources to the list. The first and last
664 * members will include the group's own colocations.
665 */
666 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
667 for (const GList *iter = rsc->children;
668 iter != NULL; iter = iter->next) {
669
670 member = (const pcmk_resource_t *) iter->data;
671 colocated_rscs = member->cmds->colocated_resources(member, orig_rsc,
672 colocated_rscs);
673 }
674
675 } else if (rsc->children != NULL) {
676 /* This group's members are not colocated, and the group is not cloned,
677 * so just add the group's own colocations to the list.
678 */
679 colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc,
680 colocated_rscs);
681 }
682
683 return colocated_rscs;
684}
685
686// Group implementation of pcmk_assignment_methods_t:with_this_colocations()
687void
689 const pcmk_resource_t *orig_rsc, GList **list)
690
691{
692 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group)
693 && (orig_rsc != NULL) && (list != NULL));
694
695 // Ignore empty groups
696 if (rsc->children == NULL) {
697 return;
698 }
699
700 /* "With this" colocations are needed only for the group itself and for its
701 * last member. (Previous members will chain via the group internal
702 * colocations.)
703 */
704 if ((orig_rsc != rsc) && (orig_rsc != pe__last_group_member(rsc))) {
705 return;
706 }
707
708 pe_rsc_trace(rsc, "Adding 'with %s' colocations to list for %s",
709 rsc->id, orig_rsc->id);
710
711 // Add the group's own colocations
712 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
713
714 // If cloned, add any relevant colocations with the clone
715 if (rsc->parent != NULL) {
716 rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc,
717 list);
718 }
719
721 // @COMPAT Non-colocated groups are deprecated
722 return;
723 }
724
725 // Add explicit colocations with the group's (other) children
726 for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
727 const pcmk_resource_t *member = iter->data;
728
729 if (member != orig_rsc) {
730 member->cmds->with_this_colocations(member, orig_rsc, list);
731 }
732 }
733}
734
735// Group implementation of pcmk_assignment_methods_t:this_with_colocations()
736void
738 const pcmk_resource_t *orig_rsc, GList **list)
739{
740 const pcmk_resource_t *member = NULL;
741
742 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group)
743 && (orig_rsc != NULL) && (list != NULL));
744
745 // Ignore empty groups
746 if (rsc->children == NULL) {
747 return;
748 }
749
750 /* "This with" colocations are normally needed only for the group itself and
751 * for its first member.
752 */
753 if ((rsc == orig_rsc)
754 || (orig_rsc == (const pcmk_resource_t *) rsc->children->data)) {
755 pe_rsc_trace(rsc, "Adding '%s with' colocations to list for %s",
756 rsc->id, orig_rsc->id);
757
758 // Add the group's own colocations
759 pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
760
761 // If cloned, add any relevant colocations involving the clone
762 if (rsc->parent != NULL) {
763 rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc,
764 list);
765 }
766
768 // @COMPAT Non-colocated groups are deprecated
769 return;
770 }
771
772 // Add explicit colocations involving the group's (other) children
773 for (const GList *iter = rsc->children;
774 iter != NULL; iter = iter->next) {
775 member = iter->data;
776 if (member != orig_rsc) {
777 member->cmds->this_with_colocations(member, orig_rsc, list);
778 }
779 }
780 return;
781 }
782
783 /* Later group members honor the group's colocations indirectly, due to the
784 * internal group colocations that chain everything from the first member.
785 * However, if an earlier group member is unmanaged, this chaining will not
786 * happen, so the group's mandatory colocations must be explicitly added.
787 */
788 for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
789 member = iter->data;
790 if (orig_rsc == member) {
791 break; // We've seen all earlier members, and none are unmanaged
792 }
793
794 if (!pcmk_is_set(member->flags, pcmk_rsc_managed)) {
795 crm_trace("Adding mandatory '%s with' colocations to list for "
796 "member %s because earlier member %s is unmanaged",
797 rsc->id, orig_rsc->id, member->id);
798 for (const GList *cons_iter = rsc->rsc_cons; cons_iter != NULL;
799 cons_iter = cons_iter->next) {
800 const pcmk__colocation_t *colocation = NULL;
801
802 colocation = (const pcmk__colocation_t *) cons_iter->data;
803 if (colocation->score == INFINITY) {
804 pcmk__add_this_with(list, colocation, orig_rsc);
805 }
806 }
807 // @TODO Add mandatory (or all?) clone constraints if cloned
808 break;
809 }
810 }
811}
812
843void
845 const pcmk_resource_t *target_rsc,
846 const char *log_id, GHashTable **nodes,
847 const pcmk__colocation_t *colocation,
848 float factor, uint32_t flags)
849{
850 pcmk_resource_t *member = NULL;
851
852 CRM_ASSERT((source_rsc != NULL)
853 && (source_rsc->variant == pcmk_rsc_variant_group)
854 && (nodes != NULL)
855 && ((colocation != NULL)
856 || ((target_rsc == NULL) && (*nodes == NULL))));
857
858 if (log_id == NULL) {
859 log_id = source_rsc->id;
860 }
861
862 // Avoid infinite recursion
863 if (pcmk_is_set(source_rsc->flags, pcmk_rsc_updating_nodes)) {
864 pe_rsc_info(source_rsc, "%s: Breaking dependency loop at %s",
865 log_id, source_rsc->id);
866 return;
867 }
869
870 // Ignore empty groups (only possible with schema validation disabled)
871 if (source_rsc->children == NULL) {
872 return;
873 }
874
875 /* Refer the operation to the first or last member as appropriate.
876 *
877 * cmp_resources() is the only caller that passes a NULL nodes table,
878 * and is also the only caller using pcmk__coloc_select_this_with.
879 * For "this with" colocations, the last member will recursively incorporate
880 * all the other members' "this with" colocations via the internal group
881 * colocations (and via the first member, the group's own colocations).
882 *
883 * For "with this" colocations, the first member works similarly.
884 */
885 if (*nodes == NULL) {
886 member = pe__last_group_member(source_rsc);
887 } else {
888 member = source_rsc->children->data;
889 }
890 pe_rsc_trace(source_rsc, "%s: Merging scores from group %s using member %s "
891 "(at %.6f)", log_id, source_rsc->id, member->id, factor);
892 member->cmds->add_colocated_node_scores(member, target_rsc, log_id, nodes,
893 colocation, factor, flags);
895}
896
897// Group implementation of pcmk_assignment_methods_t:add_utilization()
898void
900 const pcmk_resource_t *orig_rsc, GList *all_rscs,
901 GHashTable *utilization)
902{
903 pcmk_resource_t *member = NULL;
904
905 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group)
906 && (orig_rsc != NULL) && (utilization != NULL));
907
909 return;
910 }
911
912 pe_rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
913 orig_rsc->id, rsc->id);
915 || pe_rsc_is_clone(rsc->parent)) {
916 // Every group member will be on same node, so sum all members
917 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
918 member = (pcmk_resource_t *) iter->data;
919
921 && (g_list_find(all_rscs, member) == NULL)) {
922 member->cmds->add_utilization(member, orig_rsc, all_rscs,
923 utilization);
924 }
925 }
926
927 } else if (rsc->children != NULL) {
928 // Just add first member's utilization
929 member = (pcmk_resource_t *) rsc->children->data;
930 if ((member != NULL)
932 && (g_list_find(all_rscs, member) == NULL)) {
933
934 member->cmds->add_utilization(member, orig_rsc, all_rscs,
935 utilization);
936 }
937 }
938}
939
940void
942{
943 CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_group));
944
945 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
946 pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
947
948 member->cmds->shutdown_lock(member);
949 }
950}
@ 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_ACTION_PROMOTED
Definition actions.h:66
#define PCMK_ACTION_STOP
Definition actions.h:74
#define PCMK_ACTION_RUNNING
Definition actions.h:70
#define PCMK_ACTION_PROMOTE
Definition actions.h:65
#define PCMK_ACTION_START
Definition actions.h:71
@ pcmk_action_runnable
Whether action is runnable.
Definition actions.h:241
@ pcmk_action_pseudo
Whether action does not require invoking an agent.
Definition actions.h:238
@ pcmk_action_optional
Whether action should not be executed.
Definition actions.h:244
action_tasks
Possible actions (including some pseudo-actions)
Definition actions.h:79
@ pcmk_action_demote
Demote.
Definition actions.h:97
@ pcmk_action_stop
Stop.
Definition actions.h:85
#define PCMK_ACTION_STOPPED
Definition actions.h:75
#define PCMK_ACTION_DEMOTED
Definition actions.h:50
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition actions.c:42
uint64_t flags
Definition remote.c:3
gboolean crm_is_true(const char *s)
Definition strings.c:416
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:99
const char * task2text(enum action_tasks task)
Definition common.c:405
enum crm_ais_msg_types type
Definition cpg.c:3
char data[0]
Definition cpg.c:10
#define INFINITY
Definition crm.h:98
@ 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 void pcmk__apply_location(pcmk_resource_t *rsc, pe__location_t *constraint)
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)
#define crm_trace(fmt, args...)
Definition logging.h:385
#define pcmk__config_err(fmt...)
#define XML_RSC_ATTR_PROMOTABLE
Definition msg_xml.h:247
pcmk_scheduler_t * scheduler
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)
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_apply_location(pcmk_resource_t *rsc, pe__location_t *location)
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)
#define pe__clear_raw_action_flags(action_flags, action_name, flags_to_clear)
Definition internal.h:101
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:962
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:341
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition internal.h:70
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:36
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:37
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:64
void pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition complex.c:1184
pcmk_action_t * custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler)
Create or update an action object.
#define pe_rsc_info(rsc, fmt, args...)
Definition internal.h:35
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:85
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
#define pe__set_order_flags(order_flags, flags_to_set)
Definition internal.h:128
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:76
@ pcmk_rsc_variant_group
Group resource.
Definition resources.h:35
@ pcmk_rsc_variant_primitive
Primitive resource.
Definition resources.h:34
@ pcmk_rsc_promotable
Whether resource can be promoted and demoted.
Definition resources.h:124
@ pcmk_rsc_unassigned
Whether resource has not yet been assigned to a node.
Definition resources.h:127
@ pcmk_rsc_assigning
Whether resource is in the process of being assigned to a node.
Definition resources.h:130
@ pcmk_rsc_critical
Whether resource has "critical" meta-attribute enabled.
Definition resources.h:148
@ pcmk_rsc_updating_nodes
Whether resource is in the process of modifying allowed node scores.
Definition resources.h:133
@ pcmk_rsc_managed
Whether resource is managed.
Definition resources.h:106
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_sched_output_scores
Whether node scores should be output instead of logged.
Definition scheduler.h:158
@ pcmk__str_none
Implementation of pcmk_action_t.
Definition actions.h:390
char * uuid
Action key.
Definition actions.h:404
char * task
Action name.
Definition actions.h:403
pcmk_resource_t * rsc
Resource to apply action to, if any.
Definition actions.h:400
Implementation of pcmk_node_t.
Definition nodes.h:130
Implementation of pcmk_resource_t.
Definition resources.h:399
pcmk_assignment_methods_t * cmds
Resource assignment methods.
Definition resources.h:417
GList * running_on
Nodes where resource may be active.
Definition resources.h:460
GList * actions
Definition resources.h:447
enum pe_obj_types variant
Resource variant.
Definition resources.h:414
GHashTable * meta
Resource's meta-attributes.
Definition resources.h:471
GList * rsc_cons
Definition resources.h:445
GList * rsc_cons_lhs
Definition resources.h:444
GList * children
Resource's child resources, if any.
Definition resources.h:475
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition resources.h:412
char * id
Resource ID in configuration.
Definition resources.h:400
pcmk_node_t * allocated_to
Node resource is assigned to.
Definition resources.h:451
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition resources.h:466
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition resources.h:429
enum rsc_role_e next_role
Resource's scheduled next role.
Definition resources.h:469
enum rsc_role_e role
Resource's current role.
Definition resources.h:468
pcmk_resource_t * parent
Resource's parent resource, if any.
Definition resources.h:413
Implementation of pcmk_scheduler_t.
Definition scheduler.h:172
unsigned long long flags
Group of enum pcmk_scheduler_flags.
Definition scheduler.h:183
void(* create_actions)(pcmk_resource_t *rsc)
void(* apply_location)(pcmk_resource_t *rsc, pe__location_t *location)
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)