pacemaker  2.1.2-ada5c3b36
Scalable High-Availability cluster resource manager
pcmk_sched_clone.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2021 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 gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
21 static void append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all);
22 
23 static gint
24 sort_rsc_id(gconstpointer a, gconstpointer b)
25 {
26  const pe_resource_t *resource1 = (const pe_resource_t *)a;
27  const pe_resource_t *resource2 = (const pe_resource_t *)b;
28  long num1, num2;
29 
30  CRM_ASSERT(resource1 != NULL);
31  CRM_ASSERT(resource2 != NULL);
32 
33  /*
34  * Sort clone instances numerically by instance number, so instance :10
35  * comes after :9.
36  */
37  num1 = strtol(strrchr(resource1->id, ':') + 1, NULL, 10);
38  num2 = strtol(strrchr(resource2->id, ':') + 1, NULL, 10);
39  if (num1 < num2) {
40  return -1;
41  } else if (num1 > num2) {
42  return 1;
43  }
44  return 0;
45 }
46 
47 static pe_node_t *
48 parent_node_instance(const pe_resource_t * rsc, pe_node_t * node)
49 {
50  pe_node_t *ret = NULL;
51 
52  if (node != NULL && rsc->parent) {
53  ret = pe_hash_table_lookup(rsc->parent->allowed_nodes, node->details->id);
54  } else if(node != NULL) {
55  ret = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
56  }
57  return ret;
58 }
59 
60 static gboolean
61 did_fail(const pe_resource_t * rsc)
62 {
63  GList *gIter = rsc->children;
64 
65  if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
66  return TRUE;
67  }
68 
69  for (; gIter != NULL; gIter = gIter->next) {
70  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
71 
72  if (did_fail(child_rsc)) {
73  return TRUE;
74  }
75  }
76  return FALSE;
77 }
78 
95 static int
96 order_instance_by_colocation(const pe_resource_t *rsc1,
97  const pe_resource_t *rsc2,
98  pe_working_set_t *data_set)
99 {
100  int rc = 0;
101  pe_node_t *n = NULL;
102  pe_node_t *node1 = NULL;
103  pe_node_t *node2 = NULL;
104  pe_node_t *current_node1 = pe__current_node(rsc1);
105  pe_node_t *current_node2 = pe__current_node(rsc2);
106  GList *list1 = NULL;
107  GList *list2 = NULL;
108  GHashTable *hash1 = pcmk__strkey_table(NULL, free);
109  GHashTable *hash2 = pcmk__strkey_table(NULL, free);
110 
111  /* Clone instances must have parents */
112  CRM_ASSERT(rsc1->parent != NULL);
113  CRM_ASSERT(rsc2->parent != NULL);
114 
115  n = pe__copy_node(current_node1);
116  g_hash_table_insert(hash1, (gpointer) n->details->id, n);
117 
118  n = pe__copy_node(current_node2);
119  g_hash_table_insert(hash2, (gpointer) n->details->id, n);
120 
121  /* Apply rsc1's parental colocations */
122  for (GList *gIter = rsc1->parent->rsc_cons; gIter != NULL;
123  gIter = gIter->next) {
124 
125  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
126 
127  crm_trace("Applying %s to %s", constraint->id, rsc1->id);
128 
129  hash1 = pcmk__native_merge_weights(constraint->primary, rsc1->id, hash1,
130  constraint->node_attribute,
131  constraint->score / (float) INFINITY,
132  0);
133  }
134 
135  for (GList *gIter = rsc1->parent->rsc_cons_lhs; gIter != NULL;
136  gIter = gIter->next) {
137 
138  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
139 
140  if (!pcmk__colocation_has_influence(constraint, rsc1)) {
141  continue;
142  }
143  crm_trace("Applying %s to %s", constraint->id, rsc1->id);
144 
145  hash1 = pcmk__native_merge_weights(constraint->dependent, rsc1->id,
146  hash1, constraint->node_attribute,
147  constraint->score / (float) INFINITY,
149  }
150 
151  /* Apply rsc2's parental colocations */
152  for (GList *gIter = rsc2->parent->rsc_cons; gIter != NULL;
153  gIter = gIter->next) {
154 
155  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
156 
157  crm_trace("Applying %s to %s", constraint->id, rsc2->id);
158 
159  hash2 = pcmk__native_merge_weights(constraint->primary, rsc2->id, hash2,
160  constraint->node_attribute,
161  constraint->score / (float) INFINITY,
162  0);
163  }
164 
165  for (GList *gIter = rsc2->parent->rsc_cons_lhs; gIter;
166  gIter = gIter->next) {
167 
168  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
169 
170  if (!pcmk__colocation_has_influence(constraint, rsc2)) {
171  continue;
172  }
173  crm_trace("Applying %s to %s", constraint->id, rsc2->id);
174 
175  hash2 = pcmk__native_merge_weights(constraint->dependent, rsc2->id,
176  hash2, constraint->node_attribute,
177  constraint->score / (float) INFINITY,
179  }
180 
181  /* Current location score */
182  node1 = g_hash_table_lookup(hash1, current_node1->details->id);
183  node2 = g_hash_table_lookup(hash2, current_node2->details->id);
184 
185  if (node1->weight < node2->weight) {
186  if (node1->weight < 0) {
187  crm_trace("%s > %s: current score: %d %d",
188  rsc1->id, rsc2->id, node1->weight, node2->weight);
189  rc = -1;
190  goto out;
191 
192  } else {
193  crm_trace("%s < %s: current score: %d %d",
194  rsc1->id, rsc2->id, node1->weight, node2->weight);
195  rc = 1;
196  goto out;
197  }
198 
199  } else if (node1->weight > node2->weight) {
200  crm_trace("%s > %s: current score: %d %d",
201  rsc1->id, rsc2->id, node1->weight, node2->weight);
202  rc = -1;
203  goto out;
204  }
205 
206  /* All location scores */
207  list1 = g_hash_table_get_values(hash1);
208  list2 = g_hash_table_get_values(hash2);
209 
210  list1 = sort_nodes_by_weight(list1, current_node1, data_set);
211  list2 = sort_nodes_by_weight(list2, current_node2, data_set);
212 
213  for (GList *gIter1 = list1, *gIter2 = list2;
214  (gIter1 != NULL) && (gIter2 != NULL);
215  gIter1 = gIter1->next, gIter2 = gIter2->next) {
216 
217  node1 = (pe_node_t *) gIter1->data;
218  node2 = (pe_node_t *) gIter2->data;
219 
220  if (node1 == NULL) {
221  crm_trace("%s < %s: colocated score NULL", rsc1->id, rsc2->id);
222  rc = 1;
223  break;
224 
225  } else if (node2 == NULL) {
226  crm_trace("%s > %s: colocated score NULL", rsc1->id, rsc2->id);
227  rc = -1;
228  break;
229  }
230 
231  if (node1->weight < node2->weight) {
232  crm_trace("%s < %s: colocated score", rsc1->id, rsc2->id);
233  rc = 1;
234  break;
235 
236  } else if (node1->weight > node2->weight) {
237  crm_trace("%s > %s: colocated score", rsc1->id, rsc2->id);
238  rc = -1;
239  break;
240  }
241  }
242 
243 out:
244  g_hash_table_destroy(hash1);
245  g_hash_table_destroy(hash2);
246  g_list_free(list1);
247  g_list_free(list2);
248 
249  return rc;
250 }
251 
252 gint
253 sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
254 {
255  int rc = 0;
256  pe_node_t *node1 = NULL;
257  pe_node_t *node2 = NULL;
258  pe_node_t *current_node1 = NULL;
259  pe_node_t *current_node2 = NULL;
260  unsigned int nnodes1 = 0;
261  unsigned int nnodes2 = 0;
262 
263  gboolean can1 = TRUE;
264  gboolean can2 = TRUE;
265 
266  const pe_resource_t *resource1 = (const pe_resource_t *)a;
267  const pe_resource_t *resource2 = (const pe_resource_t *)b;
268 
269  CRM_ASSERT(resource1 != NULL);
270  CRM_ASSERT(resource2 != NULL);
271 
272  /* allocation order:
273  * - active instances
274  * - instances running on nodes with the least copies
275  * - active instances on nodes that can't support them or are to be fenced
276  * - failed instances
277  * - inactive instances
278  */
279 
280  current_node1 = pe__find_active_on(resource1, &nnodes1, NULL);
281  current_node2 = pe__find_active_on(resource2, &nnodes2, NULL);
282 
283  /* If both instances are running and at least one is multiply
284  * active, give precedence to the one that's running on fewer nodes.
285  */
286  if ((nnodes1 > 0) && (nnodes2 > 0)) {
287  if (nnodes1 < nnodes2) {
288  crm_trace("%s < %s: running_on", resource1->id, resource2->id);
289  return -1;
290 
291  } else if (nnodes1 > nnodes2) {
292  crm_trace("%s > %s: running_on", resource1->id, resource2->id);
293  return 1;
294  }
295  }
296 
297  /* Instance whose current location is available sorts first */
298  node1 = current_node1;
299  node2 = current_node2;
300  if (node1 != NULL) {
301  pe_node_t *match = pe_hash_table_lookup(resource1->allowed_nodes, node1->details->id);
302 
303  if (match == NULL || match->weight < 0) {
304  crm_trace("%s: current location is unavailable", resource1->id);
305  node1 = NULL;
306  can1 = FALSE;
307  }
308  }
309 
310  if (node2 != NULL) {
311  pe_node_t *match = pe_hash_table_lookup(resource2->allowed_nodes, node2->details->id);
312 
313  if (match == NULL || match->weight < 0) {
314  crm_trace("%s: current location is unavailable", resource2->id);
315  node2 = NULL;
316  can2 = FALSE;
317  }
318  }
319 
320  if (can1 && !can2) {
321  crm_trace("%s < %s: availability of current location", resource1->id,
322  resource2->id);
323  return -1;
324 
325  } else if (!can1 && can2) {
326  crm_trace("%s > %s: availability of current location", resource1->id,
327  resource2->id);
328  return 1;
329  }
330 
331  /* Higher-priority instance sorts first */
332  if (resource1->priority > resource2->priority) {
333  crm_trace("%s < %s: priority", resource1->id, resource2->id);
334  return -1;
335 
336  } else if (resource1->priority < resource2->priority) {
337  crm_trace("%s > %s: priority", resource1->id, resource2->id);
338  return 1;
339  }
340 
341  /* Active instance sorts first */
342  if (node1 == NULL && node2 == NULL) {
343  crm_trace("%s == %s: not active", resource1->id, resource2->id);
344  return 0;
345 
346  } else if (node1 == NULL) {
347  crm_trace("%s > %s: active", resource1->id, resource2->id);
348  return 1;
349 
350  } else if (node2 == NULL) {
351  crm_trace("%s < %s: active", resource1->id, resource2->id);
352  return -1;
353  }
354 
355  /* Instance whose current node can run resources sorts first */
356  can1 = can_run_resources(node1);
357  can2 = can_run_resources(node2);
358  if (can1 && !can2) {
359  crm_trace("%s < %s: can", resource1->id, resource2->id);
360  return -1;
361 
362  } else if (!can1 && can2) {
363  crm_trace("%s > %s: can", resource1->id, resource2->id);
364  return 1;
365  }
366 
367  /* Is the parent allowed to run on the instance's current node?
368  * Instance with parent allowed sorts first.
369  */
370  node1 = parent_node_instance(resource1, node1);
371  node2 = parent_node_instance(resource2, node2);
372  if (node1 == NULL && node2 == NULL) {
373  crm_trace("%s == %s: not allowed", resource1->id, resource2->id);
374  return 0;
375 
376  } else if (node1 == NULL) {
377  crm_trace("%s > %s: not allowed", resource1->id, resource2->id);
378  return 1;
379 
380  } else if (node2 == NULL) {
381  crm_trace("%s < %s: not allowed", resource1->id, resource2->id);
382  return -1;
383  }
384 
385  /* Does one node have more instances allocated?
386  * Instance whose current node has fewer instances sorts first.
387  */
388  if (node1->count < node2->count) {
389  crm_trace("%s < %s: count", resource1->id, resource2->id);
390  return -1;
391 
392  } else if (node1->count > node2->count) {
393  crm_trace("%s > %s: count", resource1->id, resource2->id);
394  return 1;
395  }
396 
397  /* Failed instance sorts first */
398  can1 = did_fail(resource1);
399  can2 = did_fail(resource2);
400  if (can1 && !can2) {
401  crm_trace("%s > %s: failed", resource1->id, resource2->id);
402  return 1;
403  } else if (!can1 && can2) {
404  crm_trace("%s < %s: failed", resource1->id, resource2->id);
405  return -1;
406  }
407 
408  rc = order_instance_by_colocation(resource1, resource2, data_set);
409  if (rc != 0) {
410  return rc;
411  }
412 
413  /* Default to lexicographic order by ID */
414  rc = strcmp(resource1->id, resource2->id);
415  crm_trace("%s %c %s: default", resource1->id, rc < 0 ? '<' : '>', resource2->id);
416  return rc;
417 }
418 
419 static pe_node_t *
420 can_run_instance(pe_resource_t * rsc, pe_node_t * node, int limit)
421 {
422  pe_node_t *local_node = NULL;
423 
424  if (node == NULL && rsc->allowed_nodes) {
425  GHashTableIter iter;
426  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
427  while (g_hash_table_iter_next(&iter, NULL, (void **)&local_node)) {
428  can_run_instance(rsc, local_node, limit);
429  }
430  return NULL;
431  }
432 
433  if (!node) {
434  /* make clang analyzer happy */
435  goto bail;
436 
437  } else if (can_run_resources(node) == FALSE) {
438  goto bail;
439 
440  } else if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
441  goto bail;
442  }
443 
444  local_node = parent_node_instance(rsc, node);
445 
446  if (local_node == NULL) {
447  crm_warn("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
448  goto bail;
449 
450  } else if (local_node->weight < 0) {
451  common_update_score(rsc, node->details->id, local_node->weight);
452  pe_rsc_trace(rsc, "%s cannot run on %s: Parent node weight doesn't allow it.",
453  rsc->id, node->details->uname);
454 
455  } else if (local_node->count < limit) {
456  pe_rsc_trace(rsc, "%s can run on %s (already running %d)",
457  rsc->id, node->details->uname, local_node->count);
458  return local_node;
459 
460  } else {
461  pe_rsc_trace(rsc, "%s cannot run on %s: node full (%d >= %d)",
462  rsc->id, node->details->uname, local_node->count, limit);
463  }
464 
465  bail:
466  if (node) {
467  common_update_score(rsc, node->details->id, -INFINITY);
468  }
469  return NULL;
470 }
471 
472 static pe_node_t *
473 allocate_instance(pe_resource_t *rsc, pe_node_t *prefer, gboolean all_coloc,
474  int limit, pe_working_set_t *data_set)
475 {
476  pe_node_t *chosen = NULL;
477  GHashTable *backup = NULL;
478 
479  CRM_ASSERT(rsc);
480  pe_rsc_trace(rsc, "Checking allocation of %s (preferring %s, using %s parent colocations)",
481  rsc->id, (prefer? prefer->details->uname: "none"),
482  (all_coloc? "all" : "some"));
483 
484  if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
485  return rsc->fns->location(rsc, NULL, FALSE);
486 
487  } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
488  pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
489  return NULL;
490  }
491 
492  /* Only include positive colocation preferences of dependent resources
493  * if not every node will get a copy of the clone
494  */
495  append_parent_colocation(rsc->parent, rsc, all_coloc);
496 
497  if (prefer) {
498  pe_node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
499 
500  if (local_prefer == NULL || local_prefer->weight < 0) {
501  pe_rsc_trace(rsc, "Not pre-allocating %s to %s - unavailable", rsc->id,
502  prefer->details->uname);
503  return NULL;
504  }
505  }
506 
507  can_run_instance(rsc, NULL, limit);
508 
509  backup = pcmk__copy_node_table(rsc->allowed_nodes);
510  pe_rsc_trace(rsc, "Allocating instance %s", rsc->id);
511  chosen = rsc->cmds->allocate(rsc, prefer, data_set);
512  if (chosen && prefer && (chosen->details != prefer->details)) {
513  crm_info("Not pre-allocating %s to %s because %s is better",
514  rsc->id, prefer->details->uname, chosen->details->uname);
515  g_hash_table_destroy(rsc->allowed_nodes);
516  rsc->allowed_nodes = backup;
517  native_deallocate(rsc);
518  chosen = NULL;
519  backup = NULL;
520  }
521  if (chosen) {
522  pe_node_t *local_node = parent_node_instance(rsc, chosen);
523 
524  if (local_node) {
525  local_node->count++;
526 
527  } else if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
528  /* what to do? we can't enforce per-node limits in this case */
529  pcmk__config_err("%s not found in %s (list of %d)",
530  chosen->details->id, rsc->parent->id,
531  g_hash_table_size(rsc->parent->allowed_nodes));
532  }
533  }
534 
535  if(backup) {
536  g_hash_table_destroy(backup);
537  }
538  return chosen;
539 }
540 
541 static void
542 append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all)
543 {
544 
545  GList *gIter = NULL;
546 
547  gIter = rsc->rsc_cons;
548  for (; gIter != NULL; gIter = gIter->next) {
549  pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
550 
551  if (all || cons->score < 0 || cons->score == INFINITY) {
552  child->rsc_cons = g_list_prepend(child->rsc_cons, cons);
553  }
554  }
555 
556  gIter = rsc->rsc_cons_lhs;
557  for (; gIter != NULL; gIter = gIter->next) {
558  pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
559 
560  if (!pcmk__colocation_has_influence(cons, child)) {
561  continue;
562  }
563  if (all || cons->score < 0) {
564  child->rsc_cons_lhs = g_list_prepend(child->rsc_cons_lhs, cons);
565  }
566  }
567 }
568 
569 
570 void
571 distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
572  int max, int per_host_max, pe_working_set_t * data_set);
573 
574 void
575 distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
576  int max, int per_host_max, pe_working_set_t * data_set)
577 {
578  int loop_max = 0;
579  int allocated = 0;
580  int available_nodes = 0;
581  bool all_coloc = false;
582 
583  /* count now tracks the number of clones currently allocated */
584  for(GList *nIter = nodes; nIter != NULL; nIter = nIter->next) {
585  pe_node_t *node = nIter->data;
586 
587  node->count = 0;
588  if (can_run_resources(node)) {
589  available_nodes++;
590  }
591  }
592 
593  all_coloc = (max < available_nodes) ? true : false;
594 
595  if(available_nodes) {
596  loop_max = max / available_nodes;
597  }
598  if (loop_max < 1) {
599  loop_max = 1;
600  }
601 
602  pe_rsc_debug(rsc, "Allocating up to %d %s instances to a possible %d nodes (at most %d per host, %d optimal)",
603  max, rsc->id, available_nodes, per_host_max, loop_max);
604 
605  /* Pre-allocate as many instances as we can to their current location */
606  for (GList *gIter = children; gIter != NULL && allocated < max; gIter = gIter->next) {
607  pe_resource_t *child = (pe_resource_t *) gIter->data;
608  pe_node_t *child_node = NULL;
609  pe_node_t *local_node = NULL;
610 
611  if ((child->running_on == NULL)
613  || pcmk_is_set(child->flags, pe_rsc_failed)) {
614 
615  continue;
616  }
617 
618  child_node = pe__current_node(child);
619  local_node = parent_node_instance(child, child_node);
620 
621  pe_rsc_trace(rsc,
622  "Checking pre-allocation of %s to %s (%d remaining of %d)",
623  child->id, child_node->details->uname, max - allocated,
624  max);
625 
626  if (!can_run_resources(child_node) || (child_node->weight < 0)) {
627  pe_rsc_trace(rsc, "Not pre-allocating because %s can not run %s",
628  child_node->details->uname, child->id);
629  continue;
630  }
631 
632  if ((local_node != NULL) && (local_node->count >= loop_max)) {
633  pe_rsc_trace(rsc,
634  "Not pre-allocating because %s already allocated "
635  "optimal instances", child_node->details->uname);
636  continue;
637  }
638 
639  if (allocate_instance(child, child_node, all_coloc, per_host_max,
640  data_set)) {
641  pe_rsc_trace(rsc, "Pre-allocated %s to %s", child->id,
642  child_node->details->uname);
643  allocated++;
644  }
645  }
646 
647  pe_rsc_trace(rsc, "Done pre-allocating (%d of %d)", allocated, max);
648 
649  for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
650  pe_resource_t *child = (pe_resource_t *) gIter->data;
651 
652  if (child->running_on != NULL) {
653  pe_node_t *child_node = pe__current_node(child);
654  pe_node_t *local_node = parent_node_instance(child, child_node);
655 
656  if (local_node == NULL) {
657  crm_err("%s is running on %s which isn't allowed",
658  child->id, child_node->details->uname);
659  }
660  }
661 
662  if (!pcmk_is_set(child->flags, pe_rsc_provisional)) {
663  } else if (allocated >= max) {
664  pe_rsc_debug(rsc, "Child %s not allocated - limit reached %d %d", child->id, allocated, max);
665  resource_location(child, NULL, -INFINITY, "clone:limit_reached", data_set);
666  } else {
667  if (allocate_instance(child, NULL, all_coloc, per_host_max,
668  data_set)) {
669  allocated++;
670  }
671  }
672  }
673 
674  pe_rsc_debug(rsc, "Allocated %d %s instances of a possible %d",
675  allocated, rsc->id, max);
676 }
677 
678 
679 pe_node_t *
681  pe_working_set_t *data_set)
682 {
683  GList *nodes = NULL;
684  clone_variant_data_t *clone_data = NULL;
685 
686  get_clone_variant_data(clone_data, rsc);
687 
688  if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
689  return NULL;
690 
691  } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
692  pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
693  return NULL;
694  }
695 
696  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
698  }
699 
701 
702  /* this information is used by sort_clone_instance() when deciding in which
703  * order to allocate clone instances
704  */
705  for (GList *gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
706  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
707 
708  pe_rsc_trace(rsc, "%s: Allocating %s first",
709  rsc->id, constraint->primary->id);
710  constraint->primary->cmds->allocate(constraint->primary, prefer,
711  data_set);
712  }
713 
714  for (GList *gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
715  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
716 
717  if (!pcmk__colocation_has_influence(constraint, NULL)) {
718  continue;
719  }
720  rsc->allowed_nodes = constraint->dependent->cmds->merge_weights(
721  constraint->dependent, rsc->id, rsc->allowed_nodes,
722  constraint->node_attribute, (float)constraint->score / INFINITY,
724  }
725 
727  rsc, __func__, rsc->allowed_nodes, data_set);
728 
729  nodes = g_hash_table_get_values(rsc->allowed_nodes);
730  nodes = sort_nodes_by_weight(nodes, NULL, data_set);
731  rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set);
732  distribute_children(rsc, rsc->children, nodes, clone_data->clone_max, clone_data->clone_node_max, data_set);
733  g_list_free(nodes);
734 
735  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
736  pcmk__set_instance_roles(rsc, data_set);
737  }
738 
740  pe_rsc_trace(rsc, "Done allocating %s", rsc->id);
741  return NULL;
742 }
743 
744 static void
745 clone_update_pseudo_status(pe_resource_t * rsc, gboolean * stopping, gboolean * starting,
746  gboolean * active)
747 {
748  GList *gIter = NULL;
749 
750  if (rsc->children) {
751 
752  gIter = rsc->children;
753  for (; gIter != NULL; gIter = gIter->next) {
754  pe_resource_t *child = (pe_resource_t *) gIter->data;
755 
756  clone_update_pseudo_status(child, stopping, starting, active);
757  }
758 
759  return;
760  }
761 
762  CRM_ASSERT(active != NULL);
763  CRM_ASSERT(starting != NULL);
764  CRM_ASSERT(stopping != NULL);
765 
766  if (rsc->running_on) {
767  *active = TRUE;
768  }
769 
770  gIter = rsc->actions;
771  for (; gIter != NULL; gIter = gIter->next) {
772  pe_action_t *action = (pe_action_t *) gIter->data;
773 
774  if (*starting && *stopping) {
775  return;
776 
777  } else if (pcmk_is_set(action->flags, pe_action_optional)) {
778  pe_rsc_trace(rsc, "Skipping optional: %s", action->uuid);
779  continue;
780 
781  } else if (!pcmk_any_flags_set(action->flags,
783  pe_rsc_trace(rsc, "Skipping unrunnable: %s", action->uuid);
784  continue;
785 
786  } else if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_casei)) {
787  pe_rsc_trace(rsc, "Stopping due to: %s", action->uuid);
788  *stopping = TRUE;
789 
790  } else if (pcmk__str_eq(RSC_START, action->task, pcmk__str_casei)) {
791  if (!pcmk_is_set(action->flags, pe_action_runnable)) {
792  pe_rsc_trace(rsc, "Skipping pseudo-op: %s run=%d, pseudo=%d",
793  action->uuid,
796  } else {
797  pe_rsc_trace(rsc, "Starting due to: %s", action->uuid);
798  pe_rsc_trace(rsc, "%s run=%d, pseudo=%d",
799  action->uuid,
802  *starting = TRUE;
803  }
804  }
805  }
806 }
807 
808 static pe_action_t *
809 find_rsc_action(pe_resource_t *rsc, const char *task)
810 {
811  pe_action_t *match = NULL;
812  GList *actions = pe__resource_actions(rsc, NULL, task, FALSE);
813 
814  for (GList *item = actions; item != NULL; item = item->next) {
815  pe_action_t *op = (pe_action_t *) item->data;
816 
817  if (!pcmk_is_set(op->flags, pe_action_optional)) {
818  if (match != NULL) {
819  // More than one match, don't return any
820  match = NULL;
821  break;
822  }
823  match = op;
824  }
825  }
826  g_list_free(actions);
827  return match;
828 }
829 
830 static void
831 child_ordering_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
832 {
833  pe_action_t *stop = NULL;
834  pe_action_t *start = NULL;
835  pe_action_t *last_stop = NULL;
836  pe_action_t *last_start = NULL;
837  GList *gIter = NULL;
838  clone_variant_data_t *clone_data = NULL;
839 
840  get_clone_variant_data(clone_data, rsc);
841 
842  if (clone_data->ordered == FALSE) {
843  return;
844  }
845  /* we have to maintain a consistent sorted child list when building order constraints */
846  rsc->children = g_list_sort(rsc->children, sort_rsc_id);
847 
848  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
849  pe_resource_t *child = (pe_resource_t *) gIter->data;
850 
851  stop = find_rsc_action(child, RSC_STOP);
852  if (stop) {
853  if (last_stop) {
854  /* child/child relative stop */
855  order_actions(stop, last_stop, pe_order_optional);
856  }
857  last_stop = stop;
858  }
859 
860  start = find_rsc_action(child, RSC_START);
861  if (start) {
862  if (last_start) {
863  /* child/child relative start */
864  order_actions(last_start, start, pe_order_optional);
865  }
866  last_start = start;
867  }
868  }
869 }
870 
871 void
873 {
874  clone_variant_data_t *clone_data = NULL;
875 
876  get_clone_variant_data(clone_data, rsc);
877  clone_create_pseudo_actions(rsc, rsc->children, &clone_data->start_notify, &clone_data->stop_notify,data_set);
878  child_ordering_constraints(rsc, data_set);
879  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
880  create_promotable_actions(rsc, data_set);
881  }
882 }
883 
884 void
886  pe_resource_t * rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify, pe_working_set_t * data_set)
887 {
888  gboolean child_active = FALSE;
889  gboolean child_starting = FALSE;
890  gboolean child_stopping = FALSE;
891  gboolean allow_dependent_migrations = TRUE;
892 
893  pe_action_t *stop = NULL;
894  pe_action_t *stopped = NULL;
895 
896  pe_action_t *start = NULL;
897  pe_action_t *started = NULL;
898 
899  pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
900 
901  for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
902  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
903  gboolean starting = FALSE;
904  gboolean stopping = FALSE;
905 
906  child_rsc->cmds->create_actions(child_rsc, data_set);
907  clone_update_pseudo_status(child_rsc, &stopping, &starting, &child_active);
908  if (stopping && starting) {
909  allow_dependent_migrations = FALSE;
910  }
911 
912  child_stopping |= stopping;
913  child_starting |= starting;
914  }
915 
916  /* start */
917  start = create_pseudo_resource_op(rsc, RSC_START, !child_starting, TRUE, data_set);
918  started = create_pseudo_resource_op(rsc, RSC_STARTED, !child_starting, FALSE, data_set);
919  started->priority = INFINITY;
920 
921  if (child_active || child_starting) {
923  }
924 
925  if (start_notify != NULL && *start_notify == NULL) {
926  *start_notify = create_notification_boundaries(rsc, RSC_START, start, started, data_set);
927  }
928 
929  /* stop */
930  stop = create_pseudo_resource_op(rsc, RSC_STOP, !child_stopping, TRUE, data_set);
931  stopped = create_pseudo_resource_op(rsc, RSC_STOPPED, !child_stopping, TRUE, data_set);
932  stopped->priority = INFINITY;
933  if (allow_dependent_migrations) {
935  }
936 
937  if (stop_notify != NULL && *stop_notify == NULL) {
938  *stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
939 
940  if (start_notify && *start_notify && *stop_notify) {
941  order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
942  }
943  }
944 }
945 
946 void
948 {
949  pe_resource_t *last_rsc = NULL;
950  GList *gIter;
951  clone_variant_data_t *clone_data = NULL;
952 
953  get_clone_variant_data(clone_data, rsc);
954 
955  pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
957  pe_order_optional, data_set);
959  pe_order_runnable_left, data_set);
961  pe_order_runnable_left, data_set);
962 
963  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
965  pe_order_optional, data_set);
967  pe_order_runnable_left, data_set);
968  }
969 
970  if (clone_data->ordered) {
971  /* we have to maintain a consistent sorted child list when building order constraints */
972  rsc->children = g_list_sort(rsc->children, sort_rsc_id);
973  }
974  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
975  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
976 
977  child_rsc->cmds->internal_constraints(child_rsc, data_set);
978 
979  pcmk__order_starts(rsc, child_rsc,
981  data_set);
984  if (clone_data->ordered && last_rsc) {
985  pcmk__order_starts(last_rsc, child_rsc, pe_order_optional,
986  data_set);
987  }
988 
990  data_set);
993  if (clone_data->ordered && last_rsc) {
994  pcmk__order_stops(child_rsc, last_rsc, pe_order_optional, data_set);
995  }
996 
997  last_rsc = child_rsc;
998  }
999  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1000  promotable_constraints(rsc, data_set);
1001  }
1002 }
1003 
1004 bool
1005 assign_node(pe_resource_t * rsc, pe_node_t * node, gboolean force)
1006 {
1007  bool changed = FALSE;
1008 
1009  if (rsc->children) {
1010 
1011  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1012  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1013 
1014  changed |= assign_node(child_rsc, node, force);
1015  }
1016 
1017  return changed;
1018  }
1019 
1020  if (rsc->allocated_to != NULL) {
1021  changed = true;
1022  }
1023 
1024  native_assign_node(rsc, node, force);
1025  return changed;
1026 }
1027 
1028 gboolean
1029 is_child_compatible(pe_resource_t *child_rsc, pe_node_t * local_node, enum rsc_role_e filter, gboolean current)
1030 {
1031  pe_node_t *node = NULL;
1032  enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
1033 
1034  CRM_CHECK(child_rsc && local_node, return FALSE);
1035  if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1036  /* We only want instances that haven't failed */
1037  node = child_rsc->fns->location(child_rsc, NULL, current);
1038  }
1039 
1040  if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
1041  crm_trace("Filtered %s", child_rsc->id);
1042  return FALSE;
1043  }
1044 
1045  if (node && (node->details == local_node->details)) {
1046  return TRUE;
1047 
1048  } else if (node) {
1049  crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
1050  local_node->details->uname);
1051 
1052  } else {
1053  crm_trace("%s - not allocated %d", child_rsc->id, current);
1054  }
1055  return FALSE;
1056 }
1057 
1058 pe_resource_t *
1060  enum rsc_role_e filter, gboolean current,
1061  pe_working_set_t *data_set)
1062 {
1063  pe_resource_t *pair = NULL;
1064  GList *gIter = NULL;
1065  GList *scratch = NULL;
1066  pe_node_t *local_node = NULL;
1067 
1068  local_node = local_child->fns->location(local_child, NULL, current);
1069  if (local_node) {
1070  return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
1071  }
1072 
1073  scratch = g_hash_table_get_values(local_child->allowed_nodes);
1074  scratch = sort_nodes_by_weight(scratch, NULL, data_set);
1075 
1076  gIter = scratch;
1077  for (; gIter != NULL; gIter = gIter->next) {
1078  pe_node_t *node = (pe_node_t *) gIter->data;
1079 
1080  pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
1081  if (pair) {
1082  goto done;
1083  }
1084  }
1085 
1086  pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
1087  done:
1088  g_list_free(scratch);
1089  return pair;
1090 }
1091 
1092 void
1094  pcmk__colocation_t *constraint,
1095  pe_working_set_t *data_set)
1096 {
1097  /* -- Never called --
1098  *
1099  * Instead we add the colocation constraints to the child and call from there
1100  */
1101  CRM_ASSERT(FALSE);
1102 }
1103 
1104 void
1106  pcmk__colocation_t *constraint,
1107  pe_working_set_t *data_set)
1108 {
1109  GList *gIter = NULL;
1110  gboolean do_interleave = FALSE;
1111  const char *interleave_s = NULL;
1112 
1113  CRM_CHECK(constraint != NULL, return);
1114  CRM_CHECK(dependent != NULL,
1115  pe_err("dependent was NULL for %s", constraint->id); return);
1116  CRM_CHECK(primary != NULL,
1117  pe_err("primary was NULL for %s", constraint->id); return);
1118  CRM_CHECK(dependent->variant == pe_native, return);
1119 
1120  pe_rsc_trace(primary, "Processing constraint %s: %s -> %s %d",
1121  constraint->id, dependent->id, primary->id, constraint->score);
1122 
1123  if (pcmk_is_set(primary->flags, pe_rsc_promotable)) {
1124  if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
1125  pe_rsc_trace(primary, "%s is still provisional", primary->id);
1126  return;
1127  } else if (constraint->primary_role == RSC_ROLE_UNKNOWN) {
1128  pe_rsc_trace(primary, "Handling %s as a clone colocation",
1129  constraint->id);
1130  } else {
1131  promotable_colocation_rh(dependent, primary, constraint, data_set);
1132  return;
1133  }
1134  }
1135 
1136  /* only the LHS side needs to be labeled as interleave */
1137  interleave_s = g_hash_table_lookup(constraint->dependent->meta,
1139  if (crm_is_true(interleave_s)
1140  && (constraint->dependent->variant > pe_group)) {
1141  /* @TODO Do we actually care about multiple primary copies sharing a
1142  * dependent copy anymore?
1143  */
1144  if (copies_per_node(constraint->dependent) != copies_per_node(constraint->primary)) {
1145  pcmk__config_err("Cannot interleave %s and %s because they do not "
1146  "support the same number of instances per node",
1147  constraint->dependent->id,
1148  constraint->primary->id);
1149 
1150  } else {
1151  do_interleave = TRUE;
1152  }
1153  }
1154 
1155  if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
1156  pe_rsc_trace(primary, "%s is still provisional", primary->id);
1157  return;
1158 
1159  } else if (do_interleave) {
1160  pe_resource_t *primary_instance = NULL;
1161 
1162  primary_instance = find_compatible_child(dependent, primary,
1163  RSC_ROLE_UNKNOWN, FALSE,
1164  data_set);
1165  if (primary_instance != NULL) {
1166  pe_rsc_debug(primary, "Pairing %s with %s",
1167  dependent->id, primary_instance->id);
1168  dependent->cmds->rsc_colocation_lh(dependent, primary_instance,
1169  constraint, data_set);
1170 
1171  } else if (constraint->score >= INFINITY) {
1172  crm_notice("Cannot pair %s with instance of %s",
1173  dependent->id, primary->id);
1174  assign_node(dependent, NULL, TRUE);
1175 
1176  } else {
1177  pe_rsc_debug(primary, "Cannot pair %s with instance of %s",
1178  dependent->id, primary->id);
1179  }
1180 
1181  return;
1182 
1183  } else if (constraint->score >= INFINITY) {
1184  GList *affected_nodes = NULL;
1185 
1186  gIter = primary->children;
1187  for (; gIter != NULL; gIter = gIter->next) {
1188  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1189  pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1190 
1191  if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1192  pe_rsc_trace(primary, "Allowing %s: %s %d",
1193  constraint->id, chosen->details->uname,
1194  chosen->weight);
1195  affected_nodes = g_list_prepend(affected_nodes, chosen);
1196  }
1197  }
1198 
1199  node_list_exclude(dependent->allowed_nodes, affected_nodes, FALSE);
1200  g_list_free(affected_nodes);
1201  return;
1202  }
1203 
1204  gIter = primary->children;
1205  for (; gIter != NULL; gIter = gIter->next) {
1206  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1207 
1208  child_rsc->cmds->rsc_colocation_rh(dependent, child_rsc, constraint,
1209  data_set);
1210  }
1211 }
1212 
1213 enum action_tasks
1215 {
1216  enum action_tasks result = no_action;
1217  pe_resource_t *child = (pe_resource_t *) action->rsc->children->data;
1218 
1219  if (pcmk__strcase_any_of(action->task, "notify", "notified", NULL)) {
1220 
1221  /* Find the action we're notifying about instead */
1222 
1223  int stop = 0;
1224  char *key = action->uuid;
1225  int lpc = strlen(key);
1226 
1227  for (; lpc > 0; lpc--) {
1228  if (key[lpc] == '_' && stop == 0) {
1229  stop = lpc;
1230 
1231  } else if (key[lpc] == '_') {
1232  char *task_mutable = NULL;
1233 
1234  lpc++;
1235  task_mutable = strdup(key + lpc);
1236  task_mutable[stop - lpc] = 0;
1237 
1238  crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
1239  result = get_complex_task(child, task_mutable, TRUE);
1240  free(task_mutable);
1241  break;
1242  }
1243  }
1244 
1245  } else {
1246  result = get_complex_task(child, action->task, TRUE);
1247  }
1248  return result;
1249 }
1250 
1251 #define pe__clear_action_summary_flags(flags, action, flag) do { \
1252  flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
1253  "Action summary", action->rsc->id, \
1254  flags, flag, #flag); \
1255  } while (0)
1256 
1257 enum pe_action_flags
1259 {
1260  GList *gIter = NULL;
1261  gboolean any_runnable = FALSE;
1262  gboolean check_runnable = TRUE;
1263  enum action_tasks task = clone_child_action(action);
1265  const char *task_s = task2text(task);
1266 
1267  for (gIter = children; gIter != NULL; gIter = gIter->next) {
1268  pe_action_t *child_action = NULL;
1269  pe_resource_t *child = (pe_resource_t *) gIter->data;
1270 
1271  child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
1272  pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
1273  node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
1274  if (child_action) {
1275  enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
1276 
1278  && !pcmk_is_set(child_flags, pe_action_optional)) {
1279  pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
1280  child_action->uuid);
1283  }
1284  if (pcmk_is_set(child_flags, pe_action_runnable)) {
1285  any_runnable = TRUE;
1286  }
1287  }
1288  }
1289 
1290  if (check_runnable && any_runnable == FALSE) {
1291  pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
1293  if (node == NULL) {
1295  }
1296  }
1297 
1298  return flags;
1299 }
1300 
1301 enum pe_action_flags
1303 {
1304  return summary_action_flags(action, action->rsc->children, node);
1305 }
1306 
1307 void
1309 {
1310  GList *gIter = rsc->children;
1311 
1312  pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
1313 
1314  pcmk__apply_location(constraint, rsc);
1315 
1316  for (; gIter != NULL; gIter = gIter->next) {
1317  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1318 
1319  child_rsc->cmds->rsc_location(child_rsc, constraint);
1320  }
1321 }
1322 
1323 void
1325 {
1326  GList *gIter = NULL;
1327  clone_variant_data_t *clone_data = NULL;
1328 
1329  get_clone_variant_data(clone_data, rsc);
1330 
1331  g_list_foreach(rsc->actions, (GFunc) rsc->cmds->action_flags, NULL);
1332 
1333  if (clone_data->start_notify) {
1334  collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
1335  pcmk__create_notification_keys(rsc, clone_data->start_notify, data_set);
1336  create_notifications(rsc, clone_data->start_notify, data_set);
1337  }
1338 
1339  if (clone_data->stop_notify) {
1340  collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
1341  pcmk__create_notification_keys(rsc, clone_data->stop_notify, data_set);
1342  create_notifications(rsc, clone_data->stop_notify, data_set);
1343  }
1344 
1345  if (clone_data->promote_notify) {
1346  collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
1347  pcmk__create_notification_keys(rsc, clone_data->promote_notify, data_set);
1348  create_notifications(rsc, clone_data->promote_notify, data_set);
1349  }
1350 
1351  if (clone_data->demote_notify) {
1352  collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
1353  pcmk__create_notification_keys(rsc, clone_data->demote_notify, data_set);
1354  create_notifications(rsc, clone_data->demote_notify, data_set);
1355  }
1356 
1357  /* Now that the notifcations have been created we can expand the children */
1358 
1359  gIter = rsc->children;
1360  for (; gIter != NULL; gIter = gIter->next) {
1361  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1362 
1363  child_rsc->cmds->expand(child_rsc, data_set);
1364  }
1365 
1366  native_expand(rsc, data_set);
1367 
1368  /* The notifications are in the graph now, we can destroy the notify_data */
1369  free_notification_data(clone_data->demote_notify);
1370  clone_data->demote_notify = NULL;
1371  free_notification_data(clone_data->stop_notify);
1372  clone_data->stop_notify = NULL;
1373  free_notification_data(clone_data->start_notify);
1374  clone_data->start_notify = NULL;
1375  free_notification_data(clone_data->promote_notify);
1376  clone_data->promote_notify = NULL;
1377 }
1378 
1379 // Check whether a resource or any of its children is known on node
1380 static bool
1381 rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
1382 {
1383  if (rsc->children) {
1384  for (GList *child_iter = rsc->children; child_iter != NULL;
1385  child_iter = child_iter->next) {
1386 
1387  pe_resource_t *child = (pe_resource_t *) child_iter->data;
1388 
1389  if (rsc_known_on(child, node)) {
1390  return TRUE;
1391  }
1392  }
1393 
1394  } else if (rsc->known_on) {
1395  GHashTableIter iter;
1396  pe_node_t *known_node = NULL;
1397 
1398  g_hash_table_iter_init(&iter, rsc->known_on);
1399  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
1400  if (node->details == known_node->details) {
1401  return TRUE;
1402  }
1403  }
1404  }
1405  return FALSE;
1406 }
1407 
1408 // Look for an instance of clone that is known on node
1409 static pe_resource_t *
1410 find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
1411 {
1412  for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
1413  pe_resource_t *child = (pe_resource_t *) gIter->data;
1414 
1415  if (rsc_known_on(child, node)) {
1416  return child;
1417  }
1418  }
1419  return NULL;
1420 }
1421 
1422 // For unique clones, probe each instance separately
1423 static gboolean
1424 probe_unique_clone(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete,
1425  gboolean force, pe_working_set_t *data_set)
1426 {
1427  gboolean any_created = FALSE;
1428 
1429  for (GList *child_iter = rsc->children; child_iter != NULL;
1430  child_iter = child_iter->next) {
1431 
1432  pe_resource_t *child = (pe_resource_t *) child_iter->data;
1433 
1434  any_created |= child->cmds->create_probe(child, node, complete, force,
1435  data_set);
1436  }
1437  return any_created;
1438 }
1439 
1440 // For anonymous clones, only a single instance needs to be probed
1441 static gboolean
1442 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
1443  pe_action_t *complete, gboolean force,
1444  pe_working_set_t *data_set)
1445 {
1446  // First, check if we probed an instance on this node last time
1447  pe_resource_t *child = find_instance_on(rsc, node);
1448 
1449  // Otherwise, check if we plan to start an instance on this node
1450  if (child == NULL) {
1451  for (GList *child_iter = rsc->children; child_iter && !child;
1452  child_iter = child_iter->next) {
1453 
1454  pe_node_t *local_node = NULL;
1455  pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
1456 
1457  if (child_rsc) { /* make clang analyzer happy */
1458  local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1459  if (local_node && (local_node->details == node->details)) {
1460  child = child_rsc;
1461  }
1462  }
1463  }
1464  }
1465 
1466  // Otherwise, use the first clone instance
1467  if (child == NULL) {
1468  child = rsc->children->data;
1469  }
1470  CRM_ASSERT(child);
1471  return child->cmds->create_probe(child, node, complete, force, data_set);
1472 }
1473 
1474 gboolean
1476  gboolean force, pe_working_set_t * data_set)
1477 {
1478  gboolean any_created = FALSE;
1479 
1480  CRM_ASSERT(rsc);
1481 
1482  rsc->children = g_list_sort(rsc->children, sort_rsc_id);
1483  if (rsc->children == NULL) {
1484  pe_warn("Clone %s has no children", rsc->id);
1485  return FALSE;
1486  }
1487 
1488  if (rsc->exclusive_discover) {
1489  pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1490  if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1491  /* exclusive discover is enabled and this node is not marked
1492  * as a node this resource should be discovered on
1493  *
1494  * remove the node from allowed_nodes so that the
1495  * notification contains only nodes that we might ever run
1496  * on
1497  */
1498  g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1499 
1500  /* Bit of a shortcut - might as well take it */
1501  return FALSE;
1502  }
1503  }
1504 
1505  if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1506  any_created = probe_unique_clone(rsc, node, complete, force, data_set);
1507  } else {
1508  any_created = probe_anonymous_clone(rsc, node, complete, force,
1509  data_set);
1510  }
1511  return any_created;
1512 }
1513 
1514 void
1515 clone_append_meta(pe_resource_t * rsc, xmlNode * xml)
1516 {
1517  char *name = NULL;
1518  clone_variant_data_t *clone_data = NULL;
1519 
1520  get_clone_variant_data(clone_data, rsc);
1521 
1523  crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1524  free(name);
1525 
1527  crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1528  free(name);
1529 
1531  crm_xml_add_int(xml, name, clone_data->clone_max);
1532  free(name);
1533 
1535  crm_xml_add_int(xml, name, clone_data->clone_node_max);
1536  free(name);
1537 
1538  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1540  crm_xml_add_int(xml, name, clone_data->promoted_max);
1541  free(name);
1542 
1544  crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1545  free(name);
1546 
1547  /* @COMPAT Maintain backward compatibility with resource agents that
1548  * expect the old names (deprecated since 2.0.0).
1549  */
1551  crm_xml_add_int(xml, name, clone_data->promoted_max);
1552  free(name);
1553 
1555  crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1556  free(name);
1557  }
1558 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:225
void pcmk__create_notification_keys(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
const char * task2text(enum action_tasks task)
Definition: common.c:406
#define RSC_STOP
Definition: crm.h:204
bool is_set_recursive(pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:397
#define crm_notice(fmt, args...)
Definition: logging.h:359
GHashTable * known_on
Definition: pe_types.h:367
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:19
#define INFINITY
Definition: crm.h:99
GList * rsc_cons
Definition: pe_types.h:357
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:59
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:353
#define pe__clear_action_summary_flags(flags, action, flag)
GList * sort_nodes_by_weight(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
#define pcmk__order_starts(rsc1, rsc2, type, data_set)
int priority
Definition: pe_types.h:408
pe_node_t * pe__find_active_on(const pe_resource_t *rsc, unsigned int *count_all, unsigned int *count_clean)
Definition: complex.c:999
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:931
GList * children
Definition: pe_types.h:377
int count
Definition: pe_types.h:243
resource_alloc_functions_t * cmds
Definition: pe_types.h:334
void clone_create_pseudo_actions(pe_resource_t *rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify, pe_working_set_t *data_set)
void collect_notification_data(pe_resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data)
void clone_rsc_colocation_rh(pe_resource_t *dependent, pe_resource_t *primary, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
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:431
gboolean exclusive_discover
Definition: pe_types.h:352
#define pcmk__config_err(fmt...)
GHashTable * meta
Definition: pe_types.h:373
gboolean native_assign_node(pe_resource_t *rsc, pe_node_t *chosen, gboolean force)
#define pe_rsc_unique
Definition: pe_types.h:254
#define pe_rsc_notify
Definition: pe_types.h:253
resource_object_functions_t * fns
Definition: pe_types.h:333
void create_notifications(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
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_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:142
pe_resource_t * dependent
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:161
#define pcmk__order_stops(rsc1, rsc2, type, data_set)
#define PCMK_XE_PROMOTED_NODE_MAX_LEGACY
Definition: msg_xml.h:44
void(* internal_constraints)(pe_resource_t *, pe_working_set_t *)
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:1691
GList * rsc_cons_lhs
Definition: pe_types.h:356
void native_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
#define RSC_START
Definition: crm.h:201
pe_node_t *(* allocate)(pe_resource_t *, pe_node_t *, pe_working_set_t *)
pe_node_t * allocated_to
Definition: pe_types.h:363
void pcmk__add_promotion_scores(pe_resource_t *rsc)
bool assign_node(pe_resource_t *rsc, pe_node_t *node, gboolean force)
GHashTable * pcmk__native_merge_weights(pe_resource_t *rsc, const char *rhs, GHashTable *nodes, const char *attr, float factor, uint32_t flags)
#define XML_RSC_ATTR_INCARNATION_MAX
Definition: msg_xml.h:226
gboolean can_run_resources(const pe_node_t *node)
#define PCMK_XE_PROMOTED_MAX_LEGACY
Definition: msg_xml.h:43
char * crm_meta_name(const char *field)
Definition: utils.c:511
const char * action
Definition: pcmk_fence.c:30
notify_data_t * create_notification_boundaries(pe_resource_t *rsc, const char *action, pe_action_t *start, pe_action_t *end, pe_working_set_t *data_set)
void free_notification_data(notify_data_t *n_data)
void promotable_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:47
#define pe_rsc_provisional
Definition: pe_types.h:258
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:54
pe_node_t * pcmk__clone_allocate(pe_resource_t *rsc, pe_node_t *prefer, pe_working_set_t *data_set)
#define pe_warn(fmt...)
Definition: internal.h:27
int weight
Definition: pe_types.h:241
#define crm_warn(fmt, args...)
Definition: logging.h:358
void promotable_colocation_rh(pe_resource_t *dependent, pe_resource_t *primary, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
enum pe_action_flags clone_action_flags(pe_action_t *action, pe_node_t *node)
gboolean(* create_probe)(pe_resource_t *, pe_node_t *, pe_action_t *, gboolean, pe_working_set_t *)
void create_promotable_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
void clone_append_meta(pe_resource_t *rsc, xmlNode *xml)
pe_action_flags
Definition: pe_types.h:291
int rc
Definition: pcmk_fence.c:35
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, pe_node_t *node)
pe_action_t * create_pseudo_resource_op(pe_resource_t *rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
#define pe_rsc_failed
Definition: pe_types.h:267
void(* rsc_colocation_lh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
pe_resource_t * primary
pe_resource_t * find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current, pe_working_set_t *data_set)
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:68
#define crm_trace(fmt, args...)
Definition: logging.h:363
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1517
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
struct pe_node_shared_s * details
Definition: pe_types.h:244
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1905
unsigned long long flags
Definition: pe_types.h:348
const char * uname
Definition: pe_types.h:209
#define pe_rsc_promotable
Definition: pe_types.h:256
void(* expand)(pe_resource_t *, pe_working_set_t *)
#define pcmk__order_resource_actions(lh_rsc, lh_task, rh_rsc, rh_task, flags, data_set)
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:359
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:228
char * uuid
Definition: pe_types.h:415
void clone_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
void(* rsc_colocation_rh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
enum pe_action_flags(* action_flags)(pe_action_t *, pe_node_t *)
#define pe_rsc_allocating
Definition: pe_types.h:259
enum pe_obj_types variant
Definition: pe_types.h:331
gboolean is_child_compatible(pe_resource_t *child_rsc, pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
void common_update_score(pe_resource_t *rsc, const char *id, int score)
Definition: complex.c:864
#define RSC_DEMOTED
Definition: crm.h:210
int rsc_discover_mode
Definition: pe_types.h:245
#define XML_RSC_ATTR_NOTIFY
Definition: msg_xml.h:235
const char * id
Definition: pe_types.h:208
enum action_tasks clone_child_action(pe_action_t *action)
GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:234
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition: pe_types.h:53
#define XML_RSC_ATTR_PROMOTED_MAX
Definition: msg_xml.h:230
gboolean clone_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
#define RSC_STARTED
Definition: crm.h:202
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
void clone_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
#define crm_err(fmt, args...)
Definition: logging.h:357
#define CRM_ASSERT(expr)
Definition: results.h:42
void clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
void clone_rsc_colocation_lh(pe_resource_t *dependent, pe_resource_t *primary, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
#define RSC_PROMOTE
Definition: crm.h:207
void(* rsc_location)(pe_resource_t *, pe__location_t *)
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:53
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:231
GList * running_on
Definition: pe_types.h:366
#define pe_rsc_block
Definition: pe_types.h:250
void(* create_actions)(pe_resource_t *, pe_working_set_t *)
enum pe_action_flags flags
Definition: pe_types.h:419
const char * node_attribute
#define RSC_STOPPED
Definition: crm.h:205
void native_deallocate(pe_resource_t *rsc)
gboolean crm_is_true(const char *s)
Definition: strings.c:416
pe_resource_t * find_compatible_child_by_node(pe_resource_t *local_child, pe_node_t *local_node, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
void clone_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:20
unsigned long long flags
Definition: pe_types.h:146
#define pe_err(fmt...)
Definition: internal.h:22
#define XML_RSC_ATTR_INTERLEAVE
Definition: msg_xml.h:224
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: utils.c:1643
char * name
Definition: pcmk_fence.c:31
pe_node_t * pcmk__set_instance_roles(pe_resource_t *rsc, pe_working_set_t *data_set)
#define pe_flag_show_scores
Definition: pe_types.h:133
#define crm_info(fmt, args...)
Definition: logging.h:360
#define pe_rsc_managed
Definition: pe_types.h:249
#define pe_rsc_orphan
Definition: pe_types.h:248
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1540
G_GNUC_INTERNAL void pcmk__apply_location(pe__location_t *constraint, pe_resource_t *rsc)
uint64_t flags
Definition: remote.c:149
action_tasks
Definition: common.h:62
pe_resource_t * parent
Definition: pe_types.h:329
GHashTable *(* merge_weights)(pe_resource_t *, const char *, GHashTable *, const char *, float, enum pe_weights)
int copies_per_node(pe_resource_t *rsc)
char * id
Definition: pe_types.h:322
GHashTable * allowed_nodes
Definition: pe_types.h:368