pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
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>
17 #include "libpacemaker_private.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 
99 static pcmk_action_t *
100 create_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 
114 void
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()
142 struct 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 
159 static void
160 member_internal_constraints(gpointer data, gpointer user_data)
161 {
162  pcmk_resource_t *member = (pcmk_resource_t *) data;
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);
198  member->parent, PCMK_ACTION_DEMOTED,
199  post_down_flags);
200 
201  // Promote group -> promote member -> group is promoted
203  member->parent, PCMK_ACTION_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);
215  member->parent, PCMK_ACTION_STOPPED,
216  post_down_flags);
217 
218  // Start group -> start member -> group is started
219  pcmk__order_starts(member->parent, member,
222  member->parent, PCMK_ACTION_RUNNING,
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,
245  pcmk__ar_none);
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 
305 void
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  */
317  rsc, PCMK_ACTION_STOPPED,
320  rsc, PCMK_ACTION_START,
323  rsc, PCMK_ACTION_RUNNING,
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 
346 static void
347 colocate_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 
392 static void
393 colocate_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 
457 void
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 
486 uint32_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 
569 uint32_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 
609 void
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()
647 GList *
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()
687 void
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()
736 void
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 
843 void
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()
898 void
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 
908  if (!pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
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 
940 void
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_assignment_methods_t * cmds
Resource assignment methods.
Definition: resources.h:417
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition: complex.c:962
void pcmk__group_create_actions(pcmk_resource_t *rsc)
pcmk_node_t * pcmk__group_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
G_GNUC_INTERNAL GList * pcmk__colocated_resources(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *colocated_rscs)
const char * task2text(enum action_tasks task)
Definition: common.c:405
#define pcmk__order_starts(rsc1, rsc2, flags)
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)
&#39;then&#39; is runnable (and migratable) only if &#39;first&#39; is runnable
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition: resources.h:412
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:36
void pcmk__group_apply_coloc_score(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:98
GList * rsc_cons
Definition: resources.h:445
Whether action should not be executed.
Definition: actions.h:244
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:76
void(* create_actions)(pcmk_resource_t *rsc)
uint32_t(* action_flags)(pcmk_action_t *action, const pcmk_node_t *node)
enum rsc_role_e role
Resource&#39;s current role.
Definition: resources.h:468
GList * children
Resource&#39;s child resources, if any.
Definition: resources.h:475
#define pcmk__order_stops(rsc1, rsc2, flags)
enum rsc_role_e next_role
Resource&#39;s scheduled next role.
Definition: resources.h:469
Implementation of pcmk_action_t.
Definition: actions.h:390
#define pcmk__config_err(fmt...)
Whether node scores should be output instead of logged.
Definition: scheduler.h:158
GHashTable * meta
Resource&#39;s meta-attributes.
Definition: resources.h:471
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)
action_tasks
Possible actions (including some pseudo-actions)
Definition: actions.h:79
pcmk_node_t *(* assign)(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
Group resource.
Definition: resources.h:35
GList * rsc_cons_lhs
Definition: resources.h:444
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)
enum crm_ais_msg_types type
Definition: cpg.c:48
Implementation of pcmk_scheduler_t.
Definition: scheduler.h:172
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)
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:64
void(* with_this_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
#define XML_RSC_ATTR_PROMOTABLE
Definition: msg_xml.h:247
#define PCMK_ACTION_DEMOTE
Definition: actions.h:49
pcmk_resource_t * parent
Resource&#39;s parent resource, if any.
Definition: resources.h:413
void pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition: complex.c:1184
Whether resource is in the process of being assigned to a node.
Definition: resources.h:130
G_GNUC_INTERNAL void pcmk__add_with_this_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
Implementation of pcmk_resource_t.
Definition: resources.h:399
uint32_t pcmk__group_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
Actions are ordered (optionally, if no other flags are set)
Demote.
Definition: actions.h:97
void(* apply_location)(pcmk_resource_t *rsc, pe__location_t *location)
Primitive resource.
Definition: resources.h:34
pcmk_resource_t * pe__last_group_member(const pcmk_resource_t *group)
Definition: group.c:37
G_GNUC_INTERNAL void pcmk__add_this_with(GList **list, const pcmk__colocation_t *colocation, const pcmk_resource_t *rsc)
char * task
Action name.
Definition: actions.h:403
void(* this_with_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:85
#define crm_trace(fmt, args...)
Definition: logging.h:387
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:99
#define PCMK_ACTION_START
Definition: actions.h:71
void(* shutdown_lock)(pcmk_resource_t *rsc)
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition: resources.h:429
GList * pcmk__group_colocated_resources(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *colocated_rscs)
#define PCMK_ACTION_STOP
Definition: actions.h:74
GList * actions
Definition: resources.h:447
GList *(* colocated_resources)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *colocated_rscs)
char * uuid
Action key.
Definition: actions.h:404
void pcmk__group_with_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
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
Implementation of pcmk_node_t.
Definition: nodes.h:130
enum pe_obj_types variant
Resource variant.
Definition: resources.h:414
G_GNUC_INTERNAL void pcmk__apply_location(pcmk_resource_t *rsc, pe__location_t *constraint)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
void(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
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.
Definition: pe_actions.c:1117
Whether resource has "critical" meta-attribute enabled.
Definition: resources.h:148
Whether resource has not yet been assigned to a node.
Definition: resources.h:127
Whether resource is in the process of modifying allowed node scores.
Definition: resources.h:133
If &#39;then&#39; is required, &#39;first&#39; must be added to the transition graph.
Whether action is runnable.
Definition: actions.h:241
void(* internal_constraints)(pcmk_resource_t *rsc)
void pcmk__group_apply_location(pcmk_resource_t *rsc, pe__location_t *location)
GList * pcmk__copy_node_list(const GList *list, bool reset)
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
Definition: pe_actions.c:1486
pcmk_scheduler_t * scheduler
Whether action does not require invoking an agent.
Definition: actions.h:238
G_GNUC_INTERNAL void pcmk__add_this_with_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
#define CRM_ASSERT(expr)
Definition: results.h:42
If &#39;first&#39; is required and runnable, &#39;then&#39; must be in graph.
#define PCMK_ACTION_STOPPED
Definition: actions.h:75
void pcmk__group_add_utilization(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
pcmk_node_t * allocated_to
Node resource is assigned to.
Definition: resources.h:451
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:70
void pcmk__group_shutdown_lock(pcmk_resource_t *rsc)
#define PCMK_ACTION_PROMOTE
Definition: actions.h:65
void pcmk__with_group_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
#define pe__show_node_scores(level, rsc, text, nodes, scheduler)
Definition: internal.h:341
GList * running_on
Nodes where resource may be active.
Definition: resources.h:460
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)
#define PCMK_ACTION_PROMOTED
Definition: actions.h:66
gboolean crm_is_true(const char *s)
Definition: strings.c:416
pcmk_resource_t * rsc
Resource to apply action to, if any.
Definition: actions.h:400
Whether resource can be promoted and demoted.
Definition: resources.h:124
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 pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:37
#define pe__set_order_flags(order_flags, flags_to_set)
Definition: internal.h:128
#define PCMK_ACTION_RUNNING
Definition: actions.h:70
unsigned long long flags
Group of enum pcmk_scheduler_flags.
Definition: scheduler.h:183
bool pe__group_flag_is_set(const pcmk_resource_t *group, uint32_t flags)
Definition: group.c:57
#define PCMK_ACTION_DEMOTED
Definition: actions.h:50
enum action_tasks get_complex_task(const pcmk_resource_t *rsc, const char *name)
Definition: pe_actions.c:1453
Whether resource is managed.
Definition: resources.h:106
#define pe__clear_raw_action_flags(action_flags, action_name, flags_to_clear)
Definition: internal.h:101
void(* add_utilization)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void pcmk__group_internal_constraints(pcmk_resource_t *rsc)
uint64_t flags
Definition: remote.c:215
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:35
No relation (compare with equality rather than bit set)
char * id
Resource ID in configuration.
Definition: resources.h:400
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition: resources.h:466