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