pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
pcmk_sched_clone.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2022 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 <crm/msg_xml.h>
13 #include <pacemaker-internal.h>
14 
15 #include "libpacemaker_private.h"
16 
17 #define VARIANT_CLONE 1
18 #include <lib/pengine/variant.h>
19 
20 static void append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all);
21 
22 static pe_node_t *
23 can_run_instance(pe_resource_t * rsc, pe_node_t * node, int limit)
24 {
25  pe_node_t *local_node = NULL;
26 
27  if (node == NULL && rsc->allowed_nodes) {
28  GHashTableIter iter;
29  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
30  while (g_hash_table_iter_next(&iter, NULL, (void **)&local_node)) {
31  can_run_instance(rsc, local_node, limit);
32  }
33  return NULL;
34  }
35 
36  if (!node) {
37  /* make clang analyzer happy */
38  goto bail;
39 
40  } else if (!pcmk__node_available(node, false, false)) {
41  goto bail;
42 
43  } else if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
44  goto bail;
45  }
46 
47  local_node = pcmk__top_allowed_node(rsc, node);
48 
49  if (local_node == NULL) {
50  crm_warn("%s cannot run on %s: node not allowed",
51  rsc->id, pe__node_name(node));
52  goto bail;
53 
54  } else if (local_node->weight < 0) {
55  common_update_score(rsc, node->details->id, local_node->weight);
56  pe_rsc_trace(rsc, "%s cannot run on %s: Parent node weight doesn't allow it.",
57  rsc->id, pe__node_name(node));
58 
59  } else if (local_node->count < limit) {
60  pe_rsc_trace(rsc, "%s can run on %s (already running %d)",
61  rsc->id, pe__node_name(node), local_node->count);
62  return local_node;
63 
64  } else {
65  pe_rsc_trace(rsc, "%s cannot run on %s: node full (%d >= %d)",
66  rsc->id, pe__node_name(node), local_node->count, limit);
67  }
68 
69  bail:
70  if (node) {
71  common_update_score(rsc, node->details->id, -INFINITY);
72  }
73  return NULL;
74 }
75 
76 static pe_node_t *
77 allocate_instance(pe_resource_t *rsc, pe_node_t *prefer, gboolean all_coloc,
78  int limit, pe_working_set_t *data_set)
79 {
80  pe_node_t *chosen = NULL;
81  GHashTable *backup = NULL;
82 
83  CRM_ASSERT(rsc);
84  pe_rsc_trace(rsc, "Checking allocation of %s (preferring %s, using %s parent colocations)",
85  rsc->id, (prefer? prefer->details->uname: "none"),
86  (all_coloc? "all" : "some"));
87 
88  if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
89  return rsc->fns->location(rsc, NULL, FALSE);
90 
91  } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
92  pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
93  return NULL;
94  }
95 
96  /* Only include positive colocation preferences of dependent resources
97  * if not every node will get a copy of the clone
98  */
99  append_parent_colocation(rsc->parent, rsc, all_coloc);
100 
101  if (prefer) {
102  pe_node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
103 
104  if (local_prefer == NULL || local_prefer->weight < 0) {
105  pe_rsc_trace(rsc, "Not pre-allocating %s to %s - unavailable", rsc->id,
106  pe__node_name(prefer));
107  return NULL;
108  }
109  }
110 
111  can_run_instance(rsc, NULL, limit);
112 
113  backup = pcmk__copy_node_table(rsc->allowed_nodes);
114  pe_rsc_trace(rsc, "Allocating instance %s", rsc->id);
115  chosen = rsc->cmds->assign(rsc, prefer);
116  if (chosen && prefer && (chosen->details != prefer->details)) {
117  crm_info("Not pre-allocating %s to %s because %s is better",
118  rsc->id, pe__node_name(prefer), pe__node_name(chosen));
119  g_hash_table_destroy(rsc->allowed_nodes);
120  rsc->allowed_nodes = backup;
122  chosen = NULL;
123  backup = NULL;
124  }
125  if (chosen) {
126  pe_node_t *local_node = pcmk__top_allowed_node(rsc, chosen);
127 
128  if (local_node) {
129  local_node->count++;
130 
131  } else if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
132  /* what to do? we can't enforce per-node limits in this case */
133  pcmk__config_err("%s not found in %s (list of %d)",
134  chosen->details->id, rsc->parent->id,
135  g_hash_table_size(rsc->parent->allowed_nodes));
136  }
137  }
138 
139  if(backup) {
140  g_hash_table_destroy(backup);
141  }
142  return chosen;
143 }
144 
145 static void
146 append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all)
147 {
148 
149  GList *gIter = NULL;
150 
151  gIter = rsc->rsc_cons;
152  for (; gIter != NULL; gIter = gIter->next) {
153  pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
154 
155  if (all || cons->score < 0 || cons->score == INFINITY) {
156  pcmk__add_this_with(child, cons);
157  }
158  }
159 
160  gIter = rsc->rsc_cons_lhs;
161  for (; gIter != NULL; gIter = gIter->next) {
162  pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
163 
164  if (!pcmk__colocation_has_influence(cons, child)) {
165  continue;
166  }
167  if (all || cons->score < 0) {
168  pcmk__add_with_this(child, cons);
169  }
170  }
171 }
172 
173 
174 void
175 distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
176  int max, int per_host_max, pe_working_set_t * data_set);
177 
178 void
179 distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
180  int max, int per_host_max, pe_working_set_t * data_set)
181 {
182  int loop_max = 0;
183  int allocated = 0;
184  int available_nodes = 0;
185  bool all_coloc = false;
186 
187  /* count now tracks the number of clones currently allocated */
188  for(GList *nIter = nodes; nIter != NULL; nIter = nIter->next) {
189  pe_node_t *node = nIter->data;
190 
191  node->count = 0;
192  if (pcmk__node_available(node, false, false)) {
193  available_nodes++;
194  }
195  }
196 
197  all_coloc = (max < available_nodes) ? true : false;
198 
199  if(available_nodes) {
200  loop_max = max / available_nodes;
201  }
202  if (loop_max < 1) {
203  loop_max = 1;
204  }
205 
206  pe_rsc_debug(rsc, "Allocating up to %d %s instances to a possible %d nodes (at most %d per host, %d optimal)",
207  max, rsc->id, available_nodes, per_host_max, loop_max);
208 
209  /* Pre-allocate as many instances as we can to their current location */
210  for (GList *gIter = children; gIter != NULL && allocated < max; gIter = gIter->next) {
211  pe_resource_t *child = (pe_resource_t *) gIter->data;
212  pe_node_t *child_node = NULL;
213  pe_node_t *local_node = NULL;
214 
215  if ((child->running_on == NULL)
217  || pcmk_is_set(child->flags, pe_rsc_failed)) {
218 
219  continue;
220  }
221 
222  child_node = pe__current_node(child);
223  local_node = pcmk__top_allowed_node(child, child_node);
224 
225  pe_rsc_trace(rsc,
226  "Checking pre-allocation of %s to %s (%d remaining of %d)",
227  child->id, pe__node_name(child_node), max - allocated,
228  max);
229 
230  if (!pcmk__node_available(child_node, true, false)) {
231  pe_rsc_trace(rsc, "Not pre-allocating because %s can not run %s",
232  pe__node_name(child_node), child->id);
233  continue;
234  }
235 
236  if ((local_node != NULL) && (local_node->count >= loop_max)) {
237  pe_rsc_trace(rsc,
238  "Not pre-allocating because %s already allocated "
239  "optimal instances", pe__node_name(child_node));
240  continue;
241  }
242 
243  if (allocate_instance(child, child_node, all_coloc, per_host_max,
244  data_set)) {
245  pe_rsc_trace(rsc, "Pre-allocated %s to %s", child->id,
246  pe__node_name(child_node));
247  allocated++;
248  }
249  }
250 
251  pe_rsc_trace(rsc, "Done pre-allocating (%d of %d)", allocated, max);
252 
253  for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
254  pe_resource_t *child = (pe_resource_t *) gIter->data;
255 
256  if (child->running_on != NULL) {
257  pe_node_t *child_node = pe__current_node(child);
258  pe_node_t *local_node = pcmk__top_allowed_node(child, child_node);
259 
260  if (local_node == NULL) {
261  crm_err("%s is running on %s which isn't allowed",
262  child->id, pe__node_name(child_node));
263  }
264  }
265 
266  if (!pcmk_is_set(child->flags, pe_rsc_provisional)) {
267  } else if (allocated >= max) {
268  pe_rsc_debug(rsc, "Child %s not allocated - limit reached %d %d", child->id, allocated, max);
269  resource_location(child, NULL, -INFINITY, "clone:limit_reached", data_set);
270  } else {
271  if (allocate_instance(child, NULL, all_coloc, per_host_max,
272  data_set)) {
273  allocated++;
274  }
275  }
276  }
277 
278  pe_rsc_debug(rsc, "Allocated %d %s instances of a possible %d",
279  allocated, rsc->id, max);
280 }
281 
291 pe_node_t *
293 {
294  GList *nodes = NULL;
295  clone_variant_data_t *clone_data = NULL;
296 
297  get_clone_variant_data(clone_data, rsc);
298 
299  if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
300  return NULL;
301 
302  } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
303  pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
304  return NULL;
305  }
306 
307  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
309  }
310 
312 
313  /* This information is used by pcmk__cmp_instance() when deciding the order
314  * in which to assign clone instances to nodes.
315  */
316  for (GList *gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
317  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
318 
319  pe_rsc_trace(rsc, "%s: Allocating %s first",
320  rsc->id, constraint->primary->id);
321  constraint->primary->cmds->assign(constraint->primary, prefer);
322  }
323 
324  for (GList *gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
325  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
326 
327  if (pcmk__colocation_has_influence(constraint, NULL)) {
328  pe_resource_t *dependent = constraint->dependent;
329  const char *attr = constraint->node_attribute;
330  const float factor = constraint->score / (float) INFINITY;
331  const uint32_t flags = pcmk__coloc_select_active
333 
334  pcmk__add_colocated_node_scores(dependent, rsc->id,
335  &rsc->allowed_nodes, attr, factor,
336  flags);
337  }
338  }
339 
341  rsc, __func__, rsc->allowed_nodes, rsc->cluster);
342 
343  nodes = g_hash_table_get_values(rsc->allowed_nodes);
344  nodes = pcmk__sort_nodes(nodes, NULL);
345  rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance);
346  distribute_children(rsc, rsc->children, nodes, clone_data->clone_max,
347  clone_data->clone_node_max, rsc->cluster);
348  g_list_free(nodes);
349 
350  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
352  }
353 
355  pe_rsc_trace(rsc, "Done allocating %s", rsc->id);
356  return NULL;
357 }
358 
359 static void
360 clone_update_pseudo_status(pe_resource_t * rsc, gboolean * stopping, gboolean * starting,
361  gboolean * active)
362 {
363  GList *gIter = NULL;
364 
365  if (rsc->children) {
366 
367  gIter = rsc->children;
368  for (; gIter != NULL; gIter = gIter->next) {
369  pe_resource_t *child = (pe_resource_t *) gIter->data;
370 
371  clone_update_pseudo_status(child, stopping, starting, active);
372  }
373 
374  return;
375  }
376 
377  CRM_ASSERT(active != NULL);
378  CRM_ASSERT(starting != NULL);
379  CRM_ASSERT(stopping != NULL);
380 
381  if (rsc->running_on) {
382  *active = TRUE;
383  }
384 
385  gIter = rsc->actions;
386  for (; gIter != NULL; gIter = gIter->next) {
387  pe_action_t *action = (pe_action_t *) gIter->data;
388 
389  if (*starting && *stopping) {
390  return;
391 
392  } else if (pcmk_is_set(action->flags, pe_action_optional)) {
393  pe_rsc_trace(rsc, "Skipping optional: %s", action->uuid);
394  continue;
395 
396  } else if (!pcmk_any_flags_set(action->flags,
398  pe_rsc_trace(rsc, "Skipping unrunnable: %s", action->uuid);
399  continue;
400 
401  } else if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_casei)) {
402  pe_rsc_trace(rsc, "Stopping due to: %s", action->uuid);
403  *stopping = TRUE;
404 
405  } else if (pcmk__str_eq(RSC_START, action->task, pcmk__str_casei)) {
406  if (!pcmk_is_set(action->flags, pe_action_runnable)) {
407  pe_rsc_trace(rsc, "Skipping pseudo-op: %s run=%d, pseudo=%d",
408  action->uuid,
411  } else {
412  pe_rsc_trace(rsc, "Starting due to: %s", action->uuid);
413  pe_rsc_trace(rsc, "%s run=%d, pseudo=%d",
414  action->uuid,
417  *starting = TRUE;
418  }
419  }
420  }
421 }
422 
423 static pe_action_t *
424 find_rsc_action(pe_resource_t *rsc, const char *task)
425 {
426  pe_action_t *match = NULL;
427  GList *actions = pe__resource_actions(rsc, NULL, task, FALSE);
428 
429  for (GList *item = actions; item != NULL; item = item->next) {
430  pe_action_t *op = (pe_action_t *) item->data;
431 
432  if (!pcmk_is_set(op->flags, pe_action_optional)) {
433  if (match != NULL) {
434  // More than one match, don't return any
435  match = NULL;
436  break;
437  }
438  match = op;
439  }
440  }
441  g_list_free(actions);
442  return match;
443 }
444 
445 static void
446 child_ordering_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
447 {
448  pe_action_t *stop = NULL;
449  pe_action_t *start = NULL;
450  pe_action_t *last_stop = NULL;
451  pe_action_t *last_start = NULL;
452  GList *gIter = NULL;
453 
454  if (!pe__clone_is_ordered(rsc)) {
455  return;
456  }
457 
458  /* we have to maintain a consistent sorted child list when building order constraints */
459  rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
460 
461  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
462  pe_resource_t *child = (pe_resource_t *) gIter->data;
463 
464  stop = find_rsc_action(child, RSC_STOP);
465  if (stop) {
466  if (last_stop) {
467  /* child/child relative stop */
468  order_actions(stop, last_stop, pe_order_optional);
469  }
470  last_stop = stop;
471  }
472 
473  start = find_rsc_action(child, RSC_START);
474  if (start) {
475  if (last_start) {
476  /* child/child relative start */
477  order_actions(last_start, start, pe_order_optional);
478  }
479  last_start = start;
480  }
481  }
482 }
483 
484 void
486 {
487  clone_variant_data_t *clone_data = NULL;
488 
489  get_clone_variant_data(clone_data, rsc);
490 
491  pe_rsc_debug(rsc, "Creating actions for clone %s", rsc->id);
492  clone_create_pseudo_actions(rsc, rsc->children, &clone_data->start_notify,
493  &clone_data->stop_notify);
494  child_ordering_constraints(rsc, rsc->cluster);
495 
496  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
498  }
499 }
500 
501 void
503  notify_data_t **start_notify,
504  notify_data_t **stop_notify)
505 {
506  gboolean child_active = FALSE;
507  gboolean child_starting = FALSE;
508  gboolean child_stopping = FALSE;
509  gboolean allow_dependent_migrations = TRUE;
510 
511  pe_action_t *stop = NULL;
512  pe_action_t *stopped = NULL;
513 
514  pe_action_t *start = NULL;
515  pe_action_t *started = NULL;
516 
517  pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
518 
519  for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
520  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
521  gboolean starting = FALSE;
522  gboolean stopping = FALSE;
523 
524  child_rsc->cmds->create_actions(child_rsc);
525  clone_update_pseudo_status(child_rsc, &stopping, &starting, &child_active);
526  if (stopping && starting) {
527  allow_dependent_migrations = FALSE;
528  }
529 
530  child_stopping |= stopping;
531  child_starting |= starting;
532  }
533 
534  /* start */
535  start = pe__new_rsc_pseudo_action(rsc, RSC_START, !child_starting, true);
536  started = pe__new_rsc_pseudo_action(rsc, RSC_STARTED, !child_starting,
537  false);
538  started->priority = INFINITY;
539 
540  if (child_active || child_starting) {
542  }
543 
544  if (start_notify != NULL && *start_notify == NULL) {
545  *start_notify = pe__clone_notif_pseudo_ops(rsc, RSC_START, start,
546  started);
547  }
548 
549  /* stop */
550  stop = pe__new_rsc_pseudo_action(rsc, RSC_STOP, !child_stopping, true);
551  stopped = pe__new_rsc_pseudo_action(rsc, RSC_STOPPED, !child_stopping,
552  true);
553  stopped->priority = INFINITY;
554  if (allow_dependent_migrations) {
556  }
557 
558  if (stop_notify != NULL && *stop_notify == NULL) {
559  *stop_notify = pe__clone_notif_pseudo_ops(rsc, RSC_STOP, stop, stopped);
560 
561  if (start_notify && *start_notify && *stop_notify) {
562  order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
563  }
564  }
565 }
566 
567 void
569 {
570  pe_resource_t *last_rsc = NULL;
571  GList *gIter;
572  bool ordered = pe__clone_is_ordered(rsc);
573 
574  pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
581 
582  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
587  }
588 
589  if (ordered) {
590  /* we have to maintain a consistent sorted child list when building order constraints */
591  rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
592  }
593  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
594  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
595 
596  child_rsc->cmds->internal_constraints(child_rsc);
597 
598  pcmk__order_starts(rsc, child_rsc,
602  if (ordered && (last_rsc != NULL)) {
603  pcmk__order_starts(last_rsc, child_rsc, pe_order_optional);
604  }
605 
609  if (ordered && (last_rsc != NULL)) {
610  pcmk__order_stops(child_rsc, last_rsc, pe_order_optional);
611  }
612 
613  last_rsc = child_rsc;
614  }
615  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
617  }
618 }
619 
620 gboolean
621 is_child_compatible(const pe_resource_t *child_rsc, const pe_node_t *local_node,
622  enum rsc_role_e filter, gboolean current)
623 {
624  pe_node_t *node = NULL;
625  enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
626 
627  CRM_CHECK(child_rsc && local_node, return FALSE);
628  if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
629  /* We only want instances that haven't failed */
630  node = child_rsc->fns->location(child_rsc, NULL, current);
631  }
632 
633  if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
634  crm_trace("Filtered %s", child_rsc->id);
635  return FALSE;
636  }
637 
638  if (node && (node->details == local_node->details)) {
639  return TRUE;
640 
641  } else if (node) {
642  crm_trace("%s - %s vs %s", child_rsc->id, pe__node_name(node),
643  pe__node_name(local_node));
644 
645  } else {
646  crm_trace("%s - not allocated %d", child_rsc->id, current);
647  }
648  return FALSE;
649 }
650 
653  const pe_resource_t *rsc, enum rsc_role_e filter,
654  gboolean current)
655 {
656  pe_resource_t *pair = NULL;
657  GList *gIter = NULL;
658  GList *scratch = NULL;
659  pe_node_t *local_node = NULL;
660 
661  local_node = local_child->fns->location(local_child, NULL, current);
662  if (local_node) {
663  return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
664  }
665 
666  scratch = g_hash_table_get_values(local_child->allowed_nodes);
667  scratch = pcmk__sort_nodes(scratch, NULL);
668 
669  gIter = scratch;
670  for (; gIter != NULL; gIter = gIter->next) {
671  pe_node_t *node = (pe_node_t *) gIter->data;
672 
673  pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
674  if (pair) {
675  goto done;
676  }
677  }
678 
679  pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
680  done:
681  g_list_free(scratch);
682  return pair;
683 }
684 
698 void
700  const pe_resource_t *primary,
701  const pcmk__colocation_t *colocation,
702  bool for_dependent)
703 {
704  GList *gIter = NULL;
705  gboolean do_interleave = FALSE;
706  const char *interleave_s = NULL;
707 
708  /* This should never be called for the clone itself as a dependent. Instead,
709  * we add its colocation constraints to its instances and call the
710  * apply_coloc_score() for the instances as dependents.
711  */
712  CRM_ASSERT(!for_dependent);
713 
714  CRM_CHECK((colocation != NULL) && (dependent != NULL) && (primary != NULL),
715  return);
716  CRM_CHECK(dependent->variant == pe_native, return);
717 
718  pe_rsc_trace(primary, "Processing constraint %s: %s -> %s %d",
719  colocation->id, dependent->id, primary->id, colocation->score);
720 
721  if (pcmk_is_set(primary->flags, pe_rsc_promotable)) {
722  if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
723  // We haven't placed the primary yet, so we can't apply colocation
724  pe_rsc_trace(primary, "%s is still provisional", primary->id);
725  return;
726 
727  } else if (colocation->primary_role == RSC_ROLE_UNKNOWN) {
728  // This isn't a role-specfic colocation, so handle normally
729  pe_rsc_trace(primary, "Handling %s as a clone colocation",
730  colocation->id);
731 
732  } else if (pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
733  // We're placing the dependent
734  pcmk__update_dependent_with_promotable(primary, dependent,
735  colocation);
736  return;
737 
738  } else if (colocation->dependent_role == RSC_ROLE_PROMOTED) {
739  // We're choosing roles for the dependent
741  colocation);
742  return;
743  }
744  }
745 
746  // Only the dependent needs to be marked for interleave
747  interleave_s = g_hash_table_lookup(colocation->dependent->meta,
749  if (crm_is_true(interleave_s)
750  && (colocation->dependent->variant > pe_group)) {
751  /* @TODO Do we actually care about multiple primary copies sharing a
752  * dependent copy anymore?
753  */
754  if (copies_per_node(colocation->dependent) != copies_per_node(colocation->primary)) {
755  pcmk__config_err("Cannot interleave %s and %s because they do not "
756  "support the same number of instances per node",
757  colocation->dependent->id,
758  colocation->primary->id);
759 
760  } else {
761  do_interleave = TRUE;
762  }
763  }
764 
765  if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
766  pe_rsc_trace(primary, "%s is still provisional", primary->id);
767  return;
768 
769  } else if (do_interleave) {
770  pe_resource_t *primary_instance = NULL;
771 
772  primary_instance = find_compatible_child(dependent, primary,
773  RSC_ROLE_UNKNOWN, FALSE);
774  if (primary_instance != NULL) {
775  pe_rsc_debug(primary, "Pairing %s with %s",
776  dependent->id, primary_instance->id);
777  dependent->cmds->apply_coloc_score(dependent, primary_instance,
778  colocation, true);
779 
780  } else if (colocation->score >= INFINITY) {
781  crm_notice("Cannot pair %s with instance of %s",
782  dependent->id, primary->id);
783  pcmk__assign_resource(dependent, NULL, true);
784 
785  } else {
786  pe_rsc_debug(primary, "Cannot pair %s with instance of %s",
787  dependent->id, primary->id);
788  }
789 
790  return;
791 
792  } else if (colocation->score >= INFINITY) {
793  GList *affected_nodes = NULL;
794 
795  gIter = primary->children;
796  for (; gIter != NULL; gIter = gIter->next) {
797  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
798  pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
799 
800  if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
801  pe_rsc_trace(primary, "Allowing %s: %s %d",
802  colocation->id, pe__node_name(chosen),
803  chosen->weight);
804  affected_nodes = g_list_prepend(affected_nodes, chosen);
805  }
806  }
807 
808  node_list_exclude(dependent->allowed_nodes, affected_nodes, FALSE);
809  g_list_free(affected_nodes);
810  return;
811  }
812 
813  gIter = primary->children;
814  for (; gIter != NULL; gIter = gIter->next) {
815  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
816 
817  child_rsc->cmds->apply_coloc_score(dependent, child_rsc, colocation,
818  false);
819  }
820 }
821 
822 enum action_tasks
824 {
826  pe_resource_t *child = (pe_resource_t *) action->rsc->children->data;
827 
828  if (pcmk__strcase_any_of(action->task, "notify", "notified", NULL)) {
829 
830  /* Find the action we're notifying about instead */
831 
832  int stop = 0;
833  char *key = action->uuid;
834  int lpc = strlen(key);
835 
836  for (; lpc > 0; lpc--) {
837  if (key[lpc] == '_' && stop == 0) {
838  stop = lpc;
839 
840  } else if (key[lpc] == '_') {
841  char *task_mutable = NULL;
842 
843  lpc++;
844  task_mutable = strdup(key + lpc);
845  task_mutable[stop - lpc] = 0;
846 
847  crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
848  result = get_complex_task(child, task_mutable, TRUE);
849  free(task_mutable);
850  break;
851  }
852  }
853 
854  } else {
855  result = get_complex_task(child, action->task, TRUE);
856  }
857  return result;
858 }
859 
860 #define pe__clear_action_summary_flags(flags, action, flag) do { \
861  flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
862  "Action summary", action->rsc->id, \
863  flags, flag, #flag); \
864  } while (0)
865 
866 enum pe_action_flags
868  const pe_node_t *node)
869 {
870  GList *gIter = NULL;
871  gboolean any_runnable = FALSE;
872  gboolean check_runnable = TRUE;
875  const char *task_s = task2text(task);
876 
877  for (gIter = children; gIter != NULL; gIter = gIter->next) {
878  pe_action_t *child_action = NULL;
879  pe_resource_t *child = (pe_resource_t *) gIter->data;
880 
881  child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
882  pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
883  pe__node_name(node), child_action?child_action->uuid:"NA");
884  if (child_action) {
885  enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
886 
888  && !pcmk_is_set(child_flags, pe_action_optional)) {
889  pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
890  child_action->uuid);
893  }
894  if (pcmk_is_set(child_flags, pe_action_runnable)) {
895  any_runnable = TRUE;
896  }
897  }
898  }
899 
900  if (check_runnable && any_runnable == FALSE) {
901  pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
903  if (node == NULL) {
905  }
906  }
907 
908  return flags;
909 }
910 
911 enum pe_action_flags
913 {
914  return summary_action_flags(action, action->rsc->children, node);
915 }
916 
917 void
919 {
920  GList *gIter = rsc->children;
921 
922  pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
923 
924  pcmk__apply_location(rsc, constraint);
925 
926  for (; gIter != NULL; gIter = gIter->next) {
927  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
928 
929  child_rsc->cmds->apply_location(child_rsc, constraint);
930  }
931 }
932 
939 void
941 {
942  GList *gIter = NULL;
943  clone_variant_data_t *clone_data = NULL;
944 
945  get_clone_variant_data(clone_data, rsc);
946 
947  g_list_foreach(rsc->actions, (GFunc) rsc->cmds->action_flags, NULL);
948 
949  pe__create_notifications(rsc, clone_data->start_notify);
950  pe__create_notifications(rsc, clone_data->stop_notify);
951  pe__create_notifications(rsc, clone_data->promote_notify);
952  pe__create_notifications(rsc, clone_data->demote_notify);
953 
954  /* Now that the notifcations have been created we can expand the children */
955 
956  gIter = rsc->children;
957  for (; gIter != NULL; gIter = gIter->next) {
958  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
959 
960  child_rsc->cmds->add_actions_to_graph(child_rsc);
961  }
962 
964 
965  /* The notifications are in the graph now, we can destroy the notify_data */
966  pe__free_notification_data(clone_data->demote_notify);
967  clone_data->demote_notify = NULL;
968  pe__free_notification_data(clone_data->stop_notify);
969  clone_data->stop_notify = NULL;
970  pe__free_notification_data(clone_data->start_notify);
971  clone_data->start_notify = NULL;
972  pe__free_notification_data(clone_data->promote_notify);
973  clone_data->promote_notify = NULL;
974 }
975 
976 // Check whether a resource or any of its children is known on node
977 static bool
978 rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
979 {
980  if (rsc->children) {
981  for (GList *child_iter = rsc->children; child_iter != NULL;
982  child_iter = child_iter->next) {
983 
984  pe_resource_t *child = (pe_resource_t *) child_iter->data;
985 
986  if (rsc_known_on(child, node)) {
987  return TRUE;
988  }
989  }
990 
991  } else if (rsc->known_on) {
992  GHashTableIter iter;
993  pe_node_t *known_node = NULL;
994 
995  g_hash_table_iter_init(&iter, rsc->known_on);
996  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
997  if (node->details == known_node->details) {
998  return TRUE;
999  }
1000  }
1001  }
1002  return FALSE;
1003 }
1004 
1005 // Look for an instance of clone that is known on node
1006 static pe_resource_t *
1007 find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
1008 {
1009  for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
1010  pe_resource_t *child = (pe_resource_t *) gIter->data;
1011 
1012  if (rsc_known_on(child, node)) {
1013  return child;
1014  }
1015  }
1016  return NULL;
1017 }
1018 
1019 // For anonymous clones, only a single instance needs to be probed
1020 static bool
1021 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
1023 {
1024  // First, check if we probed an instance on this node last time
1025  pe_resource_t *child = find_instance_on(rsc, node);
1026 
1027  // Otherwise, check if we plan to start an instance on this node
1028  if (child == NULL) {
1029  for (GList *child_iter = rsc->children; child_iter && !child;
1030  child_iter = child_iter->next) {
1031 
1032  pe_node_t *local_node = NULL;
1033  pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
1034 
1035  if (child_rsc) { /* make clang analyzer happy */
1036  local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1037  if (local_node && (local_node->details == node->details)) {
1038  child = child_rsc;
1039  }
1040  }
1041  }
1042  }
1043 
1044  // Otherwise, use the first clone instance
1045  if (child == NULL) {
1046  child = rsc->children->data;
1047  }
1048  CRM_ASSERT(child);
1049  return child->cmds->create_probe(child, node);
1050 }
1051 
1062 bool
1064 {
1065  CRM_ASSERT(rsc);
1066 
1067  rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
1068  if (rsc->children == NULL) {
1069  pe_warn("Clone %s has no children", rsc->id);
1070  return false;
1071  }
1072 
1073  if (rsc->exclusive_discover) {
1074  pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1075  if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1076  /* exclusive discover is enabled and this node is not marked
1077  * as a node this resource should be discovered on
1078  *
1079  * remove the node from allowed_nodes so that the
1080  * notification contains only nodes that we might ever run
1081  * on
1082  */
1083  g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1084 
1085  /* Bit of a shortcut - might as well take it */
1086  return false;
1087  }
1088  }
1089 
1090  if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1091  return pcmk__probe_resource_list(rsc->children, node);
1092  } else {
1093  return probe_anonymous_clone(rsc, node, rsc->cluster);
1094  }
1095 }
1096 
1097 void
1098 clone_append_meta(pe_resource_t * rsc, xmlNode * xml)
1099 {
1100  char *name = NULL;
1101  clone_variant_data_t *clone_data = NULL;
1102 
1103  get_clone_variant_data(clone_data, rsc);
1104 
1106  crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1107  free(name);
1108 
1110  crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1111  free(name);
1112 
1114  crm_xml_add_int(xml, name, clone_data->clone_max);
1115  free(name);
1116 
1118  crm_xml_add_int(xml, name, clone_data->clone_node_max);
1119  free(name);
1120 
1121  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1122  int promoted_max = pe__clone_promoted_max(rsc);
1123  int promoted_node_max = pe__clone_promoted_node_max(rsc);
1124 
1126  crm_xml_add_int(xml, name, promoted_max);
1127  free(name);
1128 
1130  crm_xml_add_int(xml, name, promoted_node_max);
1131  free(name);
1132 
1133  /* @COMPAT Maintain backward compatibility with resource agents that
1134  * expect the old names (deprecated since 2.0.0).
1135  */
1137  crm_xml_add_int(xml, name, promoted_max);
1138  free(name);
1139 
1141  crm_xml_add_int(xml, name, promoted_node_max);
1142  free(name);
1143  }
1144 }
1145 
1146 // Clone implementation of resource_alloc_functions_t:add_utilization()
1147 void
1149  const pe_resource_t *orig_rsc, GList *all_rscs,
1150  GHashTable *utilization)
1151 {
1152  bool existing = false;
1153  pe_resource_t *child = NULL;
1154 
1155  if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
1156  return;
1157  }
1158 
1159  // Look for any child already existing in the list
1160  for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
1161  child = (pe_resource_t *) iter->data;
1162  if (g_list_find(all_rscs, child)) {
1163  existing = true; // Keep checking remaining children
1164  } else {
1165  // If this is a clone of a group, look for group's members
1166  for (GList *member_iter = child->children; member_iter != NULL;
1167  member_iter = member_iter->next) {
1168 
1169  pe_resource_t *member = (pe_resource_t *) member_iter->data;
1170 
1171  if (g_list_find(all_rscs, member) != NULL) {
1172  // Add *child's* utilization, not group member's
1173  child->cmds->add_utilization(child, orig_rsc, all_rscs,
1174  utilization);
1175  existing = true;
1176  break;
1177  }
1178  }
1179  }
1180  }
1181 
1182  if (!existing && (rsc->children != NULL)) {
1183  // If nothing was found, still add first child's utilization
1184  child = (pe_resource_t *) rsc->children->data;
1185 
1186  child->cmds->add_utilization(child, orig_rsc, all_rscs, utilization);
1187  }
1188 }
1189 
1190 // Clone implementation of resource_alloc_functions_t:shutdown_lock()
1191 void
1193 {
1194  return; // Clones currently don't support shutdown locks
1195 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define PCMK_XA_PROMOTED_MAX_LEGACY
Definition: msg_xml.h:49
const char * task2text(enum action_tasks task)
Definition: common.c:401
#define pcmk__order_starts(rsc1, rsc2, flags)
#define RSC_STOP
Definition: crm.h:202
#define crm_notice(fmt, args...)
Definition: logging.h:361
GHashTable * known_on
Definition: pe_types.h:374
G_GNUC_INTERNAL void pcmk__add_rsc_actions_to_graph(pe_resource_t *rsc)
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:46
#define INFINITY
Definition: crm.h:99
GList * rsc_cons
Definition: pe_types.h:364
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:394
int pe__clone_promoted_node_max(pe_resource_t *clone)
Definition: clone.c:59
#define pe__clear_action_summary_flags(flags, action, flag)
int priority
Definition: pe_types.h:404
const char * name
Definition: cib.c:24
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
void(* internal_constraints)(pe_resource_t *rsc)
GList * children
Definition: pe_types.h:384
int count
Definition: pe_types.h:251
resource_alloc_functions_t * cmds
Definition: pe_types.h:341
#define pcmk__order_stops(rsc1, rsc2, flags)
void pcmk__clone_shutdown_lock(pe_resource_t *rsc)
int pe__clone_promoted_max(pe_resource_t *clone)
Definition: clone.c:42
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:419
gboolean exclusive_discover
Definition: pe_types.h:359
void clone_create_actions(pe_resource_t *rsc)
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1296
#define pcmk__config_err(fmt...)
GHashTable * meta
Definition: pe_types.h:380
#define pe_rsc_unique
Definition: pe_types.h:262
#define pe_rsc_notify
Definition: pe_types.h:261
G_GNUC_INTERNAL void pcmk__set_instance_roles(pe_resource_t *rsc)
resource_object_functions_t * fns
Definition: pe_types.h:340
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
pe_resource_t * dependent
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:108
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
void resource_location(pe_resource_t *rsc, pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:385
GList * rsc_cons_lhs
Definition: pe_types.h:363
pe_action_t * pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1647
#define RSC_START
Definition: crm.h:199
G_GNUC_INTERNAL void pcmk__add_with_this(pe_resource_t *rsc, pcmk__colocation_t *colocation)
G_GNUC_INTERNAL void pcmk__add_colocated_node_scores(pe_resource_t *rsc, const char *log_id, GHashTable **nodes, const char *attr, float factor, uint32_t flags)
#define XML_RSC_ATTR_INCARNATION_MAX
Definition: msg_xml.h:229
void(* add_actions_to_graph)(pe_resource_t *rsc)
void clone_internal_constraints(pe_resource_t *rsc)
char * crm_meta_name(const char *field)
Definition: utils.c:468
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
pe_node_t *(* assign)(pe_resource_t *rsc, const pe_node_t *prefer)
enum pe_action_flags(* action_flags)(pe_action_t *action, const pe_node_t *node)
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
Definition: msg_xml.h:50
void clone_create_pseudo_actions(pe_resource_t *rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify)
#define pe_rsc_provisional
Definition: pe_types.h:266
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55
#define pe_warn(fmt...)
Definition: internal.h:54
int weight
Definition: pe_types.h:249
#define crm_warn(fmt, args...)
Definition: logging.h:360
void clone_append_meta(pe_resource_t *rsc, xmlNode *xml)
pe_action_flags
Definition: pe_types.h:298
#define pe_rsc_failed
Definition: pe_types.h:276
G_GNUC_INTERNAL bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
enum pe_action_flags clone_action_flags(pe_action_t *action, const pe_node_t *node)
pe_resource_t * primary
G_GNUC_INTERNAL void pcmk__order_promotable_instances(pe_resource_t *clone)
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
#define crm_trace(fmt, args...)
Definition: logging.h:365
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: pe_actions.c:1262
G_GNUC_INTERNAL bool pcmk__probe_resource_list(GList *rscs, pe_node_t *node)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
struct pe_node_shared_s * details
Definition: pe_types.h:252
G_GNUC_INTERNAL gint pcmk__cmp_instance(gconstpointer a, gconstpointer b)
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:474
unsigned long long flags
Definition: pe_types.h:355
const char * uname
Definition: pe_types.h:216
#define pe_rsc_promotable
Definition: pe_types.h:264
pe_working_set_t * data_set
void(* create_actions)(pe_resource_t *rsc)
void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes, int max, int per_host_max, pe_working_set_t *data_set)
GList * actions
Definition: pe_types.h:366
bool pe__clone_is_ordered(pe_resource_t *clone)
Definition: clone.c:1216
pe_resource_t * find_compatible_child_by_node(const pe_resource_t *local_child, const pe_node_t *local_node, const pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:231
bool is_set_recursive(const pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:496
char * uuid
Definition: pe_types.h:411
G_GNUC_INTERNAL gint pcmk__cmp_instance_number(gconstpointer a, gconstpointer b)
#define pe_rsc_allocating
Definition: pe_types.h:267
enum pe_obj_types variant
Definition: pe_types.h:338
void(* add_utilization)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void common_update_score(pe_resource_t *rsc, const char *id, int score)
Definition: complex.c:873
#define RSC_DEMOTED
Definition: crm.h:208
G_GNUC_INTERNAL void pcmk__unassign_resource(pe_resource_t *rsc)
int rsc_discover_mode
Definition: pe_types.h:253
#define XML_RSC_ATTR_NOTIFY
Definition: msg_xml.h:238
const char * id
Definition: pe_types.h:215
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
void(* apply_coloc_score)(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
enum action_tasks clone_child_action(pe_action_t *action)
pe_node_t * pcmk__clone_allocate(pe_resource_t *rsc, const pe_node_t *prefer)
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:237
void pe__free_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:945
G_GNUC_INTERNAL void pcmk__update_dependent_with_promotable(const pe_resource_t *primary, pe_resource_t *dependent, const pcmk__colocation_t *colocation)
Update dependent for a colocation with a promotable clone.
G_GNUC_INTERNAL void pcmk__apply_location(pe_resource_t *rsc, pe__location_t *constraint)
void pe__create_notifications(pe_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:928
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition: pe_types.h:54
#define XML_RSC_ATTR_PROMOTED_MAX
Definition: msg_xml.h:233
bool(* create_probe)(pe_resource_t *rsc, pe_node_t *node)
#define RSC_STARTED
Definition: crm.h:200
pcmk__action_result_t result
Definition: pcmk_fence.c:35
void pcmk__clone_apply_coloc_score(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
G_GNUC_INTERNAL GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define crm_err(fmt, args...)
Definition: logging.h:359
#define CRM_ASSERT(expr)
Definition: results.h:42
void clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
G_GNUC_INTERNAL pe_node_t * pcmk__top_allowed_node(const pe_resource_t *rsc, const pe_node_t *node)
#define RSC_PROMOTE
Definition: crm.h:205
G_GNUC_INTERNAL void pcmk__create_promotable_actions(pe_resource_t *clone)
G_GNUC_INTERNAL void pcmk__update_promotable_dependent_priority(const pe_resource_t *primary, pe_resource_t *dependent, const pcmk__colocation_t *colocation)
G_GNUC_INTERNAL bool pcmk__assign_resource(pe_resource_t *rsc, pe_node_t *node, bool force)
pe_resource_t * find_compatible_child(const pe_resource_t *local_child, const pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
G_GNUC_INTERNAL void pcmk__add_promotion_scores(pe_resource_t *rsc)
void clone_expand(pe_resource_t *rsc)
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
#define XML_RSC_ATTR_PROMOTED_NODEMAX
Definition: msg_xml.h:234
GList * running_on
Definition: pe_types.h:373
#define pe_rsc_block
Definition: pe_types.h:258
enum pe_action_flags flags
Definition: pe_types.h:415
pe_working_set_t * cluster
Definition: pe_types.h:335
const char * node_attribute
#define RSC_STOPPED
Definition: crm.h:203
G_GNUC_INTERNAL void pcmk__add_this_with(pe_resource_t *rsc, pcmk__colocation_t *colocation)
bool clone_create_probe(pe_resource_t *rsc, pe_node_t *node)
gboolean crm_is_true(const char *s)
Definition: strings.c:416
void(* apply_location)(pe_resource_t *rsc, pe__location_t *location)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
notify_data_t * pe__clone_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
Definition: pe_notif.c:428
unsigned long long flags
Definition: pe_types.h:153
#define XML_RSC_ATTR_INTERLEAVE
Definition: msg_xml.h:227
GList * pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
Definition: pe_actions.c:1398
gboolean is_child_compatible(const pe_resource_t *child_rsc, const pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, const pe_node_t *node)
#define pe_flag_show_scores
Definition: pe_types.h:134
#define crm_info(fmt, args...)
Definition: logging.h:362
#define pe_rsc_managed
Definition: pe_types.h:257
#define pe_rsc_orphan
Definition: pe_types.h:256
void pcmk__clone_add_utilization(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
uint64_t flags
Definition: remote.c:215
action_tasks
Definition: common.h:61
pe_resource_t * parent
Definition: pe_types.h:336
int copies_per_node(pe_resource_t *rsc)
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375