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