This source file includes following definitions.
- can_run_instance
- allocate_instance
- append_parent_colocation
- distribute_children
- pcmk__clone_allocate
- clone_update_pseudo_status
- find_rsc_action
- child_ordering_constraints
- clone_create_actions
- clone_create_pseudo_actions
- clone_internal_constraints
- is_child_compatible
- find_compatible_child
- pcmk__clone_apply_coloc_score
- clone_child_action
- summary_action_flags
- clone_action_flags
- clone_rsc_location
- clone_expand
- rsc_known_on
- find_instance_on
- probe_anonymous_clone
- clone_create_probe
- clone_append_meta
- pcmk__clone_add_utilization
- pcmk__clone_shutdown_lock
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/msg_xml.h>
13 #include <pacemaker-internal.h>
14
15 #include "libpacemaker_private.h"
16
17 #define VARIANT_CLONE 1
18 #include <lib/pengine/variant.h>
19
20 static void append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all);
21
22 static pe_node_t *
23 can_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
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) {
71 common_update_score(rsc, node->details->id, -INFINITY);
72 }
73 return NULL;
74 }
75
76 static pe_node_t *
77 allocate_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
88 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
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
97
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
113 backup = pcmk__copy_node_table(rsc->allowed_nodes);
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;
121 pcmk__unassign_resource(rsc);
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
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
145 static void
146 append_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
174 void
175 distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
176 int max, int per_host_max, pe_working_set_t * data_set);
177
178 void
179 distribute_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
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
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)
216 || !pcmk_is_set(child->flags, pe_rsc_provisional)
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
282
283
284
285
286
287
288
289
290
291 pe_node_t *
292 pcmk__clone_allocate(pe_resource_t *rsc, const pe_node_t *prefer)
293 {
294 GList *nodes = NULL;
295 clone_variant_data_t *clone_data = NULL;
296
297 get_clone_variant_data(clone_data, rsc);
298
299 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
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
307 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
308 pcmk__add_promotion_scores(rsc);
309 }
310
311 pe__set_resource_flags(rsc, pe_rsc_allocating);
312
313
314
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
332 |pcmk__coloc_select_nonnegative;
333
334 pcmk__add_colocated_node_scores(dependent, rsc->id,
335 &rsc->allowed_nodes, attr, factor,
336 flags);
337 }
338 }
339
340 pe__show_node_weights(!pcmk_is_set(rsc->cluster->flags, pe_flag_show_scores),
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
350 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
351 pcmk__set_instance_roles(rsc);
352 }
353
354 pe__clear_resource_flags(rsc, pe_rsc_provisional|pe_rsc_allocating);
355 pe_rsc_trace(rsc, "Done allocating %s", rsc->id);
356 return NULL;
357 }
358
359 static void
360 clone_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,
397 pe_action_pseudo|pe_action_runnable)) {
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,
409 pcmk_is_set(action->flags, pe_action_runnable),
410 pcmk_is_set(action->flags, pe_action_pseudo));
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,
415 pcmk_is_set(action->flags, pe_action_runnable),
416 pcmk_is_set(action->flags, pe_action_pseudo));
417 *starting = TRUE;
418 }
419 }
420 }
421 }
422
423 static pe_action_t *
424 find_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
432 if (!pcmk_is_set(op->flags, pe_action_optional)) {
433 if (match != NULL) {
434
435 match = NULL;
436 break;
437 }
438 match = op;
439 }
440 }
441 g_list_free(actions);
442 return match;
443 }
444
445 static void
446 child_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
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
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
477 order_actions(last_start, start, pe_order_optional);
478 }
479 last_start = start;
480 }
481 }
482 }
483
484 void
485 clone_create_actions(pe_resource_t *rsc)
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
496 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
497 pcmk__create_promotable_actions(rsc);
498 }
499 }
500
501 void
502 clone_create_pseudo_actions(pe_resource_t *rsc, GList *children,
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
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) {
541 pe__set_action_flags(started, pe_action_runnable);
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
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) {
555 pe__set_action_flags(stop, pe_action_migrate_runnable);
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
567 void
568 clone_internal_constraints(pe_resource_t *rsc)
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);
575 pcmk__order_resource_actions(rsc, RSC_STOPPED, rsc, RSC_START,
576 pe_order_optional);
577 pcmk__order_resource_actions(rsc, RSC_START, rsc, RSC_STARTED,
578 pe_order_runnable_left);
579 pcmk__order_resource_actions(rsc, RSC_STOP, rsc, RSC_STOPPED,
580 pe_order_runnable_left);
581
582 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
583 pcmk__order_resource_actions(rsc, RSC_DEMOTED, rsc, RSC_STOP,
584 pe_order_optional);
585 pcmk__order_resource_actions(rsc, RSC_STARTED, rsc, RSC_PROMOTE,
586 pe_order_runnable_left);
587 }
588
589 if (ordered) {
590
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,
599 pe_order_runnable_left|pe_order_implies_first_printed);
600 pcmk__order_resource_actions(child_rsc, RSC_START, rsc, RSC_STARTED,
601 pe_order_implies_then_printed);
602 if (ordered && (last_rsc != NULL)) {
603 pcmk__order_starts(last_rsc, child_rsc, pe_order_optional);
604 }
605
606 pcmk__order_stops(rsc, child_rsc, pe_order_implies_first_printed);
607 pcmk__order_resource_actions(child_rsc, RSC_STOP, rsc, RSC_STOPPED,
608 pe_order_implies_then_printed);
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 }
615 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
616 pcmk__order_promotable_instances(rsc);
617 }
618 }
619
620 gboolean
621 is_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
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
651 pe_resource_t *
652 find_compatible_child(const pe_resource_t *local_child,
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
685
686
687
688
689
690
691
692
693
694
695
696
697
698 void
699 pcmk__clone_apply_coloc_score(pe_resource_t *dependent,
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
709
710
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
724 pe_rsc_trace(primary, "%s is still provisional", primary->id);
725 return;
726
727 } else if (colocation->primary_role == RSC_ROLE_UNKNOWN) {
728
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
734 pcmk__update_dependent_with_promotable(primary, dependent,
735 colocation);
736 return;
737
738 } else if (colocation->dependent_role == RSC_ROLE_PROMOTED) {
739
740 pcmk__update_promotable_dependent_priority(primary, dependent,
741 colocation);
742 return;
743 }
744 }
745
746
747 interleave_s = g_hash_table_lookup(colocation->dependent->meta,
748 XML_RSC_ATTR_INTERLEAVE);
749 if (crm_is_true(interleave_s)
750 && (colocation->dependent->variant > pe_group)) {
751
752
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
822 enum action_tasks
823 clone_child_action(pe_action_t * action)
824 {
825 enum action_tasks result = no_action;
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
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
866 enum pe_action_flags
867 summary_action_flags(pe_action_t *action, GList *children,
868 const pe_node_t *node)
869 {
870 GList *gIter = NULL;
871 gboolean any_runnable = FALSE;
872 gboolean check_runnable = TRUE;
873 enum action_tasks task = clone_child_action(action);
874 enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
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
887 if (pcmk_is_set(flags, pe_action_optional)
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);
891 pe__clear_action_summary_flags(flags, action, pe_action_optional);
892 pe__clear_action_flags(action, pe_action_optional);
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);
902 pe__clear_action_summary_flags(flags, action, pe_action_runnable);
903 if (node == NULL) {
904 pe__clear_action_flags(action, pe_action_runnable);
905 }
906 }
907
908 return flags;
909 }
910
911 enum pe_action_flags
912 clone_action_flags(pe_action_t *action, const pe_node_t *node)
913 {
914 return summary_action_flags(action, action->rsc->children, node);
915 }
916
917 void
918 clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
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
933
934
935
936
937
938
939 void
940 clone_expand(pe_resource_t *rsc)
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
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
963 pcmk__add_rsc_actions_to_graph(rsc);
964
965
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
977 static bool
978 rsc_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
1006 static pe_resource_t *
1007 find_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
1020 static bool
1021 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
1022 pe_working_set_t *data_set)
1023 {
1024
1025 pe_resource_t *child = find_instance_on(rsc, node);
1026
1027
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) {
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
1045 if (child == NULL) {
1046 child = rsc->children->data;
1047 }
1048 CRM_ASSERT(child);
1049 return child->cmds->create_probe(child, node);
1050 }
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062 bool
1063 clone_create_probe(pe_resource_t *rsc, pe_node_t *node)
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
1077
1078
1079
1080
1081
1082
1083 g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1084
1085
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
1097 void
1098 clone_append_meta(pe_resource_t * rsc, xmlNode * xml)
1099 {
1100 char *name = NULL;
1101 clone_variant_data_t *clone_data = NULL;
1102
1103 get_clone_variant_data(clone_data, rsc);
1104
1105 name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
1106 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1107 free(name);
1108
1109 name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
1110 crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1111 free(name);
1112
1113 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
1114 crm_xml_add_int(xml, name, clone_data->clone_max);
1115 free(name);
1116
1117 name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
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
1125 name = crm_meta_name(XML_RSC_ATTR_PROMOTED_MAX);
1126 crm_xml_add_int(xml, name, promoted_max);
1127 free(name);
1128
1129 name = crm_meta_name(XML_RSC_ATTR_PROMOTED_NODEMAX);
1130 crm_xml_add_int(xml, name, promoted_node_max);
1131 free(name);
1132
1133
1134
1135
1136 name = crm_meta_name(PCMK_XA_PROMOTED_MAX_LEGACY);
1137 crm_xml_add_int(xml, name, promoted_max);
1138 free(name);
1139
1140 name = crm_meta_name(PCMK_XA_PROMOTED_NODE_MAX_LEGACY);
1141 crm_xml_add_int(xml, name, promoted_node_max);
1142 free(name);
1143 }
1144 }
1145
1146
1147 void
1148 pcmk__clone_add_utilization(const pe_resource_t *rsc,
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
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;
1164 } else {
1165
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
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
1184 child = (pe_resource_t *) rsc->children->data;
1185
1186 child->cmds->add_utilization(child, orig_rsc, all_rscs, utilization);
1187 }
1188 }
1189
1190
1191 void
1192 pcmk__clone_shutdown_lock(pe_resource_t *rsc)
1193 {
1194 return;
1195 }