This source file includes following definitions.
- sort_rsc_id
- parent_node_instance
- did_fail
- sort_clone_instance
- can_run_instance
- color_instance
- append_parent_colocation
- distribute_children
- clone_color
- clone_update_pseudo_status
- find_rsc_action
- child_ordering_constraints
- clone_create_actions
- clone_create_pseudo_actions
- clone_internal_constraints
- assign_node
- is_child_compatible
- find_compatible_child
- clone_rsc_colocation_lh
- clone_rsc_colocation_rh
- clone_child_action
- summary_action_flags
- clone_action_flags
- clone_rsc_location
- clone_expand
- rsc_known_on
- find_instance_on
- clone_create_probe
- clone_append_meta
- clone_merge_weights
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20
21 #include <crm/msg_xml.h>
22 #include <allocate.h>
23 #include <notif.h>
24 #include <utils.h>
25 #include <allocate.h>
26
27 #define VARIANT_CLONE 1
28 #include <lib/pengine/variant.h>
29
30 gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
31 static void append_parent_colocation(resource_t * rsc, resource_t * child, gboolean all);
32
33 static gint
34 sort_rsc_id(gconstpointer a, gconstpointer b)
35 {
36 const resource_t *resource1 = (const resource_t *)a;
37 const resource_t *resource2 = (const resource_t *)b;
38
39 CRM_ASSERT(resource1 != NULL);
40 CRM_ASSERT(resource2 != NULL);
41
42 return strcmp(resource1->id, resource2->id);
43 }
44
45 static node_t *
46 parent_node_instance(const resource_t * rsc, node_t * node)
47 {
48 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 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 resource_t *child_rsc = (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 node_t *node1 = NULL;
82 node_t *node2 = NULL;
83
84 gboolean can1 = TRUE;
85 gboolean can2 = TRUE;
86
87 const resource_t *resource1 = (const resource_t *)a;
88 const resource_t *resource2 = (const resource_t *)b;
89
90 CRM_ASSERT(resource1 != NULL);
91 CRM_ASSERT(resource2 != NULL);
92
93
94
95
96
97
98
99
100
101 if (resource1->running_on && resource2->running_on) {
102 if (g_list_length(resource1->running_on) < g_list_length(resource2->running_on)) {
103 crm_trace("%s < %s: running_on", resource1->id, resource2->id);
104 return -1;
105
106 } else if (g_list_length(resource1->running_on) > g_list_length(resource2->running_on)) {
107 crm_trace("%s > %s: running_on", resource1->id, resource2->id);
108 return 1;
109 }
110 }
111
112 if (resource1->running_on) {
113 node1 = resource1->running_on->data;
114 }
115 if (resource2->running_on) {
116 node2 = resource2->running_on->data;
117 }
118
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, g_hash_destroy_str);
227 GHashTable *hash2 =
228 g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
229
230 n = node_copy(resource1->running_on->data);
231 g_hash_table_insert(hash1, (gpointer) n->details->id, n);
232
233 n = node_copy(resource2->running_on->data);
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
281 node1 = g_list_nth_data(resource1->running_on, 0);
282 node1 = g_hash_table_lookup(hash1, node1->details->id);
283
284 node2 = g_list_nth_data(resource2->running_on, 0);
285 node2 = g_hash_table_lookup(hash2, node2->details->id);
286
287 if (node1->weight < node2->weight) {
288 if (node1->weight < 0) {
289 crm_trace("%s > %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
290 rc = -1;
291 goto out;
292
293 } else {
294 crm_trace("%s < %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
295 rc = 1;
296 goto out;
297 }
298
299 } else if (node1->weight > node2->weight) {
300 crm_trace("%s > %s: current score: %d %d", resource1->id, resource2->id, node1->weight, node2->weight);
301 rc = -1;
302 goto out;
303 }
304
305
306 list1 = g_hash_table_get_values(hash1);
307 list2 = g_hash_table_get_values(hash2);
308
309 list1 =
310 g_list_sort_with_data(list1, sort_node_weight,
311 g_list_nth_data(resource1->running_on, 0));
312 list2 =
313 g_list_sort_with_data(list2, sort_node_weight,
314 g_list_nth_data(resource2->running_on, 0));
315 max = g_list_length(list1);
316 if (max < g_list_length(list2)) {
317 max = g_list_length(list2);
318 }
319
320 for (; lpc < max; lpc++) {
321 node1 = g_list_nth_data(list1, lpc);
322 node2 = g_list_nth_data(list2, lpc);
323 if (node1 == NULL) {
324 crm_trace("%s < %s: colocated score NULL", resource1->id, resource2->id);
325 rc = 1;
326 break;
327
328 } else if (node2 == NULL) {
329 crm_trace("%s > %s: colocated score NULL", resource1->id, resource2->id);
330 rc = -1;
331 break;
332 }
333
334 if (node1->weight < node2->weight) {
335 crm_trace("%s < %s: colocated score", resource1->id, resource2->id);
336 rc = 1;
337 break;
338
339 } else if (node1->weight > node2->weight) {
340 crm_trace("%s > %s: colocated score", resource1->id, resource2->id);
341 rc = -1;
342 break;
343 }
344 }
345
346
347 out:
348 g_hash_table_destroy(hash1);
349 g_hash_table_destroy(hash2);
350 g_list_free(list1);
351 g_list_free(list2);
352
353 if (rc != 0) {
354 return rc;
355 }
356 }
357
358 rc = strcmp(resource1->id, resource2->id);
359 crm_trace("%s %c %s: default", resource1->id, rc < 0 ? '<' : '>', resource2->id);
360 return rc;
361 }
362
363 static node_t *
364 can_run_instance(resource_t * rsc, node_t * node, int limit)
365 {
366 node_t *local_node = NULL;
367
368 if (node == NULL && rsc->allowed_nodes) {
369 GHashTableIter iter;
370 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
371 while (g_hash_table_iter_next(&iter, NULL, (void **)&local_node)) {
372 can_run_instance(rsc, local_node, limit);
373 }
374 return NULL;
375 }
376
377 if (can_run_resources(node) == FALSE) {
378 goto bail;
379
380 } else if (is_set(rsc->flags, pe_rsc_orphan)) {
381 goto bail;
382 }
383
384 local_node = parent_node_instance(rsc, node);
385
386 if (local_node == NULL) {
387 crm_warn("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
388 goto bail;
389
390 } else if (local_node->weight < 0) {
391 common_update_score(rsc, node->details->id, local_node->weight);
392 pe_rsc_trace(rsc, "%s cannot run on %s: Parent node weight doesn't allow it.",
393 rsc->id, node->details->uname);
394
395 } else if (local_node->count < limit) {
396 pe_rsc_trace(rsc, "%s can run on %s (already running %d)",
397 rsc->id, node->details->uname, local_node->count);
398 return local_node;
399
400 } else {
401 pe_rsc_trace(rsc, "%s cannot run on %s: node full (%d >= %d)",
402 rsc->id, node->details->uname, local_node->count, limit);
403 }
404
405 bail:
406 if (node) {
407 common_update_score(rsc, node->details->id, -INFINITY);
408 }
409 return NULL;
410 }
411
412 static node_t *
413 color_instance(resource_t * rsc, node_t * prefer, gboolean all_coloc, int limit, pe_working_set_t * data_set)
414 {
415 node_t *chosen = NULL;
416 GHashTable *backup = NULL;
417
418 CRM_ASSERT(rsc);
419 pe_rsc_trace(rsc, "Checking allocation of %s (preferring %s, using %s parent colocations)",
420 rsc->id, (prefer? prefer->details->uname: "none"),
421 (all_coloc? "all" : "some"));
422
423 if (is_not_set(rsc->flags, pe_rsc_provisional)) {
424 return rsc->fns->location(rsc, NULL, FALSE);
425
426 } else if (is_set(rsc->flags, pe_rsc_allocating)) {
427 pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
428 return NULL;
429 }
430
431
432
433
434 append_parent_colocation(rsc->parent, rsc, all_coloc);
435
436 if (prefer) {
437 node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
438
439 if (local_prefer == NULL || local_prefer->weight < 0) {
440 pe_rsc_trace(rsc, "Not pre-allocating %s to %s - unavailable", rsc->id,
441 prefer->details->uname);
442 return NULL;
443 }
444 }
445
446 can_run_instance(rsc, NULL, limit);
447
448 backup = node_hash_dup(rsc->allowed_nodes);
449 chosen = rsc->cmds->allocate(rsc, prefer, data_set);
450 if (chosen) {
451 node_t *local_node = parent_node_instance(rsc, chosen);
452 if (prefer && chosen && chosen->details != prefer->details) {
453 crm_notice("Pre-allocation failed: got %s instead of %s",
454 chosen->details->uname, prefer->details->uname);
455 g_hash_table_destroy(rsc->allowed_nodes);
456 rsc->allowed_nodes = backup;
457 native_deallocate(rsc);
458 chosen = NULL;
459 backup = NULL;
460
461 } else if (local_node) {
462 local_node->count++;
463
464 } else if (is_set(rsc->flags, pe_rsc_managed)) {
465
466 crm_config_err("%s not found in %s (list=%d)",
467 chosen->details->id, rsc->parent->id,
468 g_hash_table_size(rsc->parent->allowed_nodes));
469 }
470 }
471
472 if(backup) {
473 g_hash_table_destroy(backup);
474 }
475 return chosen;
476 }
477
478 static void
479 append_parent_colocation(resource_t * rsc, resource_t * child, gboolean all)
480 {
481
482 GListPtr gIter = NULL;
483
484 gIter = rsc->rsc_cons;
485 for (; gIter != NULL; gIter = gIter->next) {
486 rsc_colocation_t *cons = (rsc_colocation_t *) gIter->data;
487
488 if (all || cons->score < 0 || cons->score == INFINITY) {
489 child->rsc_cons = g_list_prepend(child->rsc_cons, cons);
490 }
491 }
492
493 gIter = rsc->rsc_cons_lhs;
494 for (; gIter != NULL; gIter = gIter->next) {
495 rsc_colocation_t *cons = (rsc_colocation_t *) gIter->data;
496
497 if (all || cons->score < 0) {
498 child->rsc_cons_lhs = g_list_prepend(child->rsc_cons_lhs, cons);
499 }
500 }
501 }
502
503
504 void
505 distribute_children(resource_t *rsc, GListPtr children, GListPtr nodes,
506 int max, int per_host_max, pe_working_set_t * data_set);
507
508 void
509 distribute_children(resource_t *rsc, GListPtr children, GListPtr nodes,
510 int max, int per_host_max, pe_working_set_t * data_set)
511 {
512 int loop_max = 0;
513 int allocated = 0;
514 int available_nodes = 0;
515
516
517 for(GListPtr nIter = nodes; nIter != NULL; nIter = nIter->next) {
518 pe_node_t *node = nIter->data;
519
520 node->count = 0;
521 if (can_run_resources(node)) {
522 available_nodes++;
523 }
524 }
525
526 if(available_nodes) {
527 loop_max = max / available_nodes;
528 }
529 if (loop_max < 1) {
530 loop_max = 1;
531 }
532
533 pe_rsc_debug(rsc, "Allocating up to %d %s instances to a possible %d nodes (at most %d per host, %d optimal)",
534 max, rsc->id, available_nodes, per_host_max, loop_max);
535
536
537 for (GListPtr gIter = children; gIter != NULL && allocated < max; gIter = gIter->next) {
538 resource_t *child = (resource_t *) gIter->data;
539
540 if (child->running_on && is_set(child->flags, pe_rsc_provisional)
541 && is_not_set(child->flags, pe_rsc_failed)) {
542 node_t *child_node = child->running_on->data;
543 node_t *local_node = parent_node_instance(child, child->running_on->data);
544
545 pe_rsc_trace(rsc, "Checking pre-allocation of %s to %s (%d remaining of %d)",
546 child->id, child_node->details->uname, max - allocated, max);
547
548 if (can_run_resources(child_node) == FALSE || child_node->weight < 0) {
549 pe_rsc_trace(rsc, "Not pre-allocating because %s can not run %s",
550 child_node->details->uname, child->id);
551
552 } else if(local_node && local_node->count >= loop_max) {
553 pe_rsc_trace(rsc,
554 "Not pre-allocating because %s already allocated optimal instances",
555 child_node->details->uname);
556
557 } else if (color_instance(child, child_node, max < available_nodes, per_host_max, data_set)) {
558 pe_rsc_trace(rsc, "Pre-allocated %s to %s", child->id,
559 child_node->details->uname);
560 allocated++;
561 }
562 }
563 }
564
565 pe_rsc_trace(rsc, "Done pre-allocating (%d of %d)", allocated, max);
566
567 for (GListPtr gIter = children; gIter != NULL; gIter = gIter->next) {
568 resource_t *child = (resource_t *) gIter->data;
569
570 if (g_list_length(child->running_on) > 0) {
571 node_t *child_node = child->running_on->data;
572 node_t *local_node = parent_node_instance(child, child->running_on->data);
573
574 if (local_node == NULL) {
575 crm_err("%s is running on %s which isn't allowed",
576 child->id, child_node->details->uname);
577 }
578 }
579
580 if (is_not_set(child->flags, pe_rsc_provisional)) {
581 } else if (allocated >= max) {
582 pe_rsc_debug(rsc, "Child %s not allocated - limit reached %d %d", child->id, allocated, max);
583 resource_location(child, NULL, -INFINITY, "clone_color:limit_reached", data_set);
584 } else {
585 if (color_instance(child, NULL, max < available_nodes, per_host_max, data_set)) {
586 allocated++;
587 }
588 }
589 }
590
591 pe_rsc_debug(rsc, "Allocated %d %s instances of a possible %d",
592 allocated, rsc->id, max);
593 }
594
595
596 node_t *
597 clone_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set)
598 {
599 GListPtr nodes = NULL;
600
601 clone_variant_data_t *clone_data = NULL;
602
603 get_clone_variant_data(clone_data, rsc);
604
605 if (is_not_set(rsc->flags, pe_rsc_provisional)) {
606 return NULL;
607
608 } else if (is_set(rsc->flags, pe_rsc_allocating)) {
609 pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
610 return NULL;
611 }
612
613 set_bit(rsc->flags, pe_rsc_allocating);
614 pe_rsc_trace(rsc, "Processing %s", rsc->id);
615
616
617
618
619 for (GListPtr gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
620 rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
621
622 pe_rsc_trace(rsc, "%s: Coloring %s first", rsc->id, constraint->rsc_rh->id);
623 constraint->rsc_rh->cmds->allocate(constraint->rsc_rh, prefer, data_set);
624 }
625
626 for (GListPtr gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
627 rsc_colocation_t *constraint = (rsc_colocation_t *) gIter->data;
628
629 rsc->allowed_nodes =
630 constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id, rsc->allowed_nodes,
631 constraint->node_attribute,
632 (float)constraint->score / INFINITY,
633 (pe_weights_rollback | pe_weights_positive));
634 }
635
636 dump_node_scores(show_scores ? 0 : scores_log_level, rsc, __FUNCTION__, rsc->allowed_nodes);
637
638 nodes = g_hash_table_get_values(rsc->allowed_nodes);
639 nodes = g_list_sort_with_data(nodes, sort_node_weight, NULL);
640 rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set);
641 distribute_children(rsc, rsc->children, nodes, clone_data->clone_max, clone_data->clone_node_max, data_set);
642 g_list_free(nodes);
643
644 clear_bit(rsc->flags, pe_rsc_provisional);
645 clear_bit(rsc->flags, pe_rsc_allocating);
646
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(resource_t * rsc, const char *key, gboolean active_only, GListPtr * list)
715 {
716 action_t *match = NULL;
717 GListPtr possible = NULL;
718 GListPtr active = NULL;
719
720 possible = find_actions(rsc->actions, key, NULL);
721
722 if (active_only) {
723 GListPtr gIter = possible;
724
725 for (; gIter != NULL; gIter = gIter->next) {
726 action_t *op = (action_t *) gIter->data;
727
728 if (is_set(op->flags, pe_action_optional) == FALSE) {
729 active = g_list_prepend(active, op);
730 }
731 }
732
733 if (active && g_list_length(active) == 1) {
734 match = g_list_nth_data(active, 0);
735 }
736
737 if (list) {
738 *list = active;
739 active = NULL;
740 }
741
742 } else if (possible && g_list_length(possible) == 1) {
743 match = g_list_nth_data(possible, 0);
744
745 }
746 if (list) {
747 *list = possible;
748 possible = NULL;
749 }
750
751 if (possible) {
752 g_list_free(possible);
753 }
754 if (active) {
755 g_list_free(active);
756 }
757
758 return match;
759 }
760
761 static void
762 child_ordering_constraints(resource_t * rsc, pe_working_set_t * data_set)
763 {
764 char *key = NULL;
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;
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
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 key = stop_key(child);
785 stop = find_rsc_action(child, key, active_only, NULL);
786 free(key);
787
788 key = start_key(child);
789 start = find_rsc_action(child, key, active_only, NULL);
790 free(key);
791
792 if (stop) {
793 if (last_stop) {
794
795 order_actions(stop, last_stop, pe_order_optional);
796 }
797 last_stop = stop;
798 }
799
800 if (start) {
801 if (last_start) {
802
803 order_actions(last_start, start, pe_order_optional);
804 }
805 last_start = start;
806 }
807 }
808 }
809
810 void
811 clone_create_actions(resource_t * rsc, pe_working_set_t * data_set)
812 {
813 clone_variant_data_t *clone_data = NULL;
814
815 get_clone_variant_data(clone_data, rsc);
816 clone_create_pseudo_actions(rsc, rsc->children, &clone_data->start_notify, &clone_data->stop_notify,data_set);
817 child_ordering_constraints(rsc, data_set);
818 }
819
820 void
821 clone_create_pseudo_actions(
822 resource_t * rsc, GListPtr children, notify_data_t **start_notify, notify_data_t **stop_notify, pe_working_set_t * data_set)
823 {
824 gboolean child_active = FALSE;
825 gboolean child_starting = FALSE;
826 gboolean child_stopping = FALSE;
827 gboolean allow_dependent_migrations = TRUE;
828
829 action_t *stop = NULL;
830 action_t *stopped = NULL;
831
832 action_t *start = NULL;
833 action_t *started = NULL;
834
835 pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
836
837 for (GListPtr gIter = children; gIter != NULL; gIter = gIter->next) {
838 resource_t *child_rsc = (resource_t *) gIter->data;
839 gboolean starting = FALSE;
840 gboolean stopping = FALSE;
841
842 child_rsc->cmds->create_actions(child_rsc, data_set);
843 clone_update_pseudo_status(child_rsc, &stopping, &starting, &child_active);
844 if (stopping && starting) {
845 allow_dependent_migrations = FALSE;
846 }
847
848 child_stopping |= stopping;
849 child_starting |= starting;
850 }
851
852
853 start = create_pseudo_resource_op(rsc, RSC_START, !child_starting, TRUE, data_set);
854 started = create_pseudo_resource_op(rsc, RSC_STARTED, !child_starting, FALSE, data_set);
855 started->priority = INFINITY;
856
857 if (child_active || child_starting) {
858 update_action_flags(started, pe_action_runnable, __FUNCTION__, __LINE__);
859 }
860
861 if (start_notify != NULL && *start_notify == NULL) {
862 *start_notify = create_notification_boundaries(rsc, RSC_START, start, started, data_set);
863 }
864
865
866 stop = create_pseudo_resource_op(rsc, RSC_STOP, !child_stopping, TRUE, data_set);
867 stopped = create_pseudo_resource_op(rsc, RSC_STOPPED, !child_stopping, TRUE, data_set);
868 stopped->priority = INFINITY;
869 if (allow_dependent_migrations) {
870 update_action_flags(stop, pe_action_migrate_runnable, __FUNCTION__, __LINE__);
871 }
872
873 if (stop_notify != NULL && *stop_notify == NULL) {
874 *stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
875
876 if (start_notify && *start_notify && *stop_notify) {
877 order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
878 }
879 }
880 }
881
882 void
883 clone_internal_constraints(resource_t * rsc, pe_working_set_t * data_set)
884 {
885 resource_t *last_rsc = NULL;
886 GListPtr gIter;
887 clone_variant_data_t *clone_data = NULL;
888
889 get_clone_variant_data(clone_data, rsc);
890
891 pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
892 new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
893 new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
894 new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
895
896 if (rsc->variant == pe_master) {
897 new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
898 new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set);
899 }
900
901 if (clone_data->ordered) {
902
903 rsc->children = g_list_sort(rsc->children, sort_rsc_id);
904 }
905 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
906 resource_t *child_rsc = (resource_t *) gIter->data;
907
908 child_rsc->cmds->internal_constraints(child_rsc, data_set);
909
910 order_start_start(rsc, child_rsc, pe_order_runnable_left | pe_order_implies_first_printed);
911 new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed,
912 data_set);
913 if (clone_data->ordered && last_rsc) {
914 order_start_start(last_rsc, child_rsc, pe_order_optional);
915 }
916
917 order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed);
918 new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed,
919 data_set);
920 if (clone_data->ordered && last_rsc) {
921 order_stop_stop(child_rsc, last_rsc, pe_order_optional);
922 }
923
924 last_rsc = child_rsc;
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 if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
959
960 node = child_rsc->fns->location(child_rsc, NULL, current);
961 }
962
963 if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
964 crm_trace("Filtered %s", child_rsc->id);
965 return FALSE;
966 }
967
968 if (node && local_node && node->details == local_node->details) {
969 return TRUE;
970
971 } else if (node) {
972 crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
973 local_node->details->uname);
974
975 } else {
976 crm_trace("%s - not allocated %d", child_rsc->id, current);
977 }
978 return FALSE;
979 }
980
981 resource_t *
982 find_compatible_child(resource_t * local_child, resource_t * rsc, enum rsc_role_e filter, gboolean current)
983 {
984 resource_t *pair = NULL;
985 GListPtr gIter = NULL;
986 GListPtr scratch = NULL;
987 node_t *local_node = NULL;
988
989 local_node = local_child->fns->location(local_child, NULL, current);
990 if (local_node) {
991 return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
992 }
993
994 scratch = g_hash_table_get_values(local_child->allowed_nodes);
995 scratch = g_list_sort_with_data(scratch, sort_node_weight, NULL);
996
997 gIter = scratch;
998 for (; gIter != NULL; gIter = gIter->next) {
999 node_t *node = (node_t *) gIter->data;
1000
1001 pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
1002 if (pair) {
1003 goto done;
1004 }
1005 }
1006
1007 pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
1008 done:
1009 g_list_free(scratch);
1010 return pair;
1011 }
1012
1013 void
1014 clone_rsc_colocation_lh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
1015 {
1016
1017
1018
1019
1020 CRM_ASSERT(FALSE);
1021 }
1022
1023 void
1024 clone_rsc_colocation_rh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint)
1025 {
1026 GListPtr gIter = NULL;
1027 gboolean do_interleave = FALSE;
1028 const char *interleave_s = NULL;
1029
1030 CRM_CHECK(constraint != NULL, return);
1031 CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
1032 CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
1033 CRM_CHECK(rsc_lh->variant == pe_native, return);
1034
1035 pe_rsc_trace(rsc_rh, "Processing constraint %s: %s -> %s %d",
1036 constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);
1037
1038
1039 interleave_s = g_hash_table_lookup(constraint->rsc_lh->meta, XML_RSC_ATTR_INTERLEAVE);
1040 if(crm_is_true(interleave_s) && constraint->rsc_lh->variant > pe_group) {
1041
1042 if (copies_per_node(constraint->rsc_lh) != copies_per_node(constraint->rsc_rh)) {
1043 crm_config_err("Cannot interleave %s and %s because"
1044 " they do not support the same number of copies per node",
1045 constraint->rsc_lh->id, constraint->rsc_rh->id);
1046
1047 } else {
1048 do_interleave = TRUE;
1049 }
1050 }
1051
1052 if (is_set(rsc_rh->flags, pe_rsc_provisional)) {
1053 pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1054 return;
1055
1056 } else if (do_interleave) {
1057 resource_t *rh_child = NULL;
1058
1059 rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN, FALSE);
1060
1061 if (rh_child) {
1062 pe_rsc_debug(rsc_rh, "Pairing %s with %s", rsc_lh->id, rh_child->id);
1063 rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint);
1064
1065 } else if (constraint->score >= INFINITY) {
1066 crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1067 assign_node(rsc_lh, NULL, TRUE);
1068
1069 } else {
1070 pe_rsc_debug(rsc_rh, "Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1071 }
1072
1073 return;
1074
1075 } else if (constraint->score >= INFINITY) {
1076 GListPtr rhs = NULL;
1077
1078 gIter = rsc_rh->children;
1079 for (; gIter != NULL; gIter = gIter->next) {
1080 resource_t *child_rsc = (resource_t *) gIter->data;
1081 node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1082
1083 if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1084 pe_rsc_trace(rsc_rh, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
1085 rhs = g_list_prepend(rhs, chosen);
1086 }
1087 }
1088
1089 node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
1090 g_list_free(rhs);
1091 return;
1092 }
1093
1094 gIter = rsc_rh->children;
1095 for (; gIter != NULL; gIter = gIter->next) {
1096 resource_t *child_rsc = (resource_t *) gIter->data;
1097
1098 child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
1099 }
1100 }
1101
1102 enum action_tasks
1103 clone_child_action(action_t * action)
1104 {
1105 enum action_tasks result = no_action;
1106 resource_t *child = (resource_t *) action->rsc->children->data;
1107
1108 if (safe_str_eq(action->task, "notify")
1109 || safe_str_eq(action->task, "notified")) {
1110
1111
1112
1113 int stop = 0;
1114 char *key = action->uuid;
1115 int lpc = strlen(key);
1116
1117 for (; lpc > 0; lpc--) {
1118 if (key[lpc] == '_' && stop == 0) {
1119 stop = lpc;
1120
1121 } else if (key[lpc] == '_') {
1122 char *task_mutable = NULL;
1123
1124 lpc++;
1125 task_mutable = strdup(key + lpc);
1126 task_mutable[stop - lpc] = 0;
1127
1128 crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
1129 result = get_complex_task(child, task_mutable, TRUE);
1130 free(task_mutable);
1131 break;
1132 }
1133 }
1134
1135 } else {
1136 result = get_complex_task(child, action->task, TRUE);
1137 }
1138 return result;
1139 }
1140
1141 enum pe_action_flags
1142 summary_action_flags(action_t * action, GListPtr children, node_t * node)
1143 {
1144 GListPtr gIter = NULL;
1145 gboolean any_runnable = FALSE;
1146 gboolean check_runnable = TRUE;
1147 enum action_tasks task = clone_child_action(action);
1148 enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
1149 const char *task_s = task2text(task);
1150
1151 for (gIter = children; gIter != NULL; gIter = gIter->next) {
1152 action_t *child_action = NULL;
1153 resource_t *child = (resource_t *) gIter->data;
1154
1155 child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
1156 pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
1157 node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
1158 if (child_action) {
1159 enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
1160
1161 if (is_set(flags, pe_action_optional)
1162 && is_set(child_flags, pe_action_optional) == FALSE) {
1163 pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
1164 child_action->uuid);
1165 flags = crm_clear_bit(__FUNCTION__, __LINE__, action->rsc->id, flags, pe_action_optional);
1166 pe_clear_action_bit(action, pe_action_optional);
1167 }
1168 if (is_set(child_flags, pe_action_runnable)) {
1169 any_runnable = TRUE;
1170 }
1171 }
1172 }
1173
1174 if (check_runnable && any_runnable == FALSE) {
1175 pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
1176 flags = crm_clear_bit(__FUNCTION__, __LINE__, action->rsc->id, flags, pe_action_runnable);
1177 if (node == NULL) {
1178 pe_clear_action_bit(action, pe_action_runnable);
1179 }
1180 }
1181
1182 return flags;
1183 }
1184
1185 enum pe_action_flags
1186 clone_action_flags(action_t * action, node_t * node)
1187 {
1188 return summary_action_flags(action, action->rsc->children, node);
1189 }
1190
1191 void
1192 clone_rsc_location(resource_t * rsc, rsc_to_node_t * constraint)
1193 {
1194 GListPtr gIter = rsc->children;
1195
1196 pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
1197
1198 native_rsc_location(rsc, constraint);
1199
1200 for (; gIter != NULL; gIter = gIter->next) {
1201 resource_t *child_rsc = (resource_t *) gIter->data;
1202
1203 child_rsc->cmds->rsc_location(child_rsc, constraint);
1204 }
1205 }
1206
1207 void
1208 clone_expand(resource_t * rsc, pe_working_set_t * data_set)
1209 {
1210 GListPtr gIter = NULL;
1211 clone_variant_data_t *clone_data = NULL;
1212
1213 get_clone_variant_data(clone_data, rsc);
1214
1215 gIter = rsc->actions;
1216 for (; gIter != NULL; gIter = gIter->next) {
1217 action_t *op = (action_t *) gIter->data;
1218
1219 rsc->cmds->action_flags(op, NULL);
1220 }
1221
1222 if (clone_data->start_notify) {
1223 collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
1224 expand_notification_data(rsc, clone_data->start_notify, data_set);
1225 create_notifications(rsc, clone_data->start_notify, data_set);
1226 }
1227
1228 if (clone_data->stop_notify) {
1229 collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
1230 expand_notification_data(rsc, clone_data->stop_notify, data_set);
1231 create_notifications(rsc, clone_data->stop_notify, data_set);
1232 }
1233
1234 if (clone_data->promote_notify) {
1235 collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
1236 expand_notification_data(rsc, clone_data->promote_notify, data_set);
1237 create_notifications(rsc, clone_data->promote_notify, data_set);
1238 }
1239
1240 if (clone_data->demote_notify) {
1241 collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
1242 expand_notification_data(rsc, clone_data->demote_notify, data_set);
1243 create_notifications(rsc, clone_data->demote_notify, data_set);
1244 }
1245
1246
1247
1248 gIter = rsc->children;
1249 for (; gIter != NULL; gIter = gIter->next) {
1250 resource_t *child_rsc = (resource_t *) gIter->data;
1251
1252 child_rsc->cmds->expand(child_rsc, data_set);
1253 }
1254
1255 native_expand(rsc, data_set);
1256
1257
1258 free_notification_data(clone_data->demote_notify);
1259 clone_data->demote_notify = NULL;
1260 free_notification_data(clone_data->stop_notify);
1261 clone_data->stop_notify = NULL;
1262 free_notification_data(clone_data->start_notify);
1263 clone_data->start_notify = NULL;
1264 free_notification_data(clone_data->promote_notify);
1265 clone_data->promote_notify = NULL;
1266 }
1267
1268 node_t *
1269 rsc_known_on(resource_t * rsc, GListPtr * list)
1270 {
1271 GListPtr gIter = NULL;
1272 node_t *one = NULL;
1273 GListPtr result = NULL;
1274
1275 if (rsc->children) {
1276
1277 gIter = rsc->children;
1278 for (; gIter != NULL; gIter = gIter->next) {
1279 resource_t *child = (resource_t *) gIter->data;
1280
1281 rsc_known_on(child, &result);
1282 }
1283
1284 } else if (rsc->known_on) {
1285 result = g_hash_table_get_values(rsc->known_on);
1286 }
1287
1288 if (result && g_list_length(result) == 1) {
1289 one = g_list_nth_data(result, 0);
1290 }
1291
1292 if (list) {
1293 GListPtr gIter = NULL;
1294
1295 gIter = result;
1296 for (; gIter != NULL; gIter = gIter->next) {
1297 node_t *node = (node_t *) gIter->data;
1298
1299 if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
1300 *list = g_list_prepend(*list, node);
1301 }
1302 }
1303 }
1304
1305 g_list_free(result);
1306 return one;
1307 }
1308
1309 static resource_t *
1310 find_instance_on(resource_t * rsc, node_t * node)
1311 {
1312 GListPtr gIter = NULL;
1313
1314 gIter = rsc->children;
1315 for (; gIter != NULL; gIter = gIter->next) {
1316 GListPtr gIter2 = NULL;
1317 GListPtr known_list = NULL;
1318 resource_t *child = (resource_t *) gIter->data;
1319
1320 rsc_known_on(child, &known_list);
1321
1322 gIter2 = known_list;
1323 for (; gIter2 != NULL; gIter2 = gIter2->next) {
1324 node_t *known = (node_t *) gIter2->data;
1325
1326 if (node->details == known->details) {
1327 g_list_free(known_list);
1328 return child;
1329 }
1330 }
1331 g_list_free(known_list);
1332 }
1333
1334 return NULL;
1335 }
1336
1337 gboolean
1338 clone_create_probe(resource_t * rsc, node_t * node, action_t * complete,
1339 gboolean force, pe_working_set_t * data_set)
1340 {
1341 GListPtr gIter = NULL;
1342 gboolean any_created = FALSE;
1343 clone_variant_data_t *clone_data = NULL;
1344
1345 CRM_ASSERT(rsc);
1346 get_clone_variant_data(clone_data, rsc);
1347
1348 rsc->children = g_list_sort(rsc->children, sort_rsc_id);
1349 if (rsc->children == NULL) {
1350 pe_warn("Clone %s has no children", rsc->id);
1351 return FALSE;
1352 }
1353
1354 if (rsc->exclusive_discover) {
1355 node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1356 if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1357
1358
1359
1360
1361
1362
1363
1364 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1365
1366
1367 return FALSE;
1368 }
1369 }
1370
1371 if (is_not_set(rsc->flags, pe_rsc_unique)
1372 && clone_data->clone_node_max == 1) {
1373
1374 resource_t *child = NULL;
1375
1376
1377 child = find_instance_on(rsc, node);
1378 if (child) {
1379 return child->cmds->create_probe(child, node, complete, force, data_set);
1380 }
1381
1382
1383 gIter = rsc->children;
1384 for (; gIter != NULL; gIter = gIter->next) {
1385 node_t *local_node = NULL;
1386 resource_t *child_rsc = (resource_t *) gIter->data;
1387
1388 CRM_ASSERT(child_rsc);
1389 local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1390 if (local_node == NULL) {
1391 continue;
1392 }
1393
1394 if (local_node->details == node->details) {
1395 return child_rsc->cmds->create_probe(child_rsc, node, complete, force, data_set);
1396 }
1397 }
1398
1399
1400 CRM_ASSERT(rsc->children);
1401 child = rsc->children->data;
1402 return child->cmds->create_probe(child, node, complete, force, data_set);
1403 }
1404
1405 gIter = rsc->children;
1406 for (; gIter != NULL; gIter = gIter->next) {
1407 resource_t *child_rsc = (resource_t *) gIter->data;
1408
1409 if (child_rsc->cmds->create_probe(child_rsc, node, complete, force, data_set)) {
1410 any_created = TRUE;
1411 }
1412
1413 if (any_created && is_not_set(rsc->flags, pe_rsc_unique)
1414 && clone_data->clone_node_max == 1) {
1415
1416 break;
1417 }
1418 }
1419
1420 return any_created;
1421 }
1422
1423 void
1424 clone_append_meta(resource_t * rsc, xmlNode * xml)
1425 {
1426 char *name = NULL;
1427 clone_variant_data_t *clone_data = NULL;
1428
1429 get_clone_variant_data(clone_data, rsc);
1430
1431 name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
1432 crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
1433 free(name);
1434
1435 name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
1436 crm_xml_add(xml, name, is_set(rsc->flags, pe_rsc_notify) ? "true" : "false");
1437 free(name);
1438
1439 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
1440 crm_xml_add_int(xml, name, clone_data->clone_max);
1441 free(name);
1442
1443 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
1444 crm_xml_add_int(xml, name, clone_data->clone_node_max);
1445 free(name);
1446 }
1447
1448 GHashTable *
1449 clone_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr,
1450 float factor, enum pe_weights flags)
1451 {
1452 return rsc_merge_weights(rsc, rhs, nodes, attr, factor, flags);
1453 }