pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_clone.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2021 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <crm/msg_xml.h>
13#include <pacemaker-internal.h>
14
15#define VARIANT_CLONE 1
16#include <lib/pengine/variant.h>
17
18gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
19static void append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all);
20
21static gint
22sort_rsc_id(gconstpointer a, gconstpointer b)
23{
24 const pe_resource_t *resource1 = (const pe_resource_t *)a;
25 const pe_resource_t *resource2 = (const pe_resource_t *)b;
26 long num1, num2;
27
28 CRM_ASSERT(resource1 != NULL);
29 CRM_ASSERT(resource2 != NULL);
30
31 /*
32 * Sort clone instances numerically by instance number, so instance :10
33 * comes after :9.
34 */
35 num1 = strtol(strrchr(resource1->id, ':') + 1, NULL, 10);
36 num2 = strtol(strrchr(resource2->id, ':') + 1, NULL, 10);
37 if (num1 < num2) {
38 return -1;
39 } else if (num1 > num2) {
40 return 1;
41 }
42 return 0;
43}
44
45static pe_node_t *
46parent_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
58static gboolean
59did_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
93static int
94order_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 /* Clone instances must have parents */
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 /* Apply rsc1's parental colocations */
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,
147 }
148
149 /* Apply rsc2's parental colocations */
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,
177 }
178
179 /* Current location score */
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 /* All location scores */
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
241out:
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
250gint
251sort_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 /* allocation order:
271 * - active instances
272 * - instances running on nodes with the least copies
273 * - active instances on nodes that can't support them or are to be fenced
274 * - failed instances
275 * - inactive instances
276 */
277
278 current_node1 = pe__find_active_on(resource1, &nnodes1, NULL);
279 current_node2 = pe__find_active_on(resource2, &nnodes2, NULL);
280
281 /* If both instances are running and at least one is multiply
282 * active, give precedence to the one that's running on fewer nodes.
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 /* Instance whose current location is available sorts first */
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 /* Higher-priority instance sorts first */
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 /* Active instance sorts first */
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 /* Instance whose current node can run resources sorts first */
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 /* Is the parent allowed to run on the instance's current node?
366 * Instance with parent allowed sorts first.
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 /* Does one node have more instances allocated?
384 * Instance whose current node has fewer instances sorts first.
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 /* Failed instance sorts first */
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 /* Default to lexicographic order by ID */
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
417static pe_node_t *
418can_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 /* make clang analyzer happy */
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
470static pe_node_t *
471allocate_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
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 /* Only include positive colocation preferences of dependent resources
491 * if not every node will get a copy of the clone
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
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;
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 /* what to do? we can't enforce per-node limits in this case */
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
539static void
540append_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
568void
569distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
570 int max, int per_host_max, pe_working_set_t * data_set);
571
572void
573distribute_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 /* count now tracks the number of clones currently allocated */
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 /* Pre-allocate as many instances as we can to their current location */
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)
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
677pe_node_t *
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
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
696 }
697
699
700 /* this information is used by sort_clone_instance() when deciding in which
701 * order to allocate clone instances
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,
722 }
723
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
734 pcmk__set_instance_roles(rsc, data_set);
735 }
736
738 pe_rsc_trace(rsc, "Done allocating %s", rsc->id);
739 return NULL;
740}
741
742static void
743clone_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,
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,
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,
800 *starting = TRUE;
801 }
802 }
803 }
804}
805
806static pe_action_t *
807find_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
855static void
856child_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; /* change to false to get the old behavior */
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 /* we have to maintain a consistent sorted child list when building order constraints */
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 /* child/child relative stop */
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 /* child/child relative start */
890 order_actions(last_start, start, pe_order_optional);
891 }
892 last_start = start;
893 }
894 }
895}
896
897void
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);
906 create_promotable_actions(rsc, data_set);
907 }
908}
909
910void
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 /* start */
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) {
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 /* stop */
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) {
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
972void
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);
985
989 }
990
991 if (clone_data->ordered) {
992 /* we have to maintain a consistent sorted child list when building order constraints */
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
1002 data_set);
1003 if (clone_data->ordered && last_rsc) {
1004 order_start_start(last_rsc, child_rsc, pe_order_optional);
1005 }
1006
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
1021bool
1022assign_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
1045gboolean
1046is_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 /* We only want instances that haven't failed */
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
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
1109void
1111 pcmk__colocation_t *constraint,
1112 pe_working_set_t *data_set)
1113{
1114 /* -- Never called --
1115 *
1116 * Instead we add the colocation constraints to the child and call from there
1117 */
1118 CRM_ASSERT(FALSE);
1119}
1120
1121void
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 /* only the LHS side needs to be labeled as interleave */
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 // TODO: Do we actually care about multiple RH copies sharing a LH copy anymore?
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
1217enum action_tasks
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 /* Find the action we're notifying about instead */
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
1261enum pe_action_flags
1263{
1264 GList *gIter = NULL;
1265 gboolean any_runnable = FALSE;
1266 gboolean check_runnable = TRUE;
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
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);
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);
1297 if (node == NULL) {
1299 }
1300 }
1301
1302 return flags;
1303}
1304
1305enum pe_action_flags
1307{
1308 return summary_action_flags(action, action->rsc->children, node);
1309}
1310
1311void
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
1327void
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 /* Now that the notifcations have been created we can expand the children */
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 /* The notifications are in the graph now, we can destroy the notify_data */
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// Check whether a resource or any of its children is known on node
1389static bool
1390rsc_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// Look for an instance of clone that is known on node
1418static pe_resource_t *
1419find_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// For unique clones, probe each instance separately
1432static gboolean
1433probe_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// For anonymous clones, only a single instance needs to be probed
1450static gboolean
1451probe_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 // First, check if we probed an instance on this node last time
1456 pe_resource_t *child = find_instance_on(rsc, node);
1457
1458 // Otherwise, check if we plan to start an instance on this node
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) { /* make clang analyzer happy */
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 // Otherwise, use the first clone instance
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
1483gboolean
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 /* exclusive discover is enabled and this node is not marked
1501 * as a node this resource should be discovered on
1502 *
1503 * remove the node from allowed_nodes so that the
1504 * notification contains only nodes that we might ever run
1505 * on
1506 */
1507 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1508
1509 /* Bit of a shortcut - might as well take it */
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
1523void
1525{
1526 char *name = NULL;
1527 clone_variant_data_t *clone_data = NULL;
1528
1529 get_clone_variant_data(clone_data, rsc);
1530
1532 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1533 free(name);
1534
1536 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1537 free(name);
1538
1540 crm_xml_add_int(xml, name, clone_data->clone_max);
1541 free(name);
1542
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)) {
1549 crm_xml_add_int(xml, name, clone_data->promoted_max);
1550 free(name);
1551
1553 crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1554 free(name);
1555
1556 /* @COMPAT Maintain backward compatibility with resource agents that
1557 * expect the old names (deprecated since 2.0.0).
1558 */
1560 crm_xml_add_int(xml, name, clone_data->promoted_max);
1561 free(name);
1562
1564 crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1565 free(name);
1566 }
1567}
uint64_t flags
Definition remote.c:3
char * crm_meta_name(const char *field)
Definition utils.c:511
gboolean crm_is_true(const char *s)
Definition strings.c:415
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
const char * task2text(enum action_tasks task)
Definition common.c:406
action_tasks
Definition common.h:62
@ no_action
Definition common.h:63
rsc_role_e
Possible roles that a resource can be in.
Definition common.h:92
@ RSC_ROLE_UNKNOWN
Definition common.h:93
#define RSC_PROMOTE
Definition crm.h:207
#define RSC_STARTED
Definition crm.h:202
#define RSC_STOPPED
Definition crm.h:205
#define RSC_START
Definition crm.h:201
#define INFINITY
Definition crm.h:99
#define RSC_STOP
Definition crm.h:204
#define RSC_DEMOTED
Definition crm.h:210
#define crm_info(fmt, args...)
Definition logging.h:353
#define crm_warn(fmt, args...)
Definition logging.h:351
#define crm_notice(fmt, args...)
Definition logging.h:352
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_trace(fmt, args...)
Definition logging.h:356
#define pcmk__config_err(fmt...)
#define XML_RSC_ATTR_PROMOTED_MAX
Definition msg_xml.h:230
#define XML_RSC_ATTR_NOTIFY
Definition msg_xml.h:235
#define XML_RSC_ATTR_INCARNATION_MAX
Definition msg_xml.h:226
#define PCMK_XE_PROMOTED_NODE_MAX_LEGACY
Definition msg_xml.h:44
#define XML_RSC_ATTR_PROMOTED_NODEMAX
Definition msg_xml.h:231
#define PCMK_XE_PROMOTED_MAX_LEGACY
Definition msg_xml.h:43
#define XML_RSC_ATTR_UNIQUE
Definition msg_xml.h:234
#define XML_RSC_ATTR_INTERLEAVE
Definition msg_xml.h:224
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition msg_xml.h:228
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition nvpair.c:432
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:324
char * name
Definition pcmk_fence.c:31
const char * action
Definition pcmk_fence.c:30
int rc
Definition pcmk_fence.c:35
bool assign_node(pe_resource_t *rsc, pe_node_t *node, gboolean force)
#define pe__clear_action_summary_flags(flags, action, flag)
void clone_rsc_colocation_lh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
pe_resource_t * find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current, pe_working_set_t *data_set)
gboolean is_child_compatible(pe_resource_t *child_rsc, pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
enum pe_action_flags clone_action_flags(pe_action_t *action, pe_node_t *node)
void clone_create_pseudo_actions(pe_resource_t *rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify, pe_working_set_t *data_set)
void clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
void clone_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
void clone_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes, int max, int per_host_max, pe_working_set_t *data_set)
void clone_append_meta(pe_resource_t *rsc, xmlNode *xml)
enum action_tasks clone_child_action(pe_action_t *action)
void clone_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
gboolean clone_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
pe_node_t * pcmk__clone_allocate(pe_resource_t *rsc, pe_node_t *prefer, pe_working_set_t *data_set)
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, pe_node_t *node)
void clone_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
void pcmk__add_promotion_scores(pe_resource_t *rsc)
void promotable_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
void native_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
void native_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
void create_promotable_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
void promotable_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
GHashTable * pcmk__native_merge_weights(pe_resource_t *rsc, const char *rhs, GHashTable *nodes, const char *attr, float factor, uint32_t flags)
pe_node_t * pcmk__set_instance_roles(pe_resource_t *rsc, pe_working_set_t *data_set)
void create_notifications(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
void free_notification_data(notify_data_t *n_data)
void collect_notification_data(pe_resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data)
notify_data_t * create_notification_boundaries(pe_resource_t *rsc, const char *action, pe_action_t *start, pe_action_t *end, pe_working_set_t *data_set)
void pcmk__create_notification_keys(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
GHashTable * pcmk__copy_node_table(GHashTable *nodes)
gboolean can_run_resources(const pe_node_t *node)
void native_deallocate(pe_resource_t *rsc)
pe_action_t * create_pseudo_resource_op(pe_resource_t *rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
pe_resource_t * find_compatible_child_by_node(pe_resource_t *local_child, pe_node_t *local_node, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
int copies_per_node(pe_resource_t *rsc)
GList * sort_nodes_by_weight(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
gboolean native_assign_node(pe_resource_t *rsc, pe_node_t *chosen, gboolean force)
#define order_start_start(rsc1, rsc2, type)
#define order_stop_stop(rsc1, rsc2, type)
int new_rsc_order(pe_resource_t *lh_rsc, const char *lh_task, pe_resource_t *rh_rsc, const char *rh_task, enum pe_ordering type, pe_working_set_t *data_set)
@ pe_weights_positive
@ pe_weights_rollback
#define pe_rsc_notify
Definition pe_types.h:253
#define pe_rsc_block
Definition pe_types.h:250
#define pe_rsc_managed
Definition pe_types.h:249
@ pe_order_implies_first_printed
Definition pe_types.h:513
@ pe_order_implies_then_printed
Definition pe_types.h:514
@ pe_order_optional
Definition pe_types.h:486
@ pe_order_runnable_left
Definition pe_types.h:496
#define pe_rsc_provisional
Definition pe_types.h:258
#define pe_rsc_unique
Definition pe_types.h:254
#define pe_rsc_allocating
Definition pe_types.h:259
#define pe_rsc_orphan
Definition pe_types.h:248
@ pe_discover_exclusive
Definition pe_types.h:480
#define pe_flag_show_scores
Definition pe_types.h:133
pe_action_flags
Definition pe_types.h:291
@ pe_action_optional
Definition pe_types.h:294
@ pe_action_runnable
Definition pe_types.h:293
@ pe_action_pseudo
Definition pe_types.h:292
@ pe_action_migrate_runnable
Definition pe_types.h:299
@ pe_group
Definition pe_types.h:38
@ pe_native
Definition pe_types.h:37
#define pe_rsc_failed
Definition pe_types.h:267
#define pe_rsc_promotable
Definition pe_types.h:256
GList * pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
Definition utils.c:1546
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition internal.h:353
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition utils.c:161
pe_node_t * pe__find_active_on(const pe_resource_t *rsc, unsigned int *count_all, unsigned int *count_clean)
Definition complex.c:999
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition utils.c:1428
bool is_set_recursive(pe_resource_t *rsc, long long flag, bool any)
Definition clone.c:397
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition internal.h:53
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:19
#define pe_warn(fmt...)
Definition internal.h:27
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition utils.c:1405
void common_update_score(pe_resource_t *rsc, const char *id, int score)
Definition complex.c:864
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition utils.c:1808
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:20
void resource_location(pe_resource_t *rsc, pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition utils.c:1594
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:47
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:68
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition utils.c:142
#define pe_err(fmt...)
Definition internal.h:22
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:59
#define CRM_ASSERT(expr)
Definition results.h:42
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:610
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:955
@ pcmk__str_casei
pe_resource_t * rsc_lh
const char * node_attribute
pe_resource_t * rsc_rh
char * uuid
Definition pe_types.h:416
int weight
Definition pe_types.h:241
int rsc_discover_mode
Definition pe_types.h:245
int count
Definition pe_types.h:243
struct pe_node_shared_s * details
Definition pe_types.h:244
const char * id
Definition pe_types.h:208
const char * uname
Definition pe_types.h:209
GList * running_on
Definition pe_types.h:367
GList * actions
Definition pe_types.h:360
enum pe_obj_types variant
Definition pe_types.h:331
GHashTable * meta
Definition pe_types.h:374
GList * rsc_cons
Definition pe_types.h:358
GList * rsc_cons_lhs
Definition pe_types.h:357
GList * children
Definition pe_types.h:378
gboolean exclusive_discover
Definition pe_types.h:353
GHashTable * known_on
Definition pe_types.h:368
GHashTable * allowed_nodes
Definition pe_types.h:369
pe_node_t * allocated_to
Definition pe_types.h:364
unsigned long long flags
Definition pe_types.h:349
pe_resource_t * parent
Definition pe_types.h:329
resource_alloc_functions_t * cmds
Definition pe_types.h:334
resource_object_functions_t * fns
Definition pe_types.h:333
unsigned long long flags
Definition pe_types.h:146
void(* rsc_location)(pe_resource_t *, pe__location_t *)
void(* rsc_colocation_lh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
void(* rsc_colocation_rh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
GHashTable *(* merge_weights)(pe_resource_t *, const char *, GHashTable *, const char *, float, enum pe_weights)
void(* expand)(pe_resource_t *, pe_working_set_t *)
pe_node_t *(* allocate)(pe_resource_t *, pe_node_t *, pe_working_set_t *)
gboolean(* create_probe)(pe_resource_t *, pe_node_t *, pe_action_t *, gboolean, pe_working_set_t *)
void(* create_actions)(pe_resource_t *, pe_working_set_t *)
void(* internal_constraints)(pe_resource_t *, pe_working_set_t *)
enum pe_action_flags(* action_flags)(pe_action_t *, pe_node_t *)
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition pe_types.h:54
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition pe_types.h:53