This source file includes following definitions.
- order_instance_promotion
- order_instance_demotion
- check_for_role_change
- apply_promoted_locations
- node_to_be_promoted_on
- cmp_promotable_instance
- add_promotion_priority_to_node_score
- apply_coloc_to_primary
- set_promotion_priority_to_node_score
- sort_promotable_instances
- find_active_anon_instance
- anonymous_known_on
- is_allowed
- promotion_score_applies
- promotion_attr_value
- promotion_score
- pcmk__add_promotion_scores
- set_current_role_unpromoted
- set_next_role_unpromoted
- set_next_role_promoted
- show_promotion_score
- set_instance_priority
- set_instance_role
- pcmk__set_instance_roles
- create_promotable_instance_actions
- reset_instance_priorities
- pcmk__create_promotable_actions
- pcmk__order_promotable_instances
- update_dependent_allowed_nodes
- pcmk__update_dependent_with_promotable
- pcmk__update_promotable_dependent_priority
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 static void
26 order_instance_promotion(pcmk_resource_t *clone, pcmk_resource_t *child,
27 pcmk_resource_t *last)
28 {
29
30 pcmk__order_resource_actions(clone, PCMK_ACTION_PROMOTE,
31 child, PCMK_ACTION_PROMOTE,
32 pcmk__ar_ordered);
33 pcmk__order_resource_actions(child, PCMK_ACTION_PROMOTE,
34 clone, PCMK_ACTION_PROMOTED,
35 pcmk__ar_ordered);
36
37
38 if ((last != NULL) && pe__clone_is_ordered(clone)) {
39 pcmk__order_resource_actions(last, PCMK_ACTION_PROMOTE,
40 child, PCMK_ACTION_PROMOTE,
41 pcmk__ar_ordered);
42 }
43 }
44
45
46
47
48
49
50
51
52
53 static void
54 order_instance_demotion(pcmk_resource_t *clone, pcmk_resource_t *child,
55 pcmk_resource_t *last)
56 {
57
58 pcmk__order_resource_actions(clone, PCMK_ACTION_DEMOTE, child,
59 PCMK_ACTION_DEMOTE,
60 pcmk__ar_then_implies_first_graphed);
61 pcmk__order_resource_actions(child, PCMK_ACTION_DEMOTE,
62 clone, PCMK_ACTION_DEMOTED,
63 pcmk__ar_first_implies_then_graphed);
64
65
66 if ((last != NULL) && pe__clone_is_ordered(clone)) {
67 pcmk__order_resource_actions(child, PCMK_ACTION_DEMOTE, last,
68 PCMK_ACTION_DEMOTE, pcmk__ar_ordered);
69 }
70 }
71
72
73
74
75
76
77
78
79
80 static void
81 check_for_role_change(const pcmk_resource_t *rsc, bool *demoting,
82 bool *promoting)
83 {
84 const GList *iter = NULL;
85
86
87 if (rsc->priv->children != NULL) {
88 for (iter = rsc->priv->children; iter != NULL; iter = iter->next) {
89 check_for_role_change((const pcmk_resource_t *) iter->data,
90 demoting, promoting);
91 }
92 return;
93 }
94
95 for (iter = rsc->priv->actions; iter != NULL; iter = iter->next) {
96 const pcmk_action_t *action = (const pcmk_action_t *) iter->data;
97
98 if (*promoting && *demoting) {
99 return;
100
101 } else if (pcmk_is_set(action->flags, pcmk__action_optional)) {
102 continue;
103
104 } else if (pcmk__str_eq(PCMK_ACTION_DEMOTE, action->task,
105 pcmk__str_none)) {
106 *demoting = true;
107
108 } else if (pcmk__str_eq(PCMK_ACTION_PROMOTE, action->task,
109 pcmk__str_none)) {
110 *promoting = true;
111 }
112 }
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127 static void
128 apply_promoted_locations(pcmk_resource_t *child,
129 const GList *location_constraints,
130 const pcmk_node_t *chosen)
131 {
132 for (const GList *iter = location_constraints; iter; iter = iter->next) {
133 const pcmk__location_t *location = iter->data;
134 const pcmk_node_t *constraint_node = NULL;
135
136 if (location->role_filter == pcmk_role_promoted) {
137 constraint_node = pe_find_node_id(location->nodes,
138 chosen->priv->id);
139 }
140 if (constraint_node != NULL) {
141 int new_priority = pcmk__add_scores(child->priv->priority,
142 constraint_node->assign->score);
143
144 pcmk__rsc_trace(child,
145 "Applying location %s to %s promotion priority on "
146 "%s: %s + %s = %s",
147 location->id, child->id,
148 pcmk__node_name(constraint_node),
149 pcmk_readable_score(child->priv->priority),
150 pcmk_readable_score(constraint_node->assign->score),
151 pcmk_readable_score(new_priority));
152 child->priv->priority = new_priority;
153 }
154 }
155 }
156
157
158
159
160
161
162
163
164
165 static pcmk_node_t *
166 node_to_be_promoted_on(const pcmk_resource_t *rsc)
167 {
168 pcmk_node_t *node = NULL;
169 pcmk_node_t *local_node = NULL;
170 const pcmk_resource_t *parent = NULL;
171
172
173 for (GList *iter = rsc->priv->children;
174 iter != NULL; iter = iter->next) {
175
176 pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
177
178 if (node_to_be_promoted_on(child) == NULL) {
179 pcmk__rsc_trace(rsc,
180 "%s can't be promoted because member %s can't",
181 rsc->id, child->id);
182 return NULL;
183 }
184 }
185
186 node = rsc->priv->fns->location(rsc, NULL, pcmk__rsc_node_assigned);
187 if (node == NULL) {
188 pcmk__rsc_trace(rsc, "%s can't be promoted because it won't be active",
189 rsc->id);
190 return NULL;
191
192 } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
193 if (rsc->priv->fns->state(rsc, TRUE) == pcmk_role_promoted) {
194 crm_notice("Unmanaged instance %s will be left promoted on %s",
195 rsc->id, pcmk__node_name(node));
196 } else {
197 pcmk__rsc_trace(rsc, "%s can't be promoted because it is unmanaged",
198 rsc->id);
199 return NULL;
200 }
201
202 } else if (rsc->priv->priority < 0) {
203 pcmk__rsc_trace(rsc,
204 "%s can't be promoted because its promotion priority "
205 "%d is negative",
206 rsc->id, rsc->priv->priority);
207 return NULL;
208
209 } else if (!pcmk__node_available(node, false, true)) {
210 pcmk__rsc_trace(rsc,
211 "%s can't be promoted because %s can't run resources",
212 rsc->id, pcmk__node_name(node));
213 return NULL;
214 }
215
216 parent = pe__const_top_resource(rsc, false);
217 local_node = g_hash_table_lookup(parent->priv->allowed_nodes,
218 node->priv->id);
219
220 if (local_node == NULL) {
221
222
223
224
225 if (pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
226 pcmk__sched_err(node->priv->scheduler,
227 "%s can't be promoted because %s is not allowed "
228 "on %s (scheduler bug?)",
229 rsc->id, parent->id, pcmk__node_name(node));
230 }
231 return NULL;
232
233 } else if ((local_node->assign->count >= pe__clone_promoted_node_max(parent))
234 && pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
235 pcmk__rsc_trace(rsc,
236 "%s can't be promoted because %s has "
237 "maximum promoted instances already",
238 rsc->id, pcmk__node_name(node));
239 return NULL;
240 }
241
242 return local_node;
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256 static gint
257 cmp_promotable_instance(gconstpointer a, gconstpointer b)
258 {
259 const pcmk_resource_t *rsc1 = (const pcmk_resource_t *) a;
260 const pcmk_resource_t *rsc2 = (const pcmk_resource_t *) b;
261
262 enum rsc_role_e role1 = pcmk_role_unknown;
263 enum rsc_role_e role2 = pcmk_role_unknown;
264
265 pcmk__assert((rsc1 != NULL) && (rsc2 != NULL));
266
267
268 if (rsc1->priv->promotion_priority > rsc2->priv->promotion_priority) {
269 pcmk__rsc_trace(rsc1,
270 "%s has higher promotion priority (%s) than %s (%d)",
271 rsc1->id,
272 pcmk_readable_score(rsc1->priv->promotion_priority),
273 rsc2->id, rsc2->priv->promotion_priority);
274 return -1;
275 }
276
277 if (rsc1->priv->promotion_priority < rsc2->priv->promotion_priority) {
278 pcmk__rsc_trace(rsc1,
279 "%s has lower promotion priority (%s) than %s (%d)",
280 rsc1->id,
281 pcmk_readable_score(rsc1->priv->promotion_priority),
282 rsc2->id, rsc2->priv->promotion_priority);
283 return 1;
284 }
285
286
287 role1 = rsc1->priv->fns->state(rsc1, TRUE);
288 role2 = rsc2->priv->fns->state(rsc2, TRUE);
289 if (role1 > role2) {
290 pcmk__rsc_trace(rsc1,
291 "%s has higher promotion priority than %s "
292 "(higher current role)",
293 rsc1->id, rsc2->id);
294 return -1;
295 } else if (role1 < role2) {
296 pcmk__rsc_trace(rsc1,
297 "%s has lower promotion priority than %s "
298 "(lower current role)",
299 rsc1->id, rsc2->id);
300 return 1;
301 }
302
303
304 return pcmk__cmp_instance(a, b);
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318 static void
319 add_promotion_priority_to_node_score(gpointer data, gpointer user_data)
320 {
321 const pcmk_resource_t *child = (const pcmk_resource_t *) data;
322 pcmk_resource_t *clone = (pcmk_resource_t *) user_data;
323
324 pcmk_node_t *node = NULL;
325 const pcmk_node_t *chosen = NULL;
326 const int promotion_priority = child->priv->promotion_priority;
327
328 if (promotion_priority < 0) {
329 pcmk__rsc_trace(clone,
330 "Not adding promotion priority of %s: negative (%s)",
331 child->id, pcmk_readable_score(promotion_priority));
332 return;
333 }
334
335 chosen = child->priv->fns->location(child, NULL, pcmk__rsc_node_assigned);
336 if (chosen == NULL) {
337 pcmk__rsc_trace(clone, "Not adding promotion priority of %s: inactive",
338 child->id);
339 return;
340 }
341
342 node = g_hash_table_lookup(clone->priv->allowed_nodes,
343 chosen->priv->id);
344 pcmk__assert(node != NULL);
345
346 node->assign->score = pcmk__add_scores(promotion_priority,
347 node->assign->score);
348 pcmk__rsc_trace(clone,
349 "Added cumulative priority of %s (%s) to score on %s "
350 "(now %d)",
351 child->id, pcmk_readable_score(promotion_priority),
352 pcmk__node_name(node), node->assign->score);
353 }
354
355
356
357
358
359
360
361
362 static void
363 apply_coloc_to_primary(gpointer data, gpointer user_data)
364 {
365 pcmk__colocation_t *colocation = data;
366 pcmk_resource_t *clone = user_data;
367 pcmk_resource_t *dependent = colocation->dependent;
368 const float factor = colocation->score / (float) PCMK_SCORE_INFINITY;
369 const uint32_t flags = pcmk__coloc_select_active
370 |pcmk__coloc_select_nonnegative;
371
372 if ((colocation->primary_role != pcmk_role_promoted)
373 || !pcmk__colocation_has_influence(colocation, NULL)) {
374 return;
375 }
376
377 pcmk__rsc_trace(clone, "Applying colocation %s (%s with promoted %s) @%s",
378 colocation->id, colocation->dependent->id,
379 colocation->primary->id,
380 pcmk_readable_score(colocation->score));
381 dependent->priv->cmds->add_colocated_node_scores(dependent, clone,
382 clone->id,
383 &(clone->priv->allowed_nodes),
384 colocation, factor, flags);
385 }
386
387
388
389
390
391
392
393
394 static void
395 set_promotion_priority_to_node_score(gpointer data, gpointer user_data)
396 {
397 pcmk_resource_t *child = (pcmk_resource_t *) data;
398 const pcmk_resource_t *clone = (const pcmk_resource_t *) user_data;
399
400 pcmk_node_t *chosen = child->priv->fns->location(child, NULL,
401 pcmk__rsc_node_assigned);
402
403 if (!pcmk_is_set(child->flags, pcmk__rsc_managed)
404 && (child->priv->next_role == pcmk_role_promoted)) {
405 child->priv->promotion_priority = PCMK_SCORE_INFINITY;
406 pcmk__rsc_trace(clone,
407 "Final promotion priority for %s is %s "
408 "(unmanaged promoted)",
409 child->id, pcmk_readable_score(PCMK_SCORE_INFINITY));
410
411 } else if (chosen == NULL) {
412 child->priv->promotion_priority = -PCMK_SCORE_INFINITY;
413 pcmk__rsc_trace(clone,
414 "Final promotion priority for %s is %s "
415 "(will not be active)",
416 child->id, pcmk_readable_score(-PCMK_SCORE_INFINITY));
417
418 } else if (child->priv->promotion_priority < 0) {
419 pcmk__rsc_trace(clone,
420 "Final promotion priority for %s is %s "
421 "(ignoring node score)",
422 child->id,
423 pcmk_readable_score(child->priv->promotion_priority));
424
425 } else {
426 const pcmk_node_t *node = NULL;
427
428 node = g_hash_table_lookup(clone->priv->allowed_nodes,
429 chosen->priv->id);
430
431 pcmk__assert(node != NULL);
432 child->priv->promotion_priority = node->assign->score;
433 pcmk__rsc_trace(clone,
434 "Adding scores for %s: "
435 "final promotion priority for %s is %s",
436 clone->id, child->id,
437 pcmk_readable_score(child->priv->promotion_priority));
438 }
439 }
440
441
442
443
444
445
446
447 static void
448 sort_promotable_instances(pcmk_resource_t *clone)
449 {
450 GList *colocations = NULL;
451
452 if (pe__set_clone_flag(clone, pcmk__clone_promotion_constrained)
453 == pcmk_rc_already) {
454 return;
455 }
456 pcmk__set_rsc_flags(clone, pcmk__rsc_updating_nodes);
457
458 for (GList *iter = clone->priv->children;
459 iter != NULL; iter = iter->next) {
460
461 pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
462
463 pcmk__rsc_trace(clone,
464 "Adding scores for %s: "
465 "initial promotion priority for %s is %s",
466 clone->id, child->id,
467 pcmk_readable_score(child->priv->promotion_priority));
468 }
469 pe__show_node_scores(true, clone, "Before", clone->priv->allowed_nodes,
470 clone->priv->scheduler);
471
472 g_list_foreach(clone->priv->children,
473 add_promotion_priority_to_node_score, clone);
474
475
476 colocations = pcmk__with_this_colocations(clone);
477 g_list_foreach(colocations, apply_coloc_to_primary, clone);
478 g_list_free(colocations);
479
480
481 pcmk__require_promotion_tickets(clone);
482
483 pe__show_node_scores(true, clone, "After", clone->priv->allowed_nodes,
484 clone->priv->scheduler);
485
486
487 g_list_foreach(clone->priv->children,
488 set_promotion_priority_to_node_score, clone);
489
490
491 clone->priv->children = g_list_sort(clone->priv->children,
492 cmp_promotable_instance);
493 pcmk__clear_rsc_flags(clone, pcmk__rsc_updating_nodes);
494 }
495
496
497
498
499
500
501
502
503
504
505
506 static pcmk_resource_t *
507 find_active_anon_instance(const pcmk_resource_t *clone, const char *id,
508 const pcmk_node_t *node)
509 {
510 for (GList *iter = clone->priv->children; iter; iter = iter->next) {
511 pcmk_resource_t *child = iter->data;
512 pcmk_resource_t *active = NULL;
513
514
515 active = clone->priv->fns->find_rsc(child, id, node,
516 pcmk_rsc_match_clone_only
517 |pcmk_rsc_match_current_node);
518 if (active != NULL) {
519 return active;
520 }
521 }
522 return NULL;
523 }
524
525
526
527
528
529
530
531
532
533
534
535 static bool
536 anonymous_known_on(const pcmk_resource_t *clone, const char *id,
537 const pcmk_node_t *node)
538 {
539 for (GList *iter = clone->priv->children; iter; iter = iter->next) {
540 pcmk_resource_t *child = iter->data;
541
542
543
544
545 child = clone->priv->fns->find_rsc(child, id, NULL,
546 pcmk_rsc_match_clone_only);
547 CRM_LOG_ASSERT(child != NULL);
548 if (child != NULL) {
549 if (g_hash_table_lookup(child->priv->probed_nodes,
550 node->priv->id)) {
551 return true;
552 }
553 }
554 }
555 return false;
556 }
557
558
559
560
561
562
563
564
565
566
567 static bool
568 is_allowed(const pcmk_resource_t *rsc, const pcmk_node_t *node)
569 {
570 pcmk_node_t *allowed = g_hash_table_lookup(rsc->priv->allowed_nodes,
571 node->priv->id);
572
573 return (allowed != NULL) && (allowed->assign->score >= 0);
574 }
575
576
577
578
579
580
581
582
583
584
585 static bool
586 promotion_score_applies(const pcmk_resource_t *rsc, const pcmk_node_t *node)
587 {
588 char *id = clone_strip(rsc->id);
589 const pcmk_resource_t *parent = pe__const_top_resource(rsc, false);
590 pcmk_resource_t *active = NULL;
591 const char *reason = "allowed";
592
593
594 if (!pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
595
596
597 active = find_active_anon_instance(parent, id, node);
598 if (active == rsc) {
599 reason = "active";
600 goto check_allowed;
601 }
602
603
604
605
606 if ((active == NULL) && anonymous_known_on(parent, id, node)) {
607 reason = "probed";
608 goto check_allowed;
609 }
610 }
611
612
613
614
615
616 if ((rsc->priv->active_nodes == NULL)
617 && (g_hash_table_size(rsc->priv->probed_nodes) == 0)) {
618 reason = "none probed";
619 goto check_allowed;
620 }
621
622
623
624
625 if ((g_hash_table_lookup(rsc->priv->probed_nodes,
626 node->priv->id) != NULL)
627 || (pe_find_node_id(rsc->priv->active_nodes,
628 node->priv->id) != NULL)) {
629 reason = "known";
630 } else {
631 pcmk__rsc_trace(rsc,
632 "Ignoring %s promotion score (for %s) on %s: "
633 "not probed",
634 rsc->id, id, pcmk__node_name(node));
635 free(id);
636 return false;
637 }
638
639 check_allowed:
640 if (is_allowed(rsc, node)) {
641 pcmk__rsc_trace(rsc, "Counting %s promotion score (for %s) on %s: %s",
642 rsc->id, id, pcmk__node_name(node), reason);
643 free(id);
644 return true;
645 }
646
647 pcmk__rsc_trace(rsc,
648 "Ignoring %s promotion score (for %s) on %s: not allowed",
649 rsc->id, id, pcmk__node_name(node));
650 free(id);
651 return false;
652 }
653
654
655
656
657
658
659
660
661
662
663
664 static const char *
665 promotion_attr_value(const pcmk_resource_t *rsc, const pcmk_node_t *node,
666 const char *name)
667 {
668 char *attr_name = NULL;
669 const char *attr_value = NULL;
670 const char *target = NULL;
671 enum pcmk__rsc_node node_type = pcmk__rsc_node_assigned;
672
673 if (pcmk_is_set(rsc->flags, pcmk__rsc_unassigned)) {
674
675 node_type = pcmk__rsc_node_current;
676 }
677 target = g_hash_table_lookup(rsc->priv->meta,
678 PCMK_META_CONTAINER_ATTRIBUTE_TARGET);
679 attr_name = pcmk_promotion_score_name(name);
680 attr_value = pcmk__node_attr(node, attr_name, target, node_type);
681 free(attr_name);
682 return attr_value;
683 }
684
685
686
687
688
689
690
691
692
693
694
695 static int
696 promotion_score(const pcmk_resource_t *rsc, const pcmk_node_t *node,
697 bool *is_default)
698 {
699 int score = 0;
700 int rc = pcmk_rc_ok;
701 const char *name = NULL;
702 const char *attr_value = NULL;
703
704 if (is_default != NULL) {
705 *is_default = true;
706 }
707
708 CRM_CHECK((rsc != NULL) && (node != NULL), return 0);
709
710
711
712
713 if (rsc->priv->children != NULL) {
714 int score = 0;
715
716 for (const GList *iter = rsc->priv->children;
717 iter != NULL; iter = iter->next) {
718
719 const pcmk_resource_t *child = (const pcmk_resource_t *) iter->data;
720 bool child_default = false;
721 int child_score = promotion_score(child, node, &child_default);
722
723 if (!child_default && (is_default != NULL)) {
724 *is_default = false;
725 }
726 score += child_score;
727 }
728 return score;
729 }
730
731 if (!promotion_score_applies(rsc, node)) {
732 return 0;
733 }
734
735
736
737
738
739 name = pcmk__s(rsc->priv->history_id, rsc->id);
740
741 attr_value = promotion_attr_value(rsc, node, name);
742 if (attr_value != NULL) {
743 pcmk__rsc_trace(rsc, "Promotion score for %s on %s = %s",
744 name, pcmk__node_name(node),
745 pcmk__s(attr_value, "(unset)"));
746 } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
747
748
749
750
751 char *rsc_name = clone_strip(rsc->id);
752
753 if (strcmp(rsc->id, rsc_name) != 0) {
754 attr_value = promotion_attr_value(rsc, node, rsc_name);
755 pcmk__rsc_trace(rsc, "Promotion score for %s on %s (for %s) = %s",
756 rsc_name, pcmk__node_name(node), rsc->id,
757 pcmk__s(attr_value, "(unset)"));
758 }
759 free(rsc_name);
760 }
761
762 if (attr_value == NULL) {
763 return 0;
764 }
765
766 if (is_default != NULL) {
767 *is_default = false;
768 }
769
770 rc = pcmk_parse_score(attr_value, &score, 0);
771 if (rc != pcmk_rc_ok) {
772 crm_warn("Using 0 as promotion score for %s on %s "
773 "because '%s' is not a valid score",
774 rsc->id, pcmk__node_name(node), attr_value);
775 }
776 return score;
777 }
778
779
780
781
782
783
784
785 void
786 pcmk__add_promotion_scores(pcmk_resource_t *rsc)
787 {
788 if (pe__set_clone_flag(rsc,
789 pcmk__clone_promotion_added) == pcmk_rc_already) {
790 return;
791 }
792
793 for (GList *iter = rsc->priv->children;
794 iter != NULL; iter = iter->next) {
795
796 pcmk_resource_t *child_rsc = (pcmk_resource_t *) iter->data;
797
798 GHashTableIter iter;
799 pcmk_node_t *node = NULL;
800 int score, new_score;
801
802 g_hash_table_iter_init(&iter, child_rsc->priv->allowed_nodes);
803 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
804 if (!pcmk__node_available(node, false, false)) {
805
806
807
808 continue;
809 }
810
811 score = promotion_score(child_rsc, node, NULL);
812 if (score > 0) {
813 new_score = pcmk__add_scores(node->assign->score, score);
814 if (new_score != node->assign->score) {
815 node->assign->score = new_score;
816 pcmk__rsc_trace(rsc,
817 "Added %s promotion priority (%s) to score "
818 "on %s (now %s)",
819 child_rsc->id, pcmk_readable_score(score),
820 pcmk__node_name(node),
821 pcmk_readable_score(new_score));
822 }
823 }
824
825 if (score > child_rsc->priv->priority) {
826 pcmk__rsc_trace(rsc,
827 "Updating %s priority to promotion score "
828 "(%d->%d)",
829 child_rsc->id, child_rsc->priv->priority,
830 score);
831 child_rsc->priv->priority = score;
832 }
833 }
834 }
835 }
836
837
838
839
840
841
842
843
844 static void
845 set_current_role_unpromoted(void *data, void *user_data)
846 {
847 pcmk_resource_t *rsc = (pcmk_resource_t *) data;
848
849 if (rsc->priv->orig_role == pcmk_role_started) {
850
851 rsc->priv->orig_role = pcmk_role_unpromoted;
852 }
853 g_list_foreach(rsc->priv->children, set_current_role_unpromoted, NULL);
854 }
855
856
857
858
859
860
861
862
863 static void
864 set_next_role_unpromoted(void *data, void *user_data)
865 {
866 pcmk_resource_t *rsc = (pcmk_resource_t *) data;
867 GList *assigned = NULL;
868
869 rsc->priv->fns->location(rsc, &assigned, pcmk__rsc_node_assigned);
870 if (assigned == NULL) {
871 pe__set_next_role(rsc, pcmk_role_stopped, "stopped instance");
872 } else {
873 pe__set_next_role(rsc, pcmk_role_unpromoted, "unpromoted instance");
874 g_list_free(assigned);
875 }
876 g_list_foreach(rsc->priv->children, set_next_role_unpromoted, NULL);
877 }
878
879
880
881
882
883
884
885
886 static void
887 set_next_role_promoted(void *data, gpointer user_data)
888 {
889 pcmk_resource_t *rsc = (pcmk_resource_t *) data;
890
891 if (rsc->priv->next_role == pcmk_role_unknown) {
892 pe__set_next_role(rsc, pcmk_role_promoted, "promoted instance");
893 }
894 g_list_foreach(rsc->priv->children, set_next_role_promoted, NULL);
895 }
896
897
898
899
900
901
902
903 static void
904 show_promotion_score(pcmk_resource_t *instance)
905 {
906 pcmk_node_t *chosen = NULL;
907 const char *score_s = NULL;
908
909 chosen = instance->priv->fns->location(instance, NULL,
910 pcmk__rsc_node_assigned);
911 score_s = pcmk_readable_score(instance->priv->promotion_priority);
912 if (pcmk_is_set(instance->priv->scheduler->flags,
913 pcmk__sched_output_scores)
914 && !pcmk__is_daemon
915 && (instance->priv->scheduler->priv->out != NULL)) {
916
917 pcmk__output_t *out = instance->priv->scheduler->priv->out;
918
919 out->message(out, "promotion-score", instance, chosen, score_s);
920
921 } else if (chosen == NULL) {
922 pcmk__rsc_debug(pe__const_top_resource(instance, false),
923 "%s promotion score (inactive): %s (priority=%d)",
924 instance->id, score_s, instance->priv->priority);
925
926 } else {
927 pcmk__rsc_debug(pe__const_top_resource(instance, false),
928 "%s promotion score on %s: %s (priority=%d)",
929 instance->id, pcmk__node_name(chosen),
930 score_s, instance->priv->priority);
931 }
932 }
933
934
935
936
937
938
939
940
941 static void
942 set_instance_priority(gpointer data, gpointer user_data)
943 {
944 pcmk_resource_t *instance = (pcmk_resource_t *) data;
945 const pcmk_resource_t *clone = (const pcmk_resource_t *) user_data;
946
947 const pcmk_node_t *chosen = NULL;
948 enum rsc_role_e next_role = pcmk_role_unknown;
949 GList *list = NULL;
950
951 pcmk__rsc_trace(clone, "Assigning priority for %s: %s", instance->id,
952 pcmk_role_text(instance->priv->next_role));
953
954 if (instance->priv->fns->state(instance, TRUE) == pcmk_role_started) {
955 set_current_role_unpromoted(instance, NULL);
956 }
957
958
959 chosen = instance->priv->fns->location(instance, &list,
960 pcmk__rsc_node_assigned);
961 if (pcmk__list_of_multiple(list)) {
962 pcmk__config_err("Cannot promote non-colocated child %s",
963 instance->id);
964 }
965 g_list_free(list);
966 if (chosen == NULL) {
967 return;
968 }
969
970 next_role = instance->priv->fns->state(instance, FALSE);
971 switch (next_role) {
972 case pcmk_role_started:
973 case pcmk_role_unknown:
974
975 {
976 bool is_default = false;
977
978 instance->priv->priority = promotion_score(instance, chosen,
979 &is_default);
980 if (is_default) {
981
982
983
984
985
986
987 instance->priv->priority = -1;
988 }
989 }
990 break;
991
992 case pcmk_role_unpromoted:
993 case pcmk_role_stopped:
994
995 instance->priv->priority = -PCMK_SCORE_INFINITY;
996 break;
997
998 case pcmk_role_promoted:
999
1000 break;
1001
1002 default:
1003 CRM_CHECK(FALSE, crm_err("Unknown resource role %d for %s",
1004 next_role, instance->id));
1005 }
1006
1007
1008 apply_promoted_locations(instance, instance->priv->location_constraints,
1009 chosen);
1010 apply_promoted_locations(instance, clone->priv->location_constraints,
1011 chosen);
1012
1013
1014 list = pcmk__this_with_colocations(instance);
1015 for (GList *iter = list; iter != NULL; iter = iter->next) {
1016 pcmk__colocation_t *cons = (pcmk__colocation_t *) iter->data;
1017
1018 instance->priv->cmds->apply_coloc_score(instance, cons->primary, cons,
1019 true);
1020 }
1021 g_list_free(list);
1022
1023 instance->priv->promotion_priority = instance->priv->priority;
1024 if (next_role == pcmk_role_promoted) {
1025 instance->priv->promotion_priority = PCMK_SCORE_INFINITY;
1026 }
1027 pcmk__rsc_trace(clone, "Assigning %s priority = %d",
1028 instance->id, instance->priv->priority);
1029 }
1030
1031
1032
1033
1034
1035
1036
1037
1038 static void
1039 set_instance_role(gpointer data, gpointer user_data)
1040 {
1041 pcmk_resource_t *instance = (pcmk_resource_t *) data;
1042 int *count = (int *) user_data;
1043
1044 const pcmk_resource_t *clone = pe__const_top_resource(instance, false);
1045 const pcmk_scheduler_t *scheduler = instance->priv->scheduler;
1046 pcmk_node_t *chosen = NULL;
1047
1048 show_promotion_score(instance);
1049
1050 if (instance->priv->promotion_priority < 0) {
1051 pcmk__rsc_trace(clone, "Not supposed to promote instance %s",
1052 instance->id);
1053
1054 } else if ((*count < pe__clone_promoted_max(instance))
1055 || !pcmk_is_set(clone->flags, pcmk__rsc_managed)) {
1056 chosen = node_to_be_promoted_on(instance);
1057 }
1058
1059 if (chosen == NULL) {
1060 set_next_role_unpromoted(instance, NULL);
1061 return;
1062 }
1063
1064 if ((instance->priv->orig_role < pcmk_role_promoted)
1065 && !pcmk_is_set(scheduler->flags, pcmk__sched_quorate)
1066 && (scheduler->no_quorum_policy == pcmk_no_quorum_freeze)) {
1067 crm_notice("Clone instance %s cannot be promoted without quorum",
1068 instance->id);
1069 set_next_role_unpromoted(instance, NULL);
1070 return;
1071 }
1072
1073 chosen->assign->count++;
1074 pcmk__rsc_info(clone, "Choosing %s (%s) on %s for promotion",
1075 instance->id, pcmk_role_text(instance->priv->orig_role),
1076 pcmk__node_name(chosen));
1077 set_next_role_promoted(instance, NULL);
1078 (*count)++;
1079 }
1080
1081
1082
1083
1084
1085
1086
1087 void
1088 pcmk__set_instance_roles(pcmk_resource_t *rsc)
1089 {
1090 int promoted = 0;
1091 GHashTableIter iter;
1092 pcmk_node_t *node = NULL;
1093
1094
1095 g_hash_table_iter_init(&iter, rsc->priv->allowed_nodes);
1096 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1097 node->assign->count = 0;
1098 }
1099
1100
1101 g_list_foreach(rsc->priv->children, set_instance_priority, rsc);
1102 sort_promotable_instances(rsc);
1103
1104
1105 g_list_foreach(rsc->priv->children, set_instance_role, &promoted);
1106 pcmk__rsc_info(rsc, "%s: Promoted %d instances of a possible %d",
1107 rsc->id, promoted, pe__clone_promoted_max(rsc));
1108 }
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119 static void
1120 create_promotable_instance_actions(pcmk_resource_t *clone,
1121 bool *any_promoting, bool *any_demoting)
1122 {
1123 for (GList *iter = clone->priv->children;
1124 iter != NULL; iter = iter->next) {
1125
1126 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1127
1128 instance->priv->cmds->create_actions(instance);
1129 check_for_role_change(instance, any_demoting, any_promoting);
1130 }
1131 }
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143 static void
1144 reset_instance_priorities(pcmk_resource_t *clone)
1145 {
1146 for (GList *iter = clone->priv->children;
1147 iter != NULL; iter = iter->next) {
1148
1149 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1150
1151 instance->priv->priority = clone->priv->priority;
1152 }
1153 }
1154
1155
1156
1157
1158
1159
1160
1161 void
1162 pcmk__create_promotable_actions(pcmk_resource_t *clone)
1163 {
1164 bool any_promoting = false;
1165 bool any_demoting = false;
1166
1167
1168 create_promotable_instance_actions(clone, &any_promoting, &any_demoting);
1169
1170
1171 pe__create_promotable_pseudo_ops(clone, any_promoting, any_demoting);
1172
1173
1174 reset_instance_priorities(clone);
1175 }
1176
1177
1178
1179
1180
1181
1182
1183 void
1184 pcmk__order_promotable_instances(pcmk_resource_t *clone)
1185 {
1186 pcmk_resource_t *previous = NULL;
1187
1188 pcmk__promotable_restart_ordering(clone);
1189
1190 for (GList *iter = clone->priv->children;
1191 iter != NULL; iter = iter->next) {
1192
1193 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1194
1195
1196 pcmk__order_resource_actions(instance, PCMK_ACTION_DEMOTE,
1197 instance, PCMK_ACTION_PROMOTE,
1198 pcmk__ar_ordered);
1199
1200 order_instance_promotion(clone, instance, previous);
1201 order_instance_demotion(clone, instance, previous);
1202 previous = instance;
1203 }
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215 static void
1216 update_dependent_allowed_nodes(pcmk_resource_t *dependent,
1217 const pcmk_resource_t *primary,
1218 const pcmk_node_t *primary_node,
1219 const pcmk__colocation_t *colocation)
1220 {
1221 GHashTableIter iter;
1222 pcmk_node_t *node = NULL;
1223 const char *primary_value = NULL;
1224 const char *attr = colocation->node_attribute;
1225
1226 if (colocation->score >= PCMK_SCORE_INFINITY) {
1227 return;
1228 }
1229
1230 primary_value = pcmk__colocation_node_attr(primary_node, attr, primary);
1231
1232 pcmk__rsc_trace(colocation->primary,
1233 "Applying %s (%s with %s on %s by %s @%d) to %s",
1234 colocation->id, colocation->dependent->id,
1235 colocation->primary->id, pcmk__node_name(primary_node),
1236 attr, colocation->score, dependent->id);
1237
1238 g_hash_table_iter_init(&iter, dependent->priv->allowed_nodes);
1239 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1240 const char *dependent_value = pcmk__colocation_node_attr(node, attr,
1241 dependent);
1242
1243 if (pcmk__str_eq(primary_value, dependent_value, pcmk__str_casei)) {
1244 node->assign->score = pcmk__add_scores(node->assign->score,
1245 colocation->score);
1246 pcmk__rsc_trace(colocation->primary,
1247 "Added %s score (%s) to %s (now %s)",
1248 colocation->id,
1249 pcmk_readable_score(colocation->score),
1250 pcmk__node_name(node),
1251 pcmk_readable_score(node->assign->score));
1252 }
1253 }
1254 }
1255
1256
1257
1258
1259
1260
1261
1262
1263 void
1264 pcmk__update_dependent_with_promotable(const pcmk_resource_t *primary,
1265 pcmk_resource_t *dependent,
1266 const pcmk__colocation_t *colocation)
1267 {
1268 GList *affected_nodes = NULL;
1269
1270
1271
1272
1273
1274 for (GList *iter = primary->priv->children;
1275 iter != NULL; iter = iter->next) {
1276
1277 pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1278 pcmk_node_t *node = NULL;
1279
1280 node = instance->priv->fns->location(instance, NULL,
1281 pcmk__rsc_node_assigned);
1282 if (node == NULL) {
1283 continue;
1284 }
1285 if (instance->priv->fns->state(instance,
1286 FALSE) == colocation->primary_role) {
1287 update_dependent_allowed_nodes(dependent, primary, node,
1288 colocation);
1289 affected_nodes = g_list_prepend(affected_nodes, node);
1290 }
1291 }
1292
1293
1294
1295
1296
1297
1298
1299
1300 if ((colocation->score >= PCMK_SCORE_INFINITY)
1301 && ((colocation->dependent_role != pcmk_role_promoted)
1302 || (colocation->primary_role != pcmk_role_promoted))) {
1303
1304 pcmk__rsc_trace(colocation->primary,
1305 "Applying %s (mandatory %s with %s) to %s",
1306 colocation->id, colocation->dependent->id,
1307 colocation->primary->id, dependent->id);
1308 pcmk__colocation_intersect_nodes(dependent, primary, colocation,
1309 affected_nodes, true);
1310 }
1311 g_list_free(affected_nodes);
1312 }
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324 int
1325 pcmk__update_promotable_dependent_priority(const pcmk_resource_t *primary,
1326 pcmk_resource_t *dependent,
1327 const pcmk__colocation_t *colocation)
1328 {
1329 pcmk_resource_t *primary_instance = NULL;
1330
1331
1332 primary_instance = pcmk__find_compatible_instance(dependent, primary,
1333 colocation->primary_role,
1334 false);
1335
1336 if (primary_instance != NULL) {
1337
1338 int new_priority = pcmk__add_scores(dependent->priv->priority,
1339 colocation->score);
1340
1341 pcmk__rsc_trace(colocation->primary,
1342 "Applying %s (%s with %s) to %s priority "
1343 "(%s + %s = %s)",
1344 colocation->id, colocation->dependent->id,
1345 colocation->primary->id, dependent->id,
1346 pcmk_readable_score(dependent->priv->priority),
1347 pcmk_readable_score(colocation->score),
1348 pcmk_readable_score(new_priority));
1349 dependent->priv->priority = new_priority;
1350 return colocation->score;
1351 }
1352
1353 if (colocation->score >= PCMK_SCORE_INFINITY) {
1354
1355 pcmk__rsc_trace(colocation->primary,
1356 "Applying %s (%s with %s) to %s: can't be promoted",
1357 colocation->id, colocation->dependent->id,
1358 colocation->primary->id, dependent->id);
1359 dependent->priv->priority = -PCMK_SCORE_INFINITY;
1360 return -PCMK_SCORE_INFINITY;
1361 }
1362 return 0;
1363 }