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