pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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) {
948  update_action_flags(started, pe_action_runnable, __func__, __LINE__);
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  __LINE__);
962  }
963 
964  if (stop_notify != NULL && *stop_notify == NULL) {
965  *stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
966 
967  if (start_notify && *start_notify && *stop_notify) {
968  order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
969  }
970  }
971 }
972 
973 void
975 {
976  pe_resource_t *last_rsc = NULL;
977  GList *gIter;
978  clone_variant_data_t *clone_data = NULL;
979 
980  get_clone_variant_data(clone_data, rsc);
981 
982  pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
983  new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
986 
987  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
988  new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
990  }
991 
992  if (clone_data->ordered) {
993  /* we have to maintain a consistent sorted child list when building order constraints */
994  rsc->children = g_list_sort(rsc->children, sort_rsc_id);
995  }
996  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
997  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
998 
999  child_rsc->cmds->internal_constraints(child_rsc, data_set);
1000 
1003  data_set);
1004  if (clone_data->ordered && last_rsc) {
1005  order_start_start(last_rsc, child_rsc, pe_order_optional);
1006  }
1007 
1010  data_set);
1011  if (clone_data->ordered && last_rsc) {
1012  order_stop_stop(child_rsc, last_rsc, pe_order_optional);
1013  }
1014 
1015  last_rsc = child_rsc;
1016  }
1017  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1018  promotable_constraints(rsc, data_set);
1019  }
1020 }
1021 
1022 bool
1023 assign_node(pe_resource_t * rsc, pe_node_t * node, gboolean force)
1024 {
1025  bool changed = FALSE;
1026 
1027  if (rsc->children) {
1028 
1029  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1030  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1031 
1032  changed |= assign_node(child_rsc, node, force);
1033  }
1034 
1035  return changed;
1036  }
1037 
1038  if (rsc->allocated_to != NULL) {
1039  changed = true;
1040  }
1041 
1042  native_assign_node(rsc, node, force);
1043  return changed;
1044 }
1045 
1046 gboolean
1047 is_child_compatible(pe_resource_t *child_rsc, pe_node_t * local_node, enum rsc_role_e filter, gboolean current)
1048 {
1049  pe_node_t *node = NULL;
1050  enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
1051 
1052  CRM_CHECK(child_rsc && local_node, return FALSE);
1053  if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1054  /* We only want instances that haven't failed */
1055  node = child_rsc->fns->location(child_rsc, NULL, current);
1056  }
1057 
1058  if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
1059  crm_trace("Filtered %s", child_rsc->id);
1060  return FALSE;
1061  }
1062 
1063  if (node && (node->details == local_node->details)) {
1064  return TRUE;
1065 
1066  } else if (node) {
1067  crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
1068  local_node->details->uname);
1069 
1070  } else {
1071  crm_trace("%s - not allocated %d", child_rsc->id, current);
1072  }
1073  return FALSE;
1074 }
1075 
1076 pe_resource_t *
1078  enum rsc_role_e filter, gboolean current,
1079  pe_working_set_t *data_set)
1080 {
1081  pe_resource_t *pair = NULL;
1082  GList *gIter = NULL;
1083  GList *scratch = NULL;
1084  pe_node_t *local_node = NULL;
1085 
1086  local_node = local_child->fns->location(local_child, NULL, current);
1087  if (local_node) {
1088  return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
1089  }
1090 
1091  scratch = g_hash_table_get_values(local_child->allowed_nodes);
1092  scratch = sort_nodes_by_weight(scratch, NULL, data_set);
1093 
1094  gIter = scratch;
1095  for (; gIter != NULL; gIter = gIter->next) {
1096  pe_node_t *node = (pe_node_t *) gIter->data;
1097 
1098  pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
1099  if (pair) {
1100  goto done;
1101  }
1102  }
1103 
1104  pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
1105  done:
1106  g_list_free(scratch);
1107  return pair;
1108 }
1109 
1110 void
1112  pcmk__colocation_t *constraint,
1113  pe_working_set_t *data_set)
1114 {
1115  /* -- Never called --
1116  *
1117  * Instead we add the colocation constraints to the child and call from there
1118  */
1119  CRM_ASSERT(FALSE);
1120 }
1121 
1122 void
1124  pcmk__colocation_t *constraint,
1125  pe_working_set_t *data_set)
1126 {
1127  GList *gIter = NULL;
1128  gboolean do_interleave = FALSE;
1129  const char *interleave_s = NULL;
1130 
1131  CRM_CHECK(constraint != NULL, return);
1132  CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
1133  CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
1134  CRM_CHECK(rsc_lh->variant == pe_native, return);
1135 
1136  pe_rsc_trace(rsc_rh, "Processing constraint %s: %s -> %s %d",
1137  constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);
1138 
1139  if (pcmk_is_set(rsc_rh->flags, pe_rsc_promotable)) {
1140  if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1141  pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1142  return;
1143  } else if (constraint->role_rh == RSC_ROLE_UNKNOWN) {
1144  pe_rsc_trace(rsc_rh, "Handling %s as a clone colocation", constraint->id);
1145  } else {
1146  promotable_colocation_rh(rsc_lh, rsc_rh, constraint, data_set);
1147  return;
1148  }
1149  }
1150 
1151  /* only the LHS side needs to be labeled as interleave */
1152  interleave_s = g_hash_table_lookup(constraint->rsc_lh->meta, XML_RSC_ATTR_INTERLEAVE);
1153  if(crm_is_true(interleave_s) && constraint->rsc_lh->variant > pe_group) {
1154  // TODO: Do we actually care about multiple RH copies sharing a LH copy anymore?
1155  if (copies_per_node(constraint->rsc_lh) != copies_per_node(constraint->rsc_rh)) {
1156  pcmk__config_err("Cannot interleave %s and %s because they do not "
1157  "support the same number of instances per node",
1158  constraint->rsc_lh->id, constraint->rsc_rh->id);
1159 
1160  } else {
1161  do_interleave = TRUE;
1162  }
1163  }
1164 
1165  if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1166  pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1167  return;
1168 
1169  } else if (do_interleave) {
1170  pe_resource_t *rh_child = NULL;
1171 
1172  rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN,
1173  FALSE, data_set);
1174 
1175  if (rh_child) {
1176  pe_rsc_debug(rsc_rh, "Pairing %s with %s", rsc_lh->id, rh_child->id);
1177  rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint,
1178  data_set);
1179 
1180  } else if (constraint->score >= INFINITY) {
1181  crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1182  assign_node(rsc_lh, NULL, TRUE);
1183 
1184  } else {
1185  pe_rsc_debug(rsc_rh, "Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1186  }
1187 
1188  return;
1189 
1190  } else if (constraint->score >= INFINITY) {
1191  GList *rhs = NULL;
1192 
1193  gIter = rsc_rh->children;
1194  for (; gIter != NULL; gIter = gIter->next) {
1195  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1196  pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1197 
1198  if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1199  pe_rsc_trace(rsc_rh, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
1200  rhs = g_list_prepend(rhs, chosen);
1201  }
1202  }
1203 
1204  node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
1205  g_list_free(rhs);
1206  return;
1207  }
1208 
1209  gIter = rsc_rh->children;
1210  for (; gIter != NULL; gIter = gIter->next) {
1211  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1212 
1213  child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint,
1214  data_set);
1215  }
1216 }
1217 
1218 enum action_tasks
1220 {
1221  enum action_tasks result = no_action;
1222  pe_resource_t *child = (pe_resource_t *) action->rsc->children->data;
1223 
1224  if (pcmk__strcase_any_of(action->task, "notify", "notified", NULL)) {
1225 
1226  /* Find the action we're notifying about instead */
1227 
1228  int stop = 0;
1229  char *key = action->uuid;
1230  int lpc = strlen(key);
1231 
1232  for (; lpc > 0; lpc--) {
1233  if (key[lpc] == '_' && stop == 0) {
1234  stop = lpc;
1235 
1236  } else if (key[lpc] == '_') {
1237  char *task_mutable = NULL;
1238 
1239  lpc++;
1240  task_mutable = strdup(key + lpc);
1241  task_mutable[stop - lpc] = 0;
1242 
1243  crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
1244  result = get_complex_task(child, task_mutable, TRUE);
1245  free(task_mutable);
1246  break;
1247  }
1248  }
1249 
1250  } else {
1251  result = get_complex_task(child, action->task, TRUE);
1252  }
1253  return result;
1254 }
1255 
1256 #define pe__clear_action_summary_flags(flags, action, flag) do { \
1257  flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
1258  "Action summary", action->rsc->id, \
1259  flags, flag, #flag); \
1260  } while (0)
1261 
1262 enum pe_action_flags
1263 summary_action_flags(pe_action_t * action, GList *children, pe_node_t * node)
1264 {
1265  GList *gIter = NULL;
1266  gboolean any_runnable = FALSE;
1267  gboolean check_runnable = TRUE;
1268  enum action_tasks task = clone_child_action(action);
1270  const char *task_s = task2text(task);
1271 
1272  for (gIter = children; gIter != NULL; gIter = gIter->next) {
1273  pe_action_t *child_action = NULL;
1274  pe_resource_t *child = (pe_resource_t *) gIter->data;
1275 
1276  child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
1277  pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
1278  node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
1279  if (child_action) {
1280  enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
1281 
1282  if (pcmk_is_set(flags, pe_action_optional)
1283  && !pcmk_is_set(child_flags, pe_action_optional)) {
1284  pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
1285  child_action->uuid);
1288  }
1289  if (pcmk_is_set(child_flags, pe_action_runnable)) {
1290  any_runnable = TRUE;
1291  }
1292  }
1293  }
1294 
1295  if (check_runnable && any_runnable == FALSE) {
1296  pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
1298  if (node == NULL) {
1300  }
1301  }
1302 
1303  return flags;
1304 }
1305 
1306 enum pe_action_flags
1308 {
1309  return summary_action_flags(action, action->rsc->children, node);
1310 }
1311 
1312 void
1314 {
1315  GList *gIter = rsc->children;
1316 
1317  pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
1318 
1319  native_rsc_location(rsc, constraint);
1320 
1321  for (; gIter != NULL; gIter = gIter->next) {
1322  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1323 
1324  child_rsc->cmds->rsc_location(child_rsc, constraint);
1325  }
1326 }
1327 
1328 void
1330 {
1331  GList *gIter = NULL;
1332  clone_variant_data_t *clone_data = NULL;
1333 
1334  get_clone_variant_data(clone_data, rsc);
1335 
1336  gIter = rsc->actions;
1337  for (; gIter != NULL; gIter = gIter->next) {
1338  pe_action_t *op = (pe_action_t *) gIter->data;
1339 
1340  rsc->cmds->action_flags(op, NULL);
1341  }
1342 
1343  if (clone_data->start_notify) {
1344  collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
1345  pcmk__create_notification_keys(rsc, clone_data->start_notify, data_set);
1346  create_notifications(rsc, clone_data->start_notify, data_set);
1347  }
1348 
1349  if (clone_data->stop_notify) {
1350  collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
1351  pcmk__create_notification_keys(rsc, clone_data->stop_notify, data_set);
1352  create_notifications(rsc, clone_data->stop_notify, data_set);
1353  }
1354 
1355  if (clone_data->promote_notify) {
1356  collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
1357  pcmk__create_notification_keys(rsc, clone_data->promote_notify, data_set);
1358  create_notifications(rsc, clone_data->promote_notify, data_set);
1359  }
1360 
1361  if (clone_data->demote_notify) {
1362  collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
1363  pcmk__create_notification_keys(rsc, clone_data->demote_notify, data_set);
1364  create_notifications(rsc, clone_data->demote_notify, data_set);
1365  }
1366 
1367  /* Now that the notifcations have been created we can expand the children */
1368 
1369  gIter = rsc->children;
1370  for (; gIter != NULL; gIter = gIter->next) {
1371  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1372 
1373  child_rsc->cmds->expand(child_rsc, data_set);
1374  }
1375 
1376  native_expand(rsc, data_set);
1377 
1378  /* The notifications are in the graph now, we can destroy the notify_data */
1379  free_notification_data(clone_data->demote_notify);
1380  clone_data->demote_notify = NULL;
1381  free_notification_data(clone_data->stop_notify);
1382  clone_data->stop_notify = NULL;
1383  free_notification_data(clone_data->start_notify);
1384  clone_data->start_notify = NULL;
1385  free_notification_data(clone_data->promote_notify);
1386  clone_data->promote_notify = NULL;
1387 }
1388 
1389 // Check whether a resource or any of its children is known on node
1390 static bool
1391 rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
1392 {
1393  if (rsc->children) {
1394  for (GList *child_iter = rsc->children; child_iter != NULL;
1395  child_iter = child_iter->next) {
1396 
1397  pe_resource_t *child = (pe_resource_t *) child_iter->data;
1398 
1399  if (rsc_known_on(child, node)) {
1400  return TRUE;
1401  }
1402  }
1403 
1404  } else if (rsc->known_on) {
1405  GHashTableIter iter;
1406  pe_node_t *known_node = NULL;
1407 
1408  g_hash_table_iter_init(&iter, rsc->known_on);
1409  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
1410  if (node->details == known_node->details) {
1411  return TRUE;
1412  }
1413  }
1414  }
1415  return FALSE;
1416 }
1417 
1418 // Look for an instance of clone that is known on node
1419 static pe_resource_t *
1420 find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
1421 {
1422  for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
1423  pe_resource_t *child = (pe_resource_t *) gIter->data;
1424 
1425  if (rsc_known_on(child, node)) {
1426  return child;
1427  }
1428  }
1429  return NULL;
1430 }
1431 
1432 // For unique clones, probe each instance separately
1433 static gboolean
1434 probe_unique_clone(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete,
1435  gboolean force, pe_working_set_t *data_set)
1436 {
1437  gboolean any_created = FALSE;
1438 
1439  for (GList *child_iter = rsc->children; child_iter != NULL;
1440  child_iter = child_iter->next) {
1441 
1442  pe_resource_t *child = (pe_resource_t *) child_iter->data;
1443 
1444  any_created |= child->cmds->create_probe(child, node, complete, force,
1445  data_set);
1446  }
1447  return any_created;
1448 }
1449 
1450 // For anonymous clones, only a single instance needs to be probed
1451 static gboolean
1452 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
1453  pe_action_t *complete, gboolean force,
1454  pe_working_set_t *data_set)
1455 {
1456  // First, check if we probed an instance on this node last time
1457  pe_resource_t *child = find_instance_on(rsc, node);
1458 
1459  // Otherwise, check if we plan to start an instance on this node
1460  if (child == NULL) {
1461  for (GList *child_iter = rsc->children; child_iter && !child;
1462  child_iter = child_iter->next) {
1463 
1464  pe_node_t *local_node = NULL;
1465  pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
1466 
1467  if (child_rsc) { /* make clang analyzer happy */
1468  local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1469  if (local_node && (local_node->details == node->details)) {
1470  child = child_rsc;
1471  }
1472  }
1473  }
1474  }
1475 
1476  // Otherwise, use the first clone instance
1477  if (child == NULL) {
1478  child = rsc->children->data;
1479  }
1480  CRM_ASSERT(child);
1481  return child->cmds->create_probe(child, node, complete, force, data_set);
1482 }
1483 
1484 gboolean
1486  gboolean force, pe_working_set_t * data_set)
1487 {
1488  gboolean any_created = FALSE;
1489 
1490  CRM_ASSERT(rsc);
1491 
1492  rsc->children = g_list_sort(rsc->children, sort_rsc_id);
1493  if (rsc->children == NULL) {
1494  pe_warn("Clone %s has no children", rsc->id);
1495  return FALSE;
1496  }
1497 
1498  if (rsc->exclusive_discover) {
1499  pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1500  if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1501  /* exclusive discover is enabled and this node is not marked
1502  * as a node this resource should be discovered on
1503  *
1504  * remove the node from allowed_nodes so that the
1505  * notification contains only nodes that we might ever run
1506  * on
1507  */
1508  g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1509 
1510  /* Bit of a shortcut - might as well take it */
1511  return FALSE;
1512  }
1513  }
1514 
1515  if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1516  any_created = probe_unique_clone(rsc, node, complete, force, data_set);
1517  } else {
1518  any_created = probe_anonymous_clone(rsc, node, complete, force,
1519  data_set);
1520  }
1521  return any_created;
1522 }
1523 
1524 void
1525 clone_append_meta(pe_resource_t * rsc, xmlNode * xml)
1526 {
1527  char *name = NULL;
1528  clone_variant_data_t *clone_data = NULL;
1529 
1530  get_clone_variant_data(clone_data, rsc);
1531 
1533  crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1534  free(name);
1535 
1537  crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1538  free(name);
1539 
1541  crm_xml_add_int(xml, name, clone_data->clone_max);
1542  free(name);
1543 
1545  crm_xml_add_int(xml, name, clone_data->clone_node_max);
1546  free(name);
1547 
1548  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1550  crm_xml_add_int(xml, name, clone_data->promoted_max);
1551  free(name);
1552 
1554  crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1555  free(name);
1556 
1557  /* @COMPAT Maintain backward compatibility with resource agents that
1558  * expect the old names (deprecated since 2.0.0).
1559  */
1561  crm_xml_add_int(xml, name, clone_data->promoted_max);
1562  free(name);
1563 
1565  crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1566  free(name);
1567  }
1568 }
#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)
enum pe_action_flags clone_action_flags(pe_action_t *action, pe_node_t *node)
const char * task2text(enum action_tasks task)
Definition: common.c:406
#define RSC_STOP
Definition: crm.h:204
void clone_append_meta(pe_resource_t *rsc, xmlNode *xml)
bool is_set_recursive(pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:363
#define crm_notice(fmt, args...)
Definition: logging.h:352
GHashTable * known_on
Definition: pe_types.h:366
gboolean(* create_probe)(pe_resource_t *, pe_node_t *, pe_action_t *, gboolean, pe_working_set_t *)
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:356
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:371
#define pe__clear_action_summary_flags(flags, action, flag)
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition: pe_types.h:53
GList * sort_nodes_by_weight(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
int priority
Definition: pe_types.h:407
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:929
GList * children
Definition: pe_types.h:376
int count
Definition: pe_types.h:243
resource_alloc_functions_t * cmds
Definition: pe_types.h:332
void collect_notification_data(pe_resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data)
enum pe_action_flags(* action_flags)(pe_action_t *, pe_node_t *)
pe_resource_t * rsc
Definition: pe_types.h:409
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer 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:432
gboolean exclusive_discover
Definition: pe_types.h:351
#define pcmk__config_err(fmt...)
pe_resource_t * rsc_rh
GHashTable * meta
Definition: pe_types.h:372
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:331
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
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, pe_node_t *node)
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:161
GHashTable *(* merge_weights)(pe_resource_t *, const char *, GHashTable *, const char *, float, enum pe_weights)
#define PCMK_XE_PROMOTED_NODE_MAX_LEGACY
Definition: msg_xml.h:44
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:1588
GList * rsc_cons_lhs
Definition: pe_types.h:355
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 * allocated_to
Definition: pe_types.h:362
void pcmk__add_promotion_scores(pe_resource_t *rsc)
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 is_child_compatible(pe_resource_t *child_rsc, pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
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
void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes, int max, int per_host_max, pe_working_set_t *data_set)
#define pe_rsc_provisional
Definition: pe_types.h:258
void clone_rsc_colocation_lh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, 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
void(* create_actions)(pe_resource_t *, pe_working_set_t *)
void create_promotable_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
void clone_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
pe_action_flags
Definition: pe_types.h:291
#define order_stop_stop(rsc1, rsc2, type)
int rc
Definition: pcmk_fence.c:35
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
pe_node_t * pcmk__clone_allocate(pe_resource_t *rsc, pe_node_t *preferred, pe_working_set_t *data_set)
void clone_rsc_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
char * task
Definition: pe_types.h:413
#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:1399
#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:1802
unsigned long long flags
Definition: pe_types.h:347
const char * uname
Definition: pe_types.h:209
#define pe_rsc_promotable
Definition: pe_types.h:256
enum action_tasks clone_child_action(pe_action_t *action)
void(* expand)(pe_resource_t *, pe_working_set_t *)
bool assign_node(pe_resource_t *rsc, pe_node_t *node, gboolean force)
GList * actions
Definition: pe_types.h:358
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:228
char * uuid
Definition: pe_types.h:414
gboolean update_action_flags(pe_action_t *action, enum pe_action_flags flags, const char *source, int line)
#define pe_rsc_allocating
Definition: pe_types.h:259
enum pe_obj_types variant
Definition: pe_types.h:329
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)
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
void(* rsc_location)(pe_resource_t *, pe__location_t *)
const char * id
Definition: pe_types.h:208
void(* rsc_colocation_rh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:234
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)
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 XML_RSC_ATTR_PROMOTED_MAX
Definition: msg_xml.h:230
#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_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
#define crm_err(fmt, args...)
Definition: logging.h:350
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_PROMOTE
Definition: crm.h:207
void clone_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
void(* internal_constraints)(pe_resource_t *, pe_working_set_t *)
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:53
gboolean clone_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
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:365
#define pe_rsc_block
Definition: pe_types.h:250
enum pe_action_flags flags
Definition: pe_types.h:418
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:54
#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)
#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:1540
char * name
Definition: pcmk_fence.c:31
pe_node_t * pcmk__set_instance_roles(pe_resource_t *rsc, pe_working_set_t *data_set)
void clone_internal_constraints(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:1422
void(* rsc_colocation_lh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
uint64_t flags
Definition: remote.c:149
action_tasks
Definition: common.h:62
pe_resource_t * parent
Definition: pe_types.h:327
int copies_per_node(pe_resource_t *rsc)
char * id
Definition: pe_types.h:320
GHashTable * allowed_nodes
Definition: pe_types.h:367
pe_node_t *(* allocate)(pe_resource_t *, pe_node_t *, pe_working_set_t *)