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