pacemaker 2.1.5-a3f44794f94
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
20static void append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all);
21
22static pe_node_t *
23can_run_instance(pe_resource_t * rsc, pe_node_t * node, int limit)
24{
25 pe_node_t *local_node = NULL;
26
27 if (node == NULL && rsc->allowed_nodes) {
28 GHashTableIter iter;
29 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
30 while (g_hash_table_iter_next(&iter, NULL, (void **)&local_node)) {
31 can_run_instance(rsc, local_node, limit);
32 }
33 return NULL;
34 }
35
36 if (!node) {
37 /* make clang analyzer happy */
38 goto bail;
39
40 } else if (!pcmk__node_available(node, false, false)) {
41 goto bail;
42
43 } else if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
44 goto bail;
45 }
46
47 local_node = pcmk__top_allowed_node(rsc, node);
48
49 if (local_node == NULL) {
50 crm_warn("%s cannot run on %s: node not allowed",
51 rsc->id, pe__node_name(node));
52 goto bail;
53
54 } else if (local_node->weight < 0) {
55 common_update_score(rsc, node->details->id, local_node->weight);
56 pe_rsc_trace(rsc, "%s cannot run on %s: Parent node weight doesn't allow it.",
57 rsc->id, pe__node_name(node));
58
59 } else if (local_node->count < limit) {
60 pe_rsc_trace(rsc, "%s can run on %s (already running %d)",
61 rsc->id, pe__node_name(node), local_node->count);
62 return local_node;
63
64 } else {
65 pe_rsc_trace(rsc, "%s cannot run on %s: node full (%d >= %d)",
66 rsc->id, pe__node_name(node), local_node->count, limit);
67 }
68
69 bail:
70 if (node) {
72 }
73 return NULL;
74}
75
76static pe_node_t *
77allocate_instance(pe_resource_t *rsc, pe_node_t *prefer, gboolean all_coloc,
78 int limit, pe_working_set_t *data_set)
79{
80 pe_node_t *chosen = NULL;
81 GHashTable *backup = NULL;
82
83 CRM_ASSERT(rsc);
84 pe_rsc_trace(rsc, "Checking allocation of %s (preferring %s, using %s parent colocations)",
85 rsc->id, (prefer? prefer->details->uname: "none"),
86 (all_coloc? "all" : "some"));
87
89 return rsc->fns->location(rsc, NULL, FALSE);
90
91 } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
92 pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
93 return NULL;
94 }
95
96 /* Only include positive colocation preferences of dependent resources
97 * if not every node will get a copy of the clone
98 */
99 append_parent_colocation(rsc->parent, rsc, all_coloc);
100
101 if (prefer) {
102 pe_node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
103
104 if (local_prefer == NULL || local_prefer->weight < 0) {
105 pe_rsc_trace(rsc, "Not pre-allocating %s to %s - unavailable", rsc->id,
106 pe__node_name(prefer));
107 return NULL;
108 }
109 }
110
111 can_run_instance(rsc, NULL, limit);
112
114 pe_rsc_trace(rsc, "Allocating instance %s", rsc->id);
115 chosen = rsc->cmds->assign(rsc, prefer);
116 if (chosen && prefer && (chosen->details != prefer->details)) {
117 crm_info("Not pre-allocating %s to %s because %s is better",
118 rsc->id, pe__node_name(prefer), pe__node_name(chosen));
119 g_hash_table_destroy(rsc->allowed_nodes);
120 rsc->allowed_nodes = backup;
122 chosen = NULL;
123 backup = NULL;
124 }
125 if (chosen) {
126 pe_node_t *local_node = pcmk__top_allowed_node(rsc, chosen);
127
128 if (local_node) {
129 local_node->count++;
130
131 } else if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
132 /* what to do? we can't enforce per-node limits in this case */
133 pcmk__config_err("%s not found in %s (list of %d)",
134 chosen->details->id, rsc->parent->id,
135 g_hash_table_size(rsc->parent->allowed_nodes));
136 }
137 }
138
139 if(backup) {
140 g_hash_table_destroy(backup);
141 }
142 return chosen;
143}
144
145static void
146append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all)
147{
148
149 GList *gIter = NULL;
150
151 gIter = rsc->rsc_cons;
152 for (; gIter != NULL; gIter = gIter->next) {
153 pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
154
155 if (all || cons->score < 0 || cons->score == INFINITY) {
156 pcmk__add_this_with(child, cons);
157 }
158 }
159
160 gIter = rsc->rsc_cons_lhs;
161 for (; gIter != NULL; gIter = gIter->next) {
162 pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
163
164 if (!pcmk__colocation_has_influence(cons, child)) {
165 continue;
166 }
167 if (all || cons->score < 0) {
168 pcmk__add_with_this(child, cons);
169 }
170 }
171}
172
173
174void
175distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
176 int max, int per_host_max, pe_working_set_t * data_set);
177
178void
179distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
180 int max, int per_host_max, pe_working_set_t * data_set)
181{
182 int loop_max = 0;
183 int allocated = 0;
184 int available_nodes = 0;
185 bool all_coloc = false;
186
187 /* count now tracks the number of clones currently allocated */
188 for(GList *nIter = nodes; nIter != NULL; nIter = nIter->next) {
189 pe_node_t *node = nIter->data;
190
191 node->count = 0;
192 if (pcmk__node_available(node, false, false)) {
193 available_nodes++;
194 }
195 }
196
197 all_coloc = (max < available_nodes) ? true : false;
198
199 if(available_nodes) {
200 loop_max = max / available_nodes;
201 }
202 if (loop_max < 1) {
203 loop_max = 1;
204 }
205
206 pe_rsc_debug(rsc, "Allocating up to %d %s instances to a possible %d nodes (at most %d per host, %d optimal)",
207 max, rsc->id, available_nodes, per_host_max, loop_max);
208
209 /* Pre-allocate as many instances as we can to their current location */
210 for (GList *gIter = children; gIter != NULL && allocated < max; gIter = gIter->next) {
211 pe_resource_t *child = (pe_resource_t *) gIter->data;
212 pe_node_t *child_node = NULL;
213 pe_node_t *local_node = NULL;
214
215 if ((child->running_on == NULL)
217 || pcmk_is_set(child->flags, pe_rsc_failed)) {
218
219 continue;
220 }
221
222 child_node = pe__current_node(child);
223 local_node = pcmk__top_allowed_node(child, child_node);
224
225 pe_rsc_trace(rsc,
226 "Checking pre-allocation of %s to %s (%d remaining of %d)",
227 child->id, pe__node_name(child_node), max - allocated,
228 max);
229
230 if (!pcmk__node_available(child_node, true, false)) {
231 pe_rsc_trace(rsc, "Not pre-allocating because %s can not run %s",
232 pe__node_name(child_node), child->id);
233 continue;
234 }
235
236 if ((local_node != NULL) && (local_node->count >= loop_max)) {
237 pe_rsc_trace(rsc,
238 "Not pre-allocating because %s already allocated "
239 "optimal instances", pe__node_name(child_node));
240 continue;
241 }
242
243 if (allocate_instance(child, child_node, all_coloc, per_host_max,
244 data_set)) {
245 pe_rsc_trace(rsc, "Pre-allocated %s to %s", child->id,
246 pe__node_name(child_node));
247 allocated++;
248 }
249 }
250
251 pe_rsc_trace(rsc, "Done pre-allocating (%d of %d)", allocated, max);
252
253 for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
254 pe_resource_t *child = (pe_resource_t *) gIter->data;
255
256 if (child->running_on != NULL) {
257 pe_node_t *child_node = pe__current_node(child);
258 pe_node_t *local_node = pcmk__top_allowed_node(child, child_node);
259
260 if (local_node == NULL) {
261 crm_err("%s is running on %s which isn't allowed",
262 child->id, pe__node_name(child_node));
263 }
264 }
265
266 if (!pcmk_is_set(child->flags, pe_rsc_provisional)) {
267 } else if (allocated >= max) {
268 pe_rsc_debug(rsc, "Child %s not allocated - limit reached %d %d", child->id, allocated, max);
269 resource_location(child, NULL, -INFINITY, "clone:limit_reached", data_set);
270 } else {
271 if (allocate_instance(child, NULL, all_coloc, per_host_max,
272 data_set)) {
273 allocated++;
274 }
275 }
276 }
277
278 pe_rsc_debug(rsc, "Allocated %d %s instances of a possible %d",
279 allocated, rsc->id, max);
280}
281
291pe_node_t *
293{
294 GList *nodes = NULL;
295 clone_variant_data_t *clone_data = NULL;
296
297 get_clone_variant_data(clone_data, rsc);
298
300 return NULL;
301
302 } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
303 pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
304 return NULL;
305 }
306
309 }
310
312
313 /* This information is used by pcmk__cmp_instance() when deciding the order
314 * in which to assign clone instances to nodes.
315 */
316 for (GList *gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
317 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
318
319 pe_rsc_trace(rsc, "%s: Allocating %s first",
320 rsc->id, constraint->primary->id);
321 constraint->primary->cmds->assign(constraint->primary, prefer);
322 }
323
324 for (GList *gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
325 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
326
327 if (pcmk__colocation_has_influence(constraint, NULL)) {
328 pe_resource_t *dependent = constraint->dependent;
329 const char *attr = constraint->node_attribute;
330 const float factor = constraint->score / (float) INFINITY;
331 const uint32_t flags = pcmk__coloc_select_active
333
334 pcmk__add_colocated_node_scores(dependent, rsc->id,
335 &rsc->allowed_nodes, attr, factor,
336 flags);
337 }
338 }
339
341 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
342
343 nodes = g_hash_table_get_values(rsc->allowed_nodes);
344 nodes = pcmk__sort_nodes(nodes, NULL);
345 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance);
346 distribute_children(rsc, rsc->children, nodes, clone_data->clone_max,
347 clone_data->clone_node_max, rsc->cluster);
348 g_list_free(nodes);
349
352 }
353
355 pe_rsc_trace(rsc, "Done allocating %s", rsc->id);
356 return NULL;
357}
358
359static void
360clone_update_pseudo_status(pe_resource_t * rsc, gboolean * stopping, gboolean * starting,
361 gboolean * active)
362{
363 GList *gIter = NULL;
364
365 if (rsc->children) {
366
367 gIter = rsc->children;
368 for (; gIter != NULL; gIter = gIter->next) {
369 pe_resource_t *child = (pe_resource_t *) gIter->data;
370
371 clone_update_pseudo_status(child, stopping, starting, active);
372 }
373
374 return;
375 }
376
377 CRM_ASSERT(active != NULL);
378 CRM_ASSERT(starting != NULL);
379 CRM_ASSERT(stopping != NULL);
380
381 if (rsc->running_on) {
382 *active = TRUE;
383 }
384
385 gIter = rsc->actions;
386 for (; gIter != NULL; gIter = gIter->next) {
387 pe_action_t *action = (pe_action_t *) gIter->data;
388
389 if (*starting && *stopping) {
390 return;
391
392 } else if (pcmk_is_set(action->flags, pe_action_optional)) {
393 pe_rsc_trace(rsc, "Skipping optional: %s", action->uuid);
394 continue;
395
396 } else if (!pcmk_any_flags_set(action->flags,
398 pe_rsc_trace(rsc, "Skipping unrunnable: %s", action->uuid);
399 continue;
400
401 } else if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_casei)) {
402 pe_rsc_trace(rsc, "Stopping due to: %s", action->uuid);
403 *stopping = TRUE;
404
405 } else if (pcmk__str_eq(RSC_START, action->task, pcmk__str_casei)) {
406 if (!pcmk_is_set(action->flags, pe_action_runnable)) {
407 pe_rsc_trace(rsc, "Skipping pseudo-op: %s run=%d, pseudo=%d",
408 action->uuid,
411 } else {
412 pe_rsc_trace(rsc, "Starting due to: %s", action->uuid);
413 pe_rsc_trace(rsc, "%s run=%d, pseudo=%d",
414 action->uuid,
417 *starting = TRUE;
418 }
419 }
420 }
421}
422
423static pe_action_t *
424find_rsc_action(pe_resource_t *rsc, const char *task)
425{
426 pe_action_t *match = NULL;
427 GList *actions = pe__resource_actions(rsc, NULL, task, FALSE);
428
429 for (GList *item = actions; item != NULL; item = item->next) {
430 pe_action_t *op = (pe_action_t *) item->data;
431
433 if (match != NULL) {
434 // More than one match, don't return any
435 match = NULL;
436 break;
437 }
438 match = op;
439 }
440 }
441 g_list_free(actions);
442 return match;
443}
444
445static void
446child_ordering_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
447{
448 pe_action_t *stop = NULL;
449 pe_action_t *start = NULL;
450 pe_action_t *last_stop = NULL;
451 pe_action_t *last_start = NULL;
452 GList *gIter = NULL;
453
454 if (!pe__clone_is_ordered(rsc)) {
455 return;
456 }
457
458 /* we have to maintain a consistent sorted child list when building order constraints */
459 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
460
461 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
462 pe_resource_t *child = (pe_resource_t *) gIter->data;
463
464 stop = find_rsc_action(child, RSC_STOP);
465 if (stop) {
466 if (last_stop) {
467 /* child/child relative stop */
468 order_actions(stop, last_stop, pe_order_optional);
469 }
470 last_stop = stop;
471 }
472
473 start = find_rsc_action(child, RSC_START);
474 if (start) {
475 if (last_start) {
476 /* child/child relative start */
477 order_actions(last_start, start, pe_order_optional);
478 }
479 last_start = start;
480 }
481 }
482}
483
484void
486{
487 clone_variant_data_t *clone_data = NULL;
488
489 get_clone_variant_data(clone_data, rsc);
490
491 pe_rsc_debug(rsc, "Creating actions for clone %s", rsc->id);
492 clone_create_pseudo_actions(rsc, rsc->children, &clone_data->start_notify,
493 &clone_data->stop_notify);
494 child_ordering_constraints(rsc, rsc->cluster);
495
498 }
499}
500
501void
503 notify_data_t **start_notify,
504 notify_data_t **stop_notify)
505{
506 gboolean child_active = FALSE;
507 gboolean child_starting = FALSE;
508 gboolean child_stopping = FALSE;
509 gboolean allow_dependent_migrations = TRUE;
510
511 pe_action_t *stop = NULL;
512 pe_action_t *stopped = NULL;
513
514 pe_action_t *start = NULL;
515 pe_action_t *started = NULL;
516
517 pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
518
519 for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
520 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
521 gboolean starting = FALSE;
522 gboolean stopping = FALSE;
523
524 child_rsc->cmds->create_actions(child_rsc);
525 clone_update_pseudo_status(child_rsc, &stopping, &starting, &child_active);
526 if (stopping && starting) {
527 allow_dependent_migrations = FALSE;
528 }
529
530 child_stopping |= stopping;
531 child_starting |= starting;
532 }
533
534 /* start */
535 start = pe__new_rsc_pseudo_action(rsc, RSC_START, !child_starting, true);
536 started = pe__new_rsc_pseudo_action(rsc, RSC_STARTED, !child_starting,
537 false);
538 started->priority = INFINITY;
539
540 if (child_active || child_starting) {
542 }
543
544 if (start_notify != NULL && *start_notify == NULL) {
545 *start_notify = pe__clone_notif_pseudo_ops(rsc, RSC_START, start,
546 started);
547 }
548
549 /* stop */
550 stop = pe__new_rsc_pseudo_action(rsc, RSC_STOP, !child_stopping, true);
551 stopped = pe__new_rsc_pseudo_action(rsc, RSC_STOPPED, !child_stopping,
552 true);
553 stopped->priority = INFINITY;
554 if (allow_dependent_migrations) {
556 }
557
558 if (stop_notify != NULL && *stop_notify == NULL) {
559 *stop_notify = pe__clone_notif_pseudo_ops(rsc, RSC_STOP, stop, stopped);
560
561 if (start_notify && *start_notify && *stop_notify) {
562 order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
563 }
564 }
565}
566
567void
569{
570 pe_resource_t *last_rsc = NULL;
571 GList *gIter;
572 bool ordered = pe__clone_is_ordered(rsc);
573
574 pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
581
587 }
588
589 if (ordered) {
590 /* we have to maintain a consistent sorted child list when building order constraints */
591 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
592 }
593 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
594 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
595
596 child_rsc->cmds->internal_constraints(child_rsc);
597
598 pcmk__order_starts(rsc, child_rsc,
602 if (ordered && (last_rsc != NULL)) {
603 pcmk__order_starts(last_rsc, child_rsc, pe_order_optional);
604 }
605
609 if (ordered && (last_rsc != NULL)) {
610 pcmk__order_stops(child_rsc, last_rsc, pe_order_optional);
611 }
612
613 last_rsc = child_rsc;
614 }
617 }
618}
619
620gboolean
621is_child_compatible(const pe_resource_t *child_rsc, const pe_node_t *local_node,
622 enum rsc_role_e filter, gboolean current)
623{
624 pe_node_t *node = NULL;
625 enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
626
627 CRM_CHECK(child_rsc && local_node, return FALSE);
628 if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
629 /* We only want instances that haven't failed */
630 node = child_rsc->fns->location(child_rsc, NULL, current);
631 }
632
633 if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
634 crm_trace("Filtered %s", child_rsc->id);
635 return FALSE;
636 }
637
638 if (node && (node->details == local_node->details)) {
639 return TRUE;
640
641 } else if (node) {
642 crm_trace("%s - %s vs %s", child_rsc->id, pe__node_name(node),
643 pe__node_name(local_node));
644
645 } else {
646 crm_trace("%s - not allocated %d", child_rsc->id, current);
647 }
648 return FALSE;
649}
650
653 const pe_resource_t *rsc, enum rsc_role_e filter,
654 gboolean current)
655{
656 pe_resource_t *pair = NULL;
657 GList *gIter = NULL;
658 GList *scratch = NULL;
659 pe_node_t *local_node = NULL;
660
661 local_node = local_child->fns->location(local_child, NULL, current);
662 if (local_node) {
663 return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
664 }
665
666 scratch = g_hash_table_get_values(local_child->allowed_nodes);
667 scratch = pcmk__sort_nodes(scratch, NULL);
668
669 gIter = scratch;
670 for (; gIter != NULL; gIter = gIter->next) {
671 pe_node_t *node = (pe_node_t *) gIter->data;
672
673 pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
674 if (pair) {
675 goto done;
676 }
677 }
678
679 pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
680 done:
681 g_list_free(scratch);
682 return pair;
683}
684
698void
700 const pe_resource_t *primary,
701 const pcmk__colocation_t *colocation,
702 bool for_dependent)
703{
704 GList *gIter = NULL;
705 gboolean do_interleave = FALSE;
706 const char *interleave_s = NULL;
707
708 /* This should never be called for the clone itself as a dependent. Instead,
709 * we add its colocation constraints to its instances and call the
710 * apply_coloc_score() for the instances as dependents.
711 */
712 CRM_ASSERT(!for_dependent);
713
714 CRM_CHECK((colocation != NULL) && (dependent != NULL) && (primary != NULL),
715 return);
716 CRM_CHECK(dependent->variant == pe_native, return);
717
718 pe_rsc_trace(primary, "Processing constraint %s: %s -> %s %d",
719 colocation->id, dependent->id, primary->id, colocation->score);
720
721 if (pcmk_is_set(primary->flags, pe_rsc_promotable)) {
722 if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
723 // We haven't placed the primary yet, so we can't apply colocation
724 pe_rsc_trace(primary, "%s is still provisional", primary->id);
725 return;
726
727 } else if (colocation->primary_role == RSC_ROLE_UNKNOWN) {
728 // This isn't a role-specfic colocation, so handle normally
729 pe_rsc_trace(primary, "Handling %s as a clone colocation",
730 colocation->id);
731
732 } else if (pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
733 // We're placing the dependent
735 colocation);
736 return;
737
738 } else if (colocation->dependent_role == RSC_ROLE_PROMOTED) {
739 // We're choosing roles for the dependent
741 colocation);
742 return;
743 }
744 }
745
746 // Only the dependent needs to be marked for interleave
747 interleave_s = g_hash_table_lookup(colocation->dependent->meta,
749 if (crm_is_true(interleave_s)
750 && (colocation->dependent->variant > pe_group)) {
751 /* @TODO Do we actually care about multiple primary copies sharing a
752 * dependent copy anymore?
753 */
754 if (copies_per_node(colocation->dependent) != copies_per_node(colocation->primary)) {
755 pcmk__config_err("Cannot interleave %s and %s because they do not "
756 "support the same number of instances per node",
757 colocation->dependent->id,
758 colocation->primary->id);
759
760 } else {
761 do_interleave = TRUE;
762 }
763 }
764
765 if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
766 pe_rsc_trace(primary, "%s is still provisional", primary->id);
767 return;
768
769 } else if (do_interleave) {
770 pe_resource_t *primary_instance = NULL;
771
772 primary_instance = find_compatible_child(dependent, primary,
773 RSC_ROLE_UNKNOWN, FALSE);
774 if (primary_instance != NULL) {
775 pe_rsc_debug(primary, "Pairing %s with %s",
776 dependent->id, primary_instance->id);
777 dependent->cmds->apply_coloc_score(dependent, primary_instance,
778 colocation, true);
779
780 } else if (colocation->score >= INFINITY) {
781 crm_notice("Cannot pair %s with instance of %s",
782 dependent->id, primary->id);
783 pcmk__assign_resource(dependent, NULL, true);
784
785 } else {
786 pe_rsc_debug(primary, "Cannot pair %s with instance of %s",
787 dependent->id, primary->id);
788 }
789
790 return;
791
792 } else if (colocation->score >= INFINITY) {
793 GList *affected_nodes = NULL;
794
795 gIter = primary->children;
796 for (; gIter != NULL; gIter = gIter->next) {
797 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
798 pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
799
800 if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
801 pe_rsc_trace(primary, "Allowing %s: %s %d",
802 colocation->id, pe__node_name(chosen),
803 chosen->weight);
804 affected_nodes = g_list_prepend(affected_nodes, chosen);
805 }
806 }
807
808 node_list_exclude(dependent->allowed_nodes, affected_nodes, FALSE);
809 g_list_free(affected_nodes);
810 return;
811 }
812
813 gIter = primary->children;
814 for (; gIter != NULL; gIter = gIter->next) {
815 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
816
817 child_rsc->cmds->apply_coloc_score(dependent, child_rsc, colocation,
818 false);
819 }
820}
821
822enum action_tasks
824{
826 pe_resource_t *child = (pe_resource_t *) action->rsc->children->data;
827
828 if (pcmk__strcase_any_of(action->task, "notify", "notified", NULL)) {
829
830 /* Find the action we're notifying about instead */
831
832 int stop = 0;
833 char *key = action->uuid;
834 int lpc = strlen(key);
835
836 for (; lpc > 0; lpc--) {
837 if (key[lpc] == '_' && stop == 0) {
838 stop = lpc;
839
840 } else if (key[lpc] == '_') {
841 char *task_mutable = NULL;
842
843 lpc++;
844 task_mutable = strdup(key + lpc);
845 task_mutable[stop - lpc] = 0;
846
847 crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
848 result = get_complex_task(child, task_mutable, TRUE);
849 free(task_mutable);
850 break;
851 }
852 }
853
854 } else {
855 result = get_complex_task(child, action->task, TRUE);
856 }
857 return result;
858}
859
860#define pe__clear_action_summary_flags(flags, action, flag) do { \
861 flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
862 "Action summary", action->rsc->id, \
863 flags, flag, #flag); \
864 } while (0)
865
868 const pe_node_t *node)
869{
870 GList *gIter = NULL;
871 gboolean any_runnable = FALSE;
872 gboolean check_runnable = TRUE;
875 const char *task_s = task2text(task);
876
877 for (gIter = children; gIter != NULL; gIter = gIter->next) {
878 pe_action_t *child_action = NULL;
879 pe_resource_t *child = (pe_resource_t *) gIter->data;
880
881 child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
882 pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
883 pe__node_name(node), child_action?child_action->uuid:"NA");
884 if (child_action) {
885 enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
886
888 && !pcmk_is_set(child_flags, pe_action_optional)) {
889 pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
890 child_action->uuid);
893 }
894 if (pcmk_is_set(child_flags, pe_action_runnable)) {
895 any_runnable = TRUE;
896 }
897 }
898 }
899
900 if (check_runnable && any_runnable == FALSE) {
901 pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
903 if (node == NULL) {
905 }
906 }
907
908 return flags;
909}
910
913{
914 return summary_action_flags(action, action->rsc->children, node);
915}
916
917void
919{
920 GList *gIter = rsc->children;
921
922 pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
923
924 pcmk__apply_location(rsc, constraint);
925
926 for (; gIter != NULL; gIter = gIter->next) {
927 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
928
929 child_rsc->cmds->apply_location(child_rsc, constraint);
930 }
931}
932
939void
941{
942 GList *gIter = NULL;
943 clone_variant_data_t *clone_data = NULL;
944
945 get_clone_variant_data(clone_data, rsc);
946
947 g_list_foreach(rsc->actions, (GFunc) rsc->cmds->action_flags, NULL);
948
949 pe__create_notifications(rsc, clone_data->start_notify);
950 pe__create_notifications(rsc, clone_data->stop_notify);
951 pe__create_notifications(rsc, clone_data->promote_notify);
952 pe__create_notifications(rsc, clone_data->demote_notify);
953
954 /* Now that the notifcations have been created we can expand the children */
955
956 gIter = rsc->children;
957 for (; gIter != NULL; gIter = gIter->next) {
958 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
959
960 child_rsc->cmds->add_actions_to_graph(child_rsc);
961 }
962
964
965 /* The notifications are in the graph now, we can destroy the notify_data */
966 pe__free_notification_data(clone_data->demote_notify);
967 clone_data->demote_notify = NULL;
968 pe__free_notification_data(clone_data->stop_notify);
969 clone_data->stop_notify = NULL;
970 pe__free_notification_data(clone_data->start_notify);
971 clone_data->start_notify = NULL;
972 pe__free_notification_data(clone_data->promote_notify);
973 clone_data->promote_notify = NULL;
974}
975
976// Check whether a resource or any of its children is known on node
977static bool
978rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
979{
980 if (rsc->children) {
981 for (GList *child_iter = rsc->children; child_iter != NULL;
982 child_iter = child_iter->next) {
983
984 pe_resource_t *child = (pe_resource_t *) child_iter->data;
985
986 if (rsc_known_on(child, node)) {
987 return TRUE;
988 }
989 }
990
991 } else if (rsc->known_on) {
992 GHashTableIter iter;
993 pe_node_t *known_node = NULL;
994
995 g_hash_table_iter_init(&iter, rsc->known_on);
996 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
997 if (node->details == known_node->details) {
998 return TRUE;
999 }
1000 }
1001 }
1002 return FALSE;
1003}
1004
1005// Look for an instance of clone that is known on node
1006static pe_resource_t *
1007find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
1008{
1009 for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
1010 pe_resource_t *child = (pe_resource_t *) gIter->data;
1011
1012 if (rsc_known_on(child, node)) {
1013 return child;
1014 }
1015 }
1016 return NULL;
1017}
1018
1019// For anonymous clones, only a single instance needs to be probed
1020static bool
1021probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
1023{
1024 // First, check if we probed an instance on this node last time
1025 pe_resource_t *child = find_instance_on(rsc, node);
1026
1027 // Otherwise, check if we plan to start an instance on this node
1028 if (child == NULL) {
1029 for (GList *child_iter = rsc->children; child_iter && !child;
1030 child_iter = child_iter->next) {
1031
1032 pe_node_t *local_node = NULL;
1033 pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
1034
1035 if (child_rsc) { /* make clang analyzer happy */
1036 local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1037 if (local_node && (local_node->details == node->details)) {
1038 child = child_rsc;
1039 }
1040 }
1041 }
1042 }
1043
1044 // Otherwise, use the first clone instance
1045 if (child == NULL) {
1046 child = rsc->children->data;
1047 }
1048 CRM_ASSERT(child);
1049 return child->cmds->create_probe(child, node);
1050}
1051
1062bool
1064{
1065 CRM_ASSERT(rsc);
1066
1067 rsc->children = g_list_sort(rsc->children, pcmk__cmp_instance_number);
1068 if (rsc->children == NULL) {
1069 pe_warn("Clone %s has no children", rsc->id);
1070 return false;
1071 }
1072
1073 if (rsc->exclusive_discover) {
1074 pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1075 if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1076 /* exclusive discover is enabled and this node is not marked
1077 * as a node this resource should be discovered on
1078 *
1079 * remove the node from allowed_nodes so that the
1080 * notification contains only nodes that we might ever run
1081 * on
1082 */
1083 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1084
1085 /* Bit of a shortcut - might as well take it */
1086 return false;
1087 }
1088 }
1089
1090 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1091 return pcmk__probe_resource_list(rsc->children, node);
1092 } else {
1093 return probe_anonymous_clone(rsc, node, rsc->cluster);
1094 }
1095}
1096
1097void
1099{
1100 char *name = NULL;
1101 clone_variant_data_t *clone_data = NULL;
1102
1103 get_clone_variant_data(clone_data, rsc);
1104
1106 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1107 free(name);
1108
1110 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1111 free(name);
1112
1114 crm_xml_add_int(xml, name, clone_data->clone_max);
1115 free(name);
1116
1118 crm_xml_add_int(xml, name, clone_data->clone_node_max);
1119 free(name);
1120
1121 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1122 int promoted_max = pe__clone_promoted_max(rsc);
1123 int promoted_node_max = pe__clone_promoted_node_max(rsc);
1124
1126 crm_xml_add_int(xml, name, promoted_max);
1127 free(name);
1128
1130 crm_xml_add_int(xml, name, promoted_node_max);
1131 free(name);
1132
1133 /* @COMPAT Maintain backward compatibility with resource agents that
1134 * expect the old names (deprecated since 2.0.0).
1135 */
1137 crm_xml_add_int(xml, name, promoted_max);
1138 free(name);
1139
1141 crm_xml_add_int(xml, name, promoted_node_max);
1142 free(name);
1143 }
1144}
1145
1146// Clone implementation of resource_alloc_functions_t:add_utilization()
1147void
1149 const pe_resource_t *orig_rsc, GList *all_rscs,
1150 GHashTable *utilization)
1151{
1152 bool existing = false;
1153 pe_resource_t *child = NULL;
1154
1155 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
1156 return;
1157 }
1158
1159 // Look for any child already existing in the list
1160 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
1161 child = (pe_resource_t *) iter->data;
1162 if (g_list_find(all_rscs, child)) {
1163 existing = true; // Keep checking remaining children
1164 } else {
1165 // If this is a clone of a group, look for group's members
1166 for (GList *member_iter = child->children; member_iter != NULL;
1167 member_iter = member_iter->next) {
1168
1169 pe_resource_t *member = (pe_resource_t *) member_iter->data;
1170
1171 if (g_list_find(all_rscs, member) != NULL) {
1172 // Add *child's* utilization, not group member's
1173 child->cmds->add_utilization(child, orig_rsc, all_rscs,
1174 utilization);
1175 existing = true;
1176 break;
1177 }
1178 }
1179 }
1180 }
1181
1182 if (!existing && (rsc->children != NULL)) {
1183 // If nothing was found, still add first child's utilization
1184 child = (pe_resource_t *) rsc->children->data;
1185
1186 child->cmds->add_utilization(child, orig_rsc, all_rscs, utilization);
1187 }
1188}
1189
1190// Clone implementation of resource_alloc_functions_t:shutdown_lock()
1191void
1193{
1194 return; // Clones currently don't support shutdown locks
1195}
const char * name
Definition: cib.c:24
uint64_t flags
Definition: remote.c:3
char * crm_meta_name(const char *field)
Definition: utils.c:468
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:121
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_PROMOTED
Definition: common.h:97
@ RSC_ROLE_UNKNOWN
Definition: common.h:93
#define RSC_PROMOTE
Definition: crm.h:205
#define RSC_STARTED
Definition: crm.h:200
#define RSC_STOPPED
Definition: crm.h:203
#define RSC_START
Definition: crm.h:199
#define INFINITY
Definition: crm.h:99
#define RSC_STOP
Definition: crm.h:202
#define RSC_DEMOTED
Definition: crm.h:208
@ pcmk__coloc_select_active
@ pcmk__coloc_select_nonnegative
#define pcmk__order_starts(rsc1, rsc2, flags)
G_GNUC_INTERNAL void pcmk__set_instance_roles(pe_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__unassign_resource(pe_resource_t *rsc)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL gint pcmk__cmp_instance_number(gconstpointer a, gconstpointer b)
G_GNUC_INTERNAL void pcmk__add_promotion_scores(pe_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__order_promotable_instances(pe_resource_t *clone)
G_GNUC_INTERNAL void pcmk__add_this_with(pe_resource_t *rsc, pcmk__colocation_t *colocation)
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
G_GNUC_INTERNAL gint pcmk__cmp_instance(gconstpointer a, gconstpointer b)
G_GNUC_INTERNAL void pcmk__add_rsc_actions_to_graph(pe_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__update_dependent_with_promotable(const pe_resource_t *primary, pe_resource_t *dependent, const pcmk__colocation_t *colocation)
Update dependent for a colocation with a promotable clone.
G_GNUC_INTERNAL pe_node_t * pcmk__top_allowed_node(const pe_resource_t *rsc, const pe_node_t *node)
G_GNUC_INTERNAL bool pcmk__probe_resource_list(GList *rscs, pe_node_t *node)
G_GNUC_INTERNAL void pcmk__add_colocated_node_scores(pe_resource_t *rsc, const char *log_id, GHashTable **nodes, const char *attr, float factor, uint32_t flags)
G_GNUC_INTERNAL bool pcmk__assign_resource(pe_resource_t *rsc, pe_node_t *node, bool force)
G_GNUC_INTERNAL void pcmk__update_promotable_dependent_priority(const pe_resource_t *primary, pe_resource_t *dependent, const pcmk__colocation_t *colocation)
G_GNUC_INTERNAL void pcmk__create_promotable_actions(pe_resource_t *clone)
#define pcmk__order_stops(rsc1, rsc2, flags)
G_GNUC_INTERNAL void pcmk__apply_location(pe_resource_t *rsc, pe__location_t *constraint)
G_GNUC_INTERNAL void pcmk__add_with_this(pe_resource_t *rsc, pcmk__colocation_t *colocation)
G_GNUC_INTERNAL bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
G_GNUC_INTERNAL GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define crm_info(fmt, args...)
Definition: logging.h:362
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define pcmk__config_err(fmt...)
#define XML_RSC_ATTR_PROMOTED_MAX
Definition: msg_xml.h:233
#define XML_RSC_ATTR_NOTIFY
Definition: msg_xml.h:238
#define XML_RSC_ATTR_INCARNATION_MAX
Definition: msg_xml.h:229
#define XML_RSC_ATTR_PROMOTED_NODEMAX
Definition: msg_xml.h:234
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
Definition: msg_xml.h:50
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:237
#define XML_RSC_ATTR_INTERLEAVE
Definition: msg_xml.h:227
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:231
#define PCMK_XA_PROMOTED_MAX_LEGACY
Definition: msg_xml.h:49
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:419
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:30
pcmk__action_result_t result
Definition: pcmk_fence.c:35
enum pe_action_flags clone_action_flags(pe_action_t *action, const pe_node_t *node)
void pcmk__clone_shutdown_lock(pe_resource_t *rsc)
#define pe__clear_action_summary_flags(flags, action, flag)
void clone_create_actions(pe_resource_t *rsc)
void pcmk__clone_apply_coloc_score(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, const pe_node_t *node)
void clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
bool clone_create_probe(pe_resource_t *rsc, pe_node_t *node)
void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes, int max, int per_host_max, pe_working_set_t *data_set)
void pcmk__clone_add_utilization(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void clone_append_meta(pe_resource_t *rsc, xmlNode *xml)
enum action_tasks clone_child_action(pe_action_t *action)
void clone_create_pseudo_actions(pe_resource_t *rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify)
void clone_expand(pe_resource_t *rsc)
void clone_internal_constraints(pe_resource_t *rsc)
pe_node_t * pcmk__clone_allocate(pe_resource_t *rsc, const pe_node_t *prefer)
gboolean is_child_compatible(const pe_resource_t *child_rsc, const pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
pe_resource_t * find_compatible_child(const pe_resource_t *local_child, const pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
pe_resource_t * find_compatible_child_by_node(const pe_resource_t *local_child, const pe_node_t *local_node, const pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
int copies_per_node(pe_resource_t *rsc)
#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:508
@ pe_order_implies_then_printed
Definition: pe_types.h:509
@ pe_order_optional
Definition: pe_types.h:481
@ pe_order_runnable_left
Definition: pe_types.h:491
#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:475
#define pe_flag_show_scores
Definition: pe_types.h:134
pe_action_flags
Definition: pe_types.h:298
@ pe_action_optional
Definition: pe_types.h:301
@ pe_action_runnable
Definition: pe_types.h:300
@ pe_action_pseudo
Definition: pe_types.h:299
@ pe_action_migrate_runnable
Definition: pe_types.h:306
@ 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: pe_actions.c:1398
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:394
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:108
void pe__create_notifications(pe_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:928
bool is_set_recursive(const pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:496
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1296
bool pe__clone_is_ordered(pe_resource_t *clone)
Definition: clone.c:1216
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:46
pe_action_t * pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1647
#define pe_warn(fmt...)
Definition: internal.h:54
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: pe_actions.c:1262
void common_update_score(pe_resource_t *rsc, const char *id, int score)
Definition: complex.c:873
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:474
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
int pe__clone_promoted_max(pe_resource_t *clone)
Definition: clone.c:42
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:385
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
notify_data_t * pe__clone_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
Definition: pe_notif.c:428
void pe__free_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:945
int pe__clone_promoted_node_max(pe_resource_t *clone)
Definition: clone.c:59
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
#define CRM_ASSERT(expr)
Definition: results.h:42
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
@ pcmk__str_casei
pe_resource_t * primary
const char * node_attribute
pe_resource_t * dependent
char * uuid
Definition: pe_types.h:411
int priority
Definition: pe_types.h:404
enum pe_action_flags flags
Definition: pe_types.h:415
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:373
GList * actions
Definition: pe_types.h:366
enum pe_obj_types variant
Definition: pe_types.h:338
GHashTable * meta
Definition: pe_types.h:380
GList * rsc_cons
Definition: pe_types.h:364
GList * rsc_cons_lhs
Definition: pe_types.h:363
GList * children
Definition: pe_types.h:384
gboolean exclusive_discover
Definition: pe_types.h:359
GHashTable * known_on
Definition: pe_types.h:374
pe_working_set_t * cluster
Definition: pe_types.h:335
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
unsigned long long flags
Definition: pe_types.h:355
pe_resource_t * parent
Definition: pe_types.h:336
resource_alloc_functions_t * cmds
Definition: pe_types.h:341
resource_object_functions_t * fns
Definition: pe_types.h:340
unsigned long long flags
Definition: pe_types.h:153
void(* apply_location)(pe_resource_t *rsc, pe__location_t *location)
void(* apply_coloc_score)(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
bool(* create_probe)(pe_resource_t *rsc, pe_node_t *node)
void(* add_utilization)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void(* create_actions)(pe_resource_t *rsc)
enum pe_action_flags(* action_flags)(pe_action_t *action, const pe_node_t *node)
void(* add_actions_to_graph)(pe_resource_t *rsc)
void(* internal_constraints)(pe_resource_t *rsc)
pe_node_t *(* assign)(pe_resource_t *rsc, const pe_node_t *prefer)
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