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 update_action_flags(started, pe_action_runnable, __func__, __LINE__);
949 }
950
951 if (start_notify != NULL && *start_notify == NULL) {
952 *start_notify = create_notification_boundaries(rsc, RSC_START, start, started, data_set);
953 }
954
955
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 update_action_flags(stop, pe_action_migrate_runnable, __func__,
961 __LINE__);
962 }
963
964 if (stop_notify != NULL && *stop_notify == NULL) {
965 *stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
966
967 if (start_notify && *start_notify && *stop_notify) {
968 order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
969 }
970 }
971 }
972
973 void
974 clone_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
975 {
976 pe_resource_t *last_rsc = NULL;
977 GList *gIter;
978 clone_variant_data_t *clone_data = NULL;
979
980 get_clone_variant_data(clone_data, rsc);
981
982 pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
983 new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
984 new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
985 new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
986
987 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
988 new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
989 new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set);
990 }
991
992 if (clone_data->ordered) {
993
994 rsc->children = g_list_sort(rsc->children, sort_rsc_id);
995 }
996 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
997 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
998
999 child_rsc->cmds->internal_constraints(child_rsc, data_set);
1000
1001 order_start_start(rsc, child_rsc, pe_order_runnable_left | pe_order_implies_first_printed);
1002 new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed,
1003 data_set);
1004 if (clone_data->ordered && last_rsc) {
1005 order_start_start(last_rsc, child_rsc, pe_order_optional);
1006 }
1007
1008 order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed);
1009 new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed,
1010 data_set);
1011 if (clone_data->ordered && last_rsc) {
1012 order_stop_stop(child_rsc, last_rsc, pe_order_optional);
1013 }
1014
1015 last_rsc = child_rsc;
1016 }
1017 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1018 promotable_constraints(rsc, data_set);
1019 }
1020 }
1021
1022 bool
1023 assign_node(pe_resource_t * rsc, pe_node_t * node, gboolean force)
1024 {
1025 bool changed = FALSE;
1026
1027 if (rsc->children) {
1028
1029 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1030 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1031
1032 changed |= assign_node(child_rsc, node, force);
1033 }
1034
1035 return changed;
1036 }
1037
1038 if (rsc->allocated_to != NULL) {
1039 changed = true;
1040 }
1041
1042 native_assign_node(rsc, node, force);
1043 return changed;
1044 }
1045
1046 gboolean
1047 is_child_compatible(pe_resource_t *child_rsc, pe_node_t * local_node, enum rsc_role_e filter, gboolean current)
1048 {
1049 pe_node_t *node = NULL;
1050 enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
1051
1052 CRM_CHECK(child_rsc && local_node, return FALSE);
1053 if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1054
1055 node = child_rsc->fns->location(child_rsc, NULL, current);
1056 }
1057
1058 if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
1059 crm_trace("Filtered %s", child_rsc->id);
1060 return FALSE;
1061 }
1062
1063 if (node && (node->details == local_node->details)) {
1064 return TRUE;
1065
1066 } else if (node) {
1067 crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
1068 local_node->details->uname);
1069
1070 } else {
1071 crm_trace("%s - not allocated %d", child_rsc->id, current);
1072 }
1073 return FALSE;
1074 }
1075
1076 pe_resource_t *
1077 find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc,
1078 enum rsc_role_e filter, gboolean current,
1079 pe_working_set_t *data_set)
1080 {
1081 pe_resource_t *pair = NULL;
1082 GList *gIter = NULL;
1083 GList *scratch = NULL;
1084 pe_node_t *local_node = NULL;
1085
1086 local_node = local_child->fns->location(local_child, NULL, current);
1087 if (local_node) {
1088 return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
1089 }
1090
1091 scratch = g_hash_table_get_values(local_child->allowed_nodes);
1092 scratch = sort_nodes_by_weight(scratch, NULL, data_set);
1093
1094 gIter = scratch;
1095 for (; gIter != NULL; gIter = gIter->next) {
1096 pe_node_t *node = (pe_node_t *) gIter->data;
1097
1098 pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
1099 if (pair) {
1100 goto done;
1101 }
1102 }
1103
1104 pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
1105 done:
1106 g_list_free(scratch);
1107 return pair;
1108 }
1109
1110 void
1111 clone_rsc_colocation_lh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
1112 pcmk__colocation_t *constraint,
1113 pe_working_set_t *data_set)
1114 {
1115
1116
1117
1118
1119 CRM_ASSERT(FALSE);
1120 }
1121
1122 void
1123 clone_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
1124 pcmk__colocation_t *constraint,
1125 pe_working_set_t *data_set)
1126 {
1127 GList *gIter = NULL;
1128 gboolean do_interleave = FALSE;
1129 const char *interleave_s = NULL;
1130
1131 CRM_CHECK(constraint != NULL, return);
1132 CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
1133 CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
1134 CRM_CHECK(rsc_lh->variant == pe_native, return);
1135
1136 pe_rsc_trace(rsc_rh, "Processing constraint %s: %s -> %s %d",
1137 constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);
1138
1139 if (pcmk_is_set(rsc_rh->flags, pe_rsc_promotable)) {
1140 if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1141 pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1142 return;
1143 } else if (constraint->role_rh == RSC_ROLE_UNKNOWN) {
1144 pe_rsc_trace(rsc_rh, "Handling %s as a clone colocation", constraint->id);
1145 } else {
1146 promotable_colocation_rh(rsc_lh, rsc_rh, constraint, data_set);
1147 return;
1148 }
1149 }
1150
1151
1152 interleave_s = g_hash_table_lookup(constraint->rsc_lh->meta, XML_RSC_ATTR_INTERLEAVE);
1153 if(crm_is_true(interleave_s) && constraint->rsc_lh->variant > pe_group) {
1154
1155 if (copies_per_node(constraint->rsc_lh) != copies_per_node(constraint->rsc_rh)) {
1156 pcmk__config_err("Cannot interleave %s and %s because they do not "
1157 "support the same number of instances per node",
1158 constraint->rsc_lh->id, constraint->rsc_rh->id);
1159
1160 } else {
1161 do_interleave = TRUE;
1162 }
1163 }
1164
1165 if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1166 pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1167 return;
1168
1169 } else if (do_interleave) {
1170 pe_resource_t *rh_child = NULL;
1171
1172 rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN,
1173 FALSE, data_set);
1174
1175 if (rh_child) {
1176 pe_rsc_debug(rsc_rh, "Pairing %s with %s", rsc_lh->id, rh_child->id);
1177 rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint,
1178 data_set);
1179
1180 } else if (constraint->score >= INFINITY) {
1181 crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1182 assign_node(rsc_lh, NULL, TRUE);
1183
1184 } else {
1185 pe_rsc_debug(rsc_rh, "Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1186 }
1187
1188 return;
1189
1190 } else if (constraint->score >= INFINITY) {
1191 GList *rhs = NULL;
1192
1193 gIter = rsc_rh->children;
1194 for (; gIter != NULL; gIter = gIter->next) {
1195 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1196 pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1197
1198 if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1199 pe_rsc_trace(rsc_rh, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
1200 rhs = g_list_prepend(rhs, chosen);
1201 }
1202 }
1203
1204 node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
1205 g_list_free(rhs);
1206 return;
1207 }
1208
1209 gIter = rsc_rh->children;
1210 for (; gIter != NULL; gIter = gIter->next) {
1211 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1212
1213 child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint,
1214 data_set);
1215 }
1216 }
1217
1218 enum action_tasks
1219 clone_child_action(pe_action_t * action)
1220 {
1221 enum action_tasks result = no_action;
1222 pe_resource_t *child = (pe_resource_t *) action->rsc->children->data;
1223
1224 if (pcmk__strcase_any_of(action->task, "notify", "notified", NULL)) {
1225
1226
1227
1228 int stop = 0;
1229 char *key = action->uuid;
1230 int lpc = strlen(key);
1231
1232 for (; lpc > 0; lpc--) {
1233 if (key[lpc] == '_' && stop == 0) {
1234 stop = lpc;
1235
1236 } else if (key[lpc] == '_') {
1237 char *task_mutable = NULL;
1238
1239 lpc++;
1240 task_mutable = strdup(key + lpc);
1241 task_mutable[stop - lpc] = 0;
1242
1243 crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
1244 result = get_complex_task(child, task_mutable, TRUE);
1245 free(task_mutable);
1246 break;
1247 }
1248 }
1249
1250 } else {
1251 result = get_complex_task(child, action->task, TRUE);
1252 }
1253 return result;
1254 }
1255
1256 #define pe__clear_action_summary_flags(flags, action, flag) do { \
1257 flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
1258 "Action summary", action->rsc->id, \
1259 flags, flag, #flag); \
1260 } while (0)
1261
1262 enum pe_action_flags
1263 summary_action_flags(pe_action_t * action, GList *children, pe_node_t * node)
1264 {
1265 GList *gIter = NULL;
1266 gboolean any_runnable = FALSE;
1267 gboolean check_runnable = TRUE;
1268 enum action_tasks task = clone_child_action(action);
1269 enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
1270 const char *task_s = task2text(task);
1271
1272 for (gIter = children; gIter != NULL; gIter = gIter->next) {
1273 pe_action_t *child_action = NULL;
1274 pe_resource_t *child = (pe_resource_t *) gIter->data;
1275
1276 child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
1277 pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
1278 node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
1279 if (child_action) {
1280 enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
1281
1282 if (pcmk_is_set(flags, pe_action_optional)
1283 && !pcmk_is_set(child_flags, pe_action_optional)) {
1284 pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
1285 child_action->uuid);
1286 pe__clear_action_summary_flags(flags, action, pe_action_optional);
1287 pe__clear_action_flags(action, pe_action_optional);
1288 }
1289 if (pcmk_is_set(child_flags, pe_action_runnable)) {
1290 any_runnable = TRUE;
1291 }
1292 }
1293 }
1294
1295 if (check_runnable && any_runnable == FALSE) {
1296 pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
1297 pe__clear_action_summary_flags(flags, action, pe_action_runnable);
1298 if (node == NULL) {
1299 pe__clear_action_flags(action, pe_action_runnable);
1300 }
1301 }
1302
1303 return flags;
1304 }
1305
1306 enum pe_action_flags
1307 clone_action_flags(pe_action_t * action, pe_node_t * node)
1308 {
1309 return summary_action_flags(action, action->rsc->children, node);
1310 }
1311
1312 void
1313 clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
1314 {
1315 GList *gIter = rsc->children;
1316
1317 pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
1318
1319 native_rsc_location(rsc, constraint);
1320
1321 for (; gIter != NULL; gIter = gIter->next) {
1322 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1323
1324 child_rsc->cmds->rsc_location(child_rsc, constraint);
1325 }
1326 }
1327
1328 void
1329 clone_expand(pe_resource_t * rsc, pe_working_set_t * data_set)
1330 {
1331 GList *gIter = NULL;
1332 clone_variant_data_t *clone_data = NULL;
1333
1334 get_clone_variant_data(clone_data, rsc);
1335
1336 gIter = rsc->actions;
1337 for (; gIter != NULL; gIter = gIter->next) {
1338 pe_action_t *op = (pe_action_t *) gIter->data;
1339
1340 rsc->cmds->action_flags(op, NULL);
1341 }
1342
1343 if (clone_data->start_notify) {
1344 collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
1345 pcmk__create_notification_keys(rsc, clone_data->start_notify, data_set);
1346 create_notifications(rsc, clone_data->start_notify, data_set);
1347 }
1348
1349 if (clone_data->stop_notify) {
1350 collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
1351 pcmk__create_notification_keys(rsc, clone_data->stop_notify, data_set);
1352 create_notifications(rsc, clone_data->stop_notify, data_set);
1353 }
1354
1355 if (clone_data->promote_notify) {
1356 collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
1357 pcmk__create_notification_keys(rsc, clone_data->promote_notify, data_set);
1358 create_notifications(rsc, clone_data->promote_notify, data_set);
1359 }
1360
1361 if (clone_data->demote_notify) {
1362 collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
1363 pcmk__create_notification_keys(rsc, clone_data->demote_notify, data_set);
1364 create_notifications(rsc, clone_data->demote_notify, data_set);
1365 }
1366
1367
1368
1369 gIter = rsc->children;
1370 for (; gIter != NULL; gIter = gIter->next) {
1371 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1372
1373 child_rsc->cmds->expand(child_rsc, data_set);
1374 }
1375
1376 native_expand(rsc, data_set);
1377
1378
1379 free_notification_data(clone_data->demote_notify);
1380 clone_data->demote_notify = NULL;
1381 free_notification_data(clone_data->stop_notify);
1382 clone_data->stop_notify = NULL;
1383 free_notification_data(clone_data->start_notify);
1384 clone_data->start_notify = NULL;
1385 free_notification_data(clone_data->promote_notify);
1386 clone_data->promote_notify = NULL;
1387 }
1388
1389
1390 static bool
1391 rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
1392 {
1393 if (rsc->children) {
1394 for (GList *child_iter = rsc->children; child_iter != NULL;
1395 child_iter = child_iter->next) {
1396
1397 pe_resource_t *child = (pe_resource_t *) child_iter->data;
1398
1399 if (rsc_known_on(child, node)) {
1400 return TRUE;
1401 }
1402 }
1403
1404 } else if (rsc->known_on) {
1405 GHashTableIter iter;
1406 pe_node_t *known_node = NULL;
1407
1408 g_hash_table_iter_init(&iter, rsc->known_on);
1409 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
1410 if (node->details == known_node->details) {
1411 return TRUE;
1412 }
1413 }
1414 }
1415 return FALSE;
1416 }
1417
1418
1419 static pe_resource_t *
1420 find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
1421 {
1422 for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
1423 pe_resource_t *child = (pe_resource_t *) gIter->data;
1424
1425 if (rsc_known_on(child, node)) {
1426 return child;
1427 }
1428 }
1429 return NULL;
1430 }
1431
1432
1433 static gboolean
1434 probe_unique_clone(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete,
1435 gboolean force, pe_working_set_t *data_set)
1436 {
1437 gboolean any_created = FALSE;
1438
1439 for (GList *child_iter = rsc->children; child_iter != NULL;
1440 child_iter = child_iter->next) {
1441
1442 pe_resource_t *child = (pe_resource_t *) child_iter->data;
1443
1444 any_created |= child->cmds->create_probe(child, node, complete, force,
1445 data_set);
1446 }
1447 return any_created;
1448 }
1449
1450
1451 static gboolean
1452 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
1453 pe_action_t *complete, gboolean force,
1454 pe_working_set_t *data_set)
1455 {
1456
1457 pe_resource_t *child = find_instance_on(rsc, node);
1458
1459
1460 if (child == NULL) {
1461 for (GList *child_iter = rsc->children; child_iter && !child;
1462 child_iter = child_iter->next) {
1463
1464 pe_node_t *local_node = NULL;
1465 pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
1466
1467 if (child_rsc) {
1468 local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1469 if (local_node && (local_node->details == node->details)) {
1470 child = child_rsc;
1471 }
1472 }
1473 }
1474 }
1475
1476
1477 if (child == NULL) {
1478 child = rsc->children->data;
1479 }
1480 CRM_ASSERT(child);
1481 return child->cmds->create_probe(child, node, complete, force, data_set);
1482 }
1483
1484 gboolean
1485 clone_create_probe(pe_resource_t * rsc, pe_node_t * node, pe_action_t * complete,
1486 gboolean force, pe_working_set_t * data_set)
1487 {
1488 gboolean any_created = FALSE;
1489
1490 CRM_ASSERT(rsc);
1491
1492 rsc->children = g_list_sort(rsc->children, sort_rsc_id);
1493 if (rsc->children == NULL) {
1494 pe_warn("Clone %s has no children", rsc->id);
1495 return FALSE;
1496 }
1497
1498 if (rsc->exclusive_discover) {
1499 pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1500 if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1501
1502
1503
1504
1505
1506
1507
1508 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1509
1510
1511 return FALSE;
1512 }
1513 }
1514
1515 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1516 any_created = probe_unique_clone(rsc, node, complete, force, data_set);
1517 } else {
1518 any_created = probe_anonymous_clone(rsc, node, complete, force,
1519 data_set);
1520 }
1521 return any_created;
1522 }
1523
1524 void
1525 clone_append_meta(pe_resource_t * rsc, xmlNode * xml)
1526 {
1527 char *name = NULL;
1528 clone_variant_data_t *clone_data = NULL;
1529
1530 get_clone_variant_data(clone_data, rsc);
1531
1532 name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
1533 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1534 free(name);
1535
1536 name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
1537 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1538 free(name);
1539
1540 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
1541 crm_xml_add_int(xml, name, clone_data->clone_max);
1542 free(name);
1543
1544 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
1545 crm_xml_add_int(xml, name, clone_data->clone_node_max);
1546 free(name);
1547
1548 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1549 name = crm_meta_name(XML_RSC_ATTR_PROMOTED_MAX);
1550 crm_xml_add_int(xml, name, clone_data->promoted_max);
1551 free(name);
1552
1553 name = crm_meta_name(XML_RSC_ATTR_PROMOTED_NODEMAX);
1554 crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1555 free(name);
1556
1557
1558
1559
1560 name = crm_meta_name(PCMK_XE_PROMOTED_MAX_LEGACY);
1561 crm_xml_add_int(xml, name, clone_data->promoted_max);
1562 free(name);
1563
1564 name = crm_meta_name(PCMK_XE_PROMOTED_NODE_MAX_LEGACY);
1565 crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1566 free(name);
1567 }
1568 }