This source file includes following definitions.
- pcmk__clone_assign
- pcmk__clone_create_actions
- pcmk__clone_internal_constraints
- can_interleave
- pcmk__clone_apply_coloc_score
- pcmk__with_clone_colocations
- pcmk__clone_with_colocations
- pcmk__clone_action_flags
- pcmk__clone_apply_location
- call_action_flags
- pcmk__clone_add_actions_to_graph
- rsc_probed_on
- find_probed_instance_on
- probe_anonymous_clone
- pcmk__clone_create_probe
- pcmk__clone_add_graph_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/common/xml.h>
13 #include <pacemaker-internal.h>
14
15 #include "libpacemaker_private.h"
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 pcmk_node_t *
37 pcmk__clone_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer,
38 bool stop_if_fail)
39 {
40 GList *colocations = NULL;
41
42 pcmk__assert(pcmk__is_clone(rsc));
43
44 if (!pcmk_is_set(rsc->flags, pcmk__rsc_unassigned)) {
45 return NULL;
46 }
47
48
49 if (pcmk_is_set(rsc->flags, pcmk__rsc_assigning)) {
50 pcmk__rsc_debug(rsc, "Breaking assignment loop involving %s", rsc->id);
51 return NULL;
52 }
53 pcmk__set_rsc_flags(rsc, pcmk__rsc_assigning);
54
55
56 if (pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
57 pcmk__add_promotion_scores(rsc);
58 }
59
60
61 colocations = pcmk__this_with_colocations(rsc);
62 for (GList *iter = colocations; iter != NULL; iter = iter->next) {
63 pcmk__colocation_t *constraint = (pcmk__colocation_t *) iter->data;
64 pcmk_resource_t *primary = constraint->primary;
65
66 pcmk__rsc_trace(rsc, "%s: Assigning colocation %s primary %s first",
67 rsc->id, constraint->id, primary->id);
68 primary->priv->cmds->assign(primary, prefer, stop_if_fail);
69 }
70 g_list_free(colocations);
71
72
73 colocations = pcmk__with_this_colocations(rsc);
74 g_list_foreach(colocations, pcmk__add_dependent_scores, rsc);
75 g_list_free(colocations);
76
77 pe__show_node_scores(!pcmk_is_set(rsc->priv->scheduler->flags,
78 pcmk__sched_output_scores),
79 rsc, __func__, rsc->priv->allowed_nodes,
80 rsc->priv->scheduler);
81
82 rsc->priv->children = g_list_sort(rsc->priv->children, pcmk__cmp_instance);
83 pcmk__assign_instances(rsc, rsc->priv->children, pe__clone_max(rsc),
84 pe__clone_node_max(rsc));
85
86 if (pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
87 pcmk__set_instance_roles(rsc);
88 }
89
90 pcmk__clear_rsc_flags(rsc, pcmk__rsc_unassigned|pcmk__rsc_assigning);
91 pcmk__rsc_trace(rsc, "Assigned clone %s", rsc->id);
92 return NULL;
93 }
94
95
96
97
98
99
100
101 void
102 pcmk__clone_create_actions(pcmk_resource_t *rsc)
103 {
104 pcmk__assert(pcmk__is_clone(rsc));
105
106 pcmk__rsc_trace(rsc, "Creating actions for clone %s", rsc->id);
107 pcmk__create_instance_actions(rsc, rsc->priv->children);
108 if (pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
109 pcmk__create_promotable_actions(rsc);
110 }
111 }
112
113
114
115
116
117
118
119 void
120 pcmk__clone_internal_constraints(pcmk_resource_t *rsc)
121 {
122 bool ordered = false;
123
124 pcmk__assert(pcmk__is_clone(rsc));
125
126 pcmk__rsc_trace(rsc, "Creating internal constraints for clone %s", rsc->id);
127
128
129 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOPPED,
130 rsc, PCMK_ACTION_START,
131 pcmk__ar_ordered);
132 pcmk__order_resource_actions(rsc, PCMK_ACTION_START,
133 rsc, PCMK_ACTION_RUNNING,
134 pcmk__ar_unrunnable_first_blocks);
135 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP,
136 rsc, PCMK_ACTION_STOPPED,
137 pcmk__ar_unrunnable_first_blocks);
138
139
140 if (pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
141 pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTED,
142 rsc, PCMK_ACTION_STOP,
143 pcmk__ar_ordered);
144 pcmk__order_resource_actions(rsc, PCMK_ACTION_RUNNING,
145 rsc, PCMK_ACTION_PROMOTE,
146 pcmk__ar_unrunnable_first_blocks);
147 }
148
149 ordered = pe__clone_is_ordered(rsc);
150 if (ordered) {
151
152
153
154
155 rsc->priv->children = g_list_sort(rsc->priv->children,
156 pcmk__cmp_instance_number);
157 }
158 for (GList *iter = rsc->priv->children;
159 iter != NULL; iter = iter->next) {
160
161 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
162
163 instance->priv->cmds->internal_constraints(instance);
164
165
166 pcmk__order_starts(rsc, instance, pcmk__ar_unrunnable_first_blocks
167 |pcmk__ar_then_implies_first_graphed);
168 pcmk__order_resource_actions(instance, PCMK_ACTION_START,
169 rsc, PCMK_ACTION_RUNNING,
170 pcmk__ar_first_implies_then_graphed);
171
172
173 pcmk__order_stops(rsc, instance, pcmk__ar_then_implies_first_graphed);
174 pcmk__order_resource_actions(instance, PCMK_ACTION_STOP,
175 rsc, PCMK_ACTION_STOPPED,
176 pcmk__ar_first_implies_then_graphed);
177
178
179
180
181
182 if (ordered) {
183 for (GList *later = iter->next;
184 later != NULL; later = later->next) {
185 pcmk__order_starts(instance, (pcmk_resource_t *) later->data,
186 pcmk__ar_ordered);
187 pcmk__order_stops((pcmk_resource_t *) later->data, instance,
188 pcmk__ar_ordered);
189 }
190 }
191 }
192 if (pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
193 pcmk__order_promotable_instances(rsc);
194 }
195 }
196
197
198
199
200
201
202
203
204
205 static bool
206 can_interleave(const pcmk__colocation_t *colocation)
207 {
208 const pcmk_resource_t *primary = colocation->primary;
209 const pcmk_resource_t *dependent = colocation->dependent;
210
211
212 if (dependent->priv->variant <= pcmk__rsc_variant_group) {
213 return false;
214 }
215
216
217 if (!crm_is_true(g_hash_table_lookup(dependent->priv->meta,
218 PCMK_META_INTERLEAVE))) {
219 return false;
220 }
221
222
223
224
225 if (dependent->priv->fns->max_per_node(dependent)
226 != primary->priv->fns->max_per_node(primary)) {
227 pcmk__config_err("Cannot interleave %s and %s because they do not "
228 "support the same number of instances per node",
229 dependent->id, primary->id);
230 return false;
231 }
232
233 return true;
234 }
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251 int
252 pcmk__clone_apply_coloc_score(pcmk_resource_t *dependent,
253 const pcmk_resource_t *primary,
254 const pcmk__colocation_t *colocation,
255 bool for_dependent)
256 {
257 const GList *iter = NULL;
258 int priority_delta = 0;
259
260
261
262
263
264 pcmk__assert(!for_dependent && (colocation != NULL)
265 && pcmk__is_clone(primary) && pcmk__is_primitive(dependent));
266
267 if (pcmk_is_set(primary->flags, pcmk__rsc_unassigned)) {
268 pcmk__rsc_trace(primary,
269 "Delaying processing colocation %s "
270 "because cloned primary %s is still provisional",
271 colocation->id, primary->id);
272 return 0;
273 }
274
275 pcmk__rsc_trace(primary, "Processing colocation %s (%s with clone %s @%s)",
276 colocation->id, dependent->id, primary->id,
277 pcmk_readable_score(colocation->score));
278
279
280 if (pcmk_is_set(primary->flags, pcmk__rsc_promotable)
281 && (colocation->primary_role != pcmk_role_unknown)) {
282
283 if (pcmk_is_set(dependent->flags, pcmk__rsc_unassigned)) {
284
285 pcmk__update_dependent_with_promotable(primary, dependent,
286 colocation);
287 return 0;
288 }
289
290 if (colocation->dependent_role == pcmk_role_promoted) {
291
292 return pcmk__update_promotable_dependent_priority(primary,
293 dependent,
294 colocation);
295 }
296 }
297
298
299 if (can_interleave(colocation)) {
300 const pcmk_resource_t *primary_instance = NULL;
301
302 primary_instance = pcmk__find_compatible_instance(dependent, primary,
303 pcmk_role_unknown,
304 false);
305 if (primary_instance != NULL) {
306 pcmk__rsc_debug(primary, "Interleaving %s with %s",
307 dependent->id, primary_instance->id);
308
309 return dependent->priv->cmds->apply_coloc_score(dependent,
310 primary_instance,
311 colocation, true);
312 }
313
314 if (colocation->score >= PCMK_SCORE_INFINITY) {
315 crm_notice("%s cannot run because it cannot interleave with "
316 "any instance of %s", dependent->id, primary->id);
317 pcmk__assign_resource(dependent, NULL, true, true);
318
319 } else {
320 pcmk__rsc_debug(primary,
321 "%s will not colocate with %s "
322 "because no instance can interleave with it",
323 dependent->id, primary->id);
324 }
325
326 return 0;
327 }
328
329
330 if (colocation->score >= PCMK_SCORE_INFINITY) {
331 GList *primary_nodes = NULL;
332
333
334 for (iter = primary->priv->children;
335 iter != NULL; iter = iter->next) {
336
337 const pcmk_resource_t *instance = iter->data;
338 pcmk_node_t *chosen = NULL;
339
340 chosen = instance->priv->fns->location(instance, NULL,
341 pcmk__rsc_node_assigned);
342 if ((chosen != NULL)
343 && !is_set_recursive(instance, pcmk__rsc_blocked, TRUE)) {
344 pcmk__rsc_trace(primary, "Allowing %s: %s %d",
345 colocation->id, pcmk__node_name(chosen),
346 chosen->assign->score);
347 primary_nodes = g_list_prepend(primary_nodes, chosen);
348 }
349 }
350 pcmk__colocation_intersect_nodes(dependent, primary, colocation,
351 primary_nodes, false);
352 g_list_free(primary_nodes);
353 return 0;
354 }
355
356
357 for (iter = primary->priv->children; iter != NULL; iter = iter->next) {
358 const pcmk_resource_t *instance = iter->data;
359 int instance_delta = instance->priv->cmds->apply_coloc_score(dependent,
360 instance,
361 colocation,
362 false);
363
364 priority_delta = pcmk__add_scores(priority_delta, instance_delta);
365 }
366 return priority_delta;
367 }
368
369
370 void
371 pcmk__with_clone_colocations(const pcmk_resource_t *rsc,
372 const pcmk_resource_t *orig_rsc, GList **list)
373 {
374 const pcmk_resource_t *parent = NULL;
375
376 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
377 parent = rsc->priv->parent;
378
379 pcmk__add_with_this_list(list, rsc->priv->with_this_colocations,
380 orig_rsc);
381
382 if (parent != NULL) {
383 parent->priv->cmds->with_this_colocations(parent, orig_rsc, list);
384 }
385 }
386
387
388 void
389 pcmk__clone_with_colocations(const pcmk_resource_t *rsc,
390 const pcmk_resource_t *orig_rsc, GList **list)
391 {
392 const pcmk_resource_t *parent = NULL;
393
394 CRM_CHECK((rsc != NULL) && (orig_rsc != NULL) && (list != NULL), return);
395 parent = rsc->priv->parent;
396
397 pcmk__add_this_with_list(list, rsc->priv->this_with_colocations,
398 orig_rsc);
399
400 if (parent != NULL) {
401 parent->priv->cmds->this_with_colocations(parent, orig_rsc, list);
402 }
403 }
404
405
406
407
408
409
410
411
412
413
414 uint32_t
415 pcmk__clone_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
416 {
417 pcmk__assert((action != NULL) && pcmk__is_clone(action->rsc));
418
419 return pcmk__collective_action_flags(action, action->rsc->priv->children,
420 node);
421 }
422
423
424
425
426
427
428
429
430 void
431 pcmk__clone_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
432 {
433 CRM_CHECK((location != NULL) && pcmk__is_clone(rsc), return);
434
435 pcmk__apply_location(rsc, location);
436
437 for (GList *iter = rsc->priv->children;
438 iter != NULL; iter = iter->next) {
439
440 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
441
442 instance->priv->cmds->apply_location(instance, location);
443 }
444 }
445
446
447 static void
448 call_action_flags(gpointer data, gpointer user_data)
449 {
450 pcmk_resource_t *rsc = user_data;
451
452 rsc->priv->cmds->action_flags((pcmk_action_t *) data, NULL);
453 }
454
455
456
457
458
459
460
461 void
462 pcmk__clone_add_actions_to_graph(pcmk_resource_t *rsc)
463 {
464 pcmk__assert(pcmk__is_clone(rsc));
465
466 g_list_foreach(rsc->priv->actions, call_action_flags, rsc);
467 pe__create_clone_notifications(rsc);
468
469 for (GList *iter = rsc->priv->children;
470 iter != NULL; iter = iter->next) {
471
472 pcmk_resource_t *child_rsc = (pcmk_resource_t *) iter->data;
473
474 child_rsc->priv->cmds->add_actions_to_graph(child_rsc);
475 }
476
477 pcmk__add_rsc_actions_to_graph(rsc);
478 pe__free_clone_notification_data(rsc);
479 }
480
481
482
483
484
485
486
487
488
489
490
491 static bool
492 rsc_probed_on(const pcmk_resource_t *rsc, const pcmk_node_t *node)
493 {
494 if (rsc->priv->children != NULL) {
495 for (GList *child_iter = rsc->priv->children;
496 child_iter != NULL; child_iter = child_iter->next) {
497
498 pcmk_resource_t *child = (pcmk_resource_t *) child_iter->data;
499
500 if (rsc_probed_on(child, node)) {
501 return true;
502 }
503 }
504 return false;
505 }
506
507 if (rsc->priv->probed_nodes != NULL) {
508 GHashTableIter iter;
509 pcmk_node_t *known_node = NULL;
510
511 g_hash_table_iter_init(&iter, rsc->priv->probed_nodes);
512 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
513 if (pcmk__same_node(node, known_node)) {
514 return true;
515 }
516 }
517 }
518 return false;
519 }
520
521
522
523
524
525
526
527
528
529
530
531 static pcmk_resource_t *
532 find_probed_instance_on(const pcmk_resource_t *clone, const pcmk_node_t *node)
533 {
534 for (GList *iter = clone->priv->children;
535 iter != NULL; iter = iter->next) {
536
537 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
538
539 if (rsc_probed_on(instance, node)) {
540 return instance;
541 }
542 }
543 return NULL;
544 }
545
546
547
548
549
550
551
552
553 static bool
554 probe_anonymous_clone(pcmk_resource_t *clone, pcmk_node_t *node)
555 {
556
557 pcmk_resource_t *child = find_probed_instance_on(clone, node);
558
559
560 for (GList *iter = clone->priv->children;
561 (iter != NULL) && (child == NULL); iter = iter->next) {
562
563 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
564 const pcmk_node_t *instance_node = NULL;
565
566 instance_node = instance->priv->fns->location(instance, NULL,
567 pcmk__rsc_node_assigned);
568 if (pcmk__same_node(instance_node, node)) {
569 child = instance;
570 }
571 }
572
573
574 if (child == NULL) {
575 child = clone->priv->children->data;
576 }
577
578
579 return child->priv->cmds->create_probe(child, node);
580 }
581
582
583
584
585
586
587
588
589
590
591 bool
592 pcmk__clone_create_probe(pcmk_resource_t *rsc, pcmk_node_t *node)
593 {
594 pcmk__assert((node != NULL) && pcmk__is_clone(rsc));
595
596 if (pcmk_is_set(rsc->flags, pcmk__rsc_exclusive_probes)) {
597
598
599
600
601
602
603
604
605
606 pcmk_node_t *allowed = g_hash_table_lookup(rsc->priv->allowed_nodes,
607 node->priv->id);
608
609 if ((allowed == NULL)
610 || (allowed->assign->probe_mode != pcmk__probe_exclusive)) {
611
612
613
614
615 pcmk__rsc_trace(rsc,
616 "Skipping probe for %s on %s because resource has "
617 "exclusive discovery but is not allowed on node",
618 rsc->id, pcmk__node_name(node));
619 g_hash_table_remove(rsc->priv->allowed_nodes, node->priv->id);
620 return false;
621 }
622 }
623
624 rsc->priv->children = g_list_sort(rsc->priv->children,
625 pcmk__cmp_instance_number);
626 if (pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
627 return pcmk__probe_resource_list(rsc->priv->children, node);
628 } else {
629 return probe_anonymous_clone(rsc, node);
630 }
631 }
632
633
634
635
636
637
638
639
640
641
642 void
643 pcmk__clone_add_graph_meta(const pcmk_resource_t *rsc, xmlNode *xml)
644 {
645 char *name = NULL;
646
647 pcmk__assert(pcmk__is_clone(rsc) && (xml != NULL));
648
649 name = crm_meta_name(PCMK_META_GLOBALLY_UNIQUE);
650 crm_xml_add(xml, name, pcmk__flag_text(rsc->flags, pcmk__rsc_unique));
651 free(name);
652
653 name = crm_meta_name(PCMK_META_NOTIFY);
654 crm_xml_add(xml, name, pcmk__flag_text(rsc->flags, pcmk__rsc_notify));
655 free(name);
656
657 name = crm_meta_name(PCMK_META_CLONE_MAX);
658 crm_xml_add_int(xml, name, pe__clone_max(rsc));
659 free(name);
660
661 name = crm_meta_name(PCMK_META_CLONE_NODE_MAX);
662 crm_xml_add_int(xml, name, pe__clone_node_max(rsc));
663 free(name);
664
665 if (pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
666 int promoted_max = pe__clone_promoted_max(rsc);
667 int promoted_node_max = pe__clone_promoted_node_max(rsc);
668
669 name = crm_meta_name(PCMK_META_PROMOTED_MAX);
670 crm_xml_add_int(xml, name, promoted_max);
671 free(name);
672
673 name = crm_meta_name(PCMK_META_PROMOTED_NODE_MAX);
674 crm_xml_add_int(xml, name, promoted_node_max);
675 free(name);
676
677
678
679
680 name = crm_meta_name(PCMK__META_PROMOTED_MAX_LEGACY);
681 crm_xml_add_int(xml, name, promoted_max);
682 free(name);
683
684 name = crm_meta_name(PCMK__META_PROMOTED_NODE_MAX_LEGACY);
685 crm_xml_add_int(xml, name, promoted_node_max);
686 free(name);
687 }
688 }
689
690
691 void
692 pcmk__clone_add_utilization(const pcmk_resource_t *rsc,
693 const pcmk_resource_t *orig_rsc, GList *all_rscs,
694 GHashTable *utilization)
695 {
696 bool existing = false;
697 pcmk_resource_t *child = NULL;
698
699 pcmk__assert(pcmk__is_clone(rsc) && (orig_rsc != NULL)
700 && (utilization != NULL));
701
702 if (!pcmk_is_set(rsc->flags, pcmk__rsc_unassigned)) {
703 return;
704 }
705
706
707 for (GList *iter = rsc->priv->children;
708 iter != NULL; iter = iter->next) {
709
710 child = (pcmk_resource_t *) iter->data;
711 if (g_list_find(all_rscs, child)) {
712 existing = true;
713 } else {
714
715 for (GList *member_iter = child->priv->children;
716 member_iter != NULL; member_iter = member_iter->next) {
717
718 pcmk_resource_t *member = (pcmk_resource_t *) member_iter->data;
719
720 if (g_list_find(all_rscs, member) != NULL) {
721
722 child->priv->cmds->add_utilization(child, orig_rsc,
723 all_rscs, utilization);
724 existing = true;
725 break;
726 }
727 }
728 }
729 }
730
731 if (!existing && (rsc->priv->children != NULL)) {
732
733 child = (pcmk_resource_t *) rsc->priv->children->data;
734
735 child->priv->cmds->add_utilization(child, orig_rsc, all_rscs,
736 utilization);
737 }
738 }
739
740
741 void
742 pcmk__clone_shutdown_lock(pcmk_resource_t *rsc)
743 {
744 pcmk__assert(pcmk__is_clone(rsc));
745 return;
746 }