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