pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
pcmk_sched_promotable.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
20extern gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
21
22extern bool pcmk__is_daemon;
23
24static void
25child_promoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
26 pe_resource_t * rsc, pe_resource_t * child, pe_resource_t * last,
28{
29 if (child == NULL) {
30 if (clone_data->ordered && last != NULL) {
31 pe_rsc_trace(rsc, "Ordered version (last node)");
32 /* last child promote before promoted started */
34 type, data_set);
35 }
36 return;
37 }
38
39 /* child promote before global promoted */
41 data_set);
42
43 /* global promote before child promote */
45 data_set);
46
47 if (clone_data->ordered) {
48 pe_rsc_trace(rsc, "Ordered version");
49 if (last == NULL) {
50 /* global promote before first child promote */
51 last = rsc;
52
53 }
54 /* else: child/child relative promote */
55 pcmk__order_starts(last, child, type, data_set);
57 type, data_set);
58
59 } else {
60 pe_rsc_trace(rsc, "Un-ordered version");
61 }
62}
63
64static void
65child_demoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
66 pe_resource_t * rsc, pe_resource_t * child, pe_resource_t * last,
68{
69 if (child == NULL) {
70 if (clone_data->ordered && last != NULL) {
71 pe_rsc_trace(rsc, "Ordered version (last node)");
72 /* global demote before first child demote */
75 }
76 return;
77 }
78
79 /* child demote before global demoted */
82
83 /* global demote before child demote */
86
87 if (clone_data->ordered && last != NULL) {
88 pe_rsc_trace(rsc, "Ordered version");
89
90 /* child/child relative demote */
92 data_set);
93
94 } else if (clone_data->ordered) {
95 pe_rsc_trace(rsc, "Ordered version (1st node)");
96 /* first child stop before global stopped */
98 data_set);
99
100 } else {
101 pe_rsc_trace(rsc, "Un-ordered version");
102 }
103}
104
105static void
106check_promotable_actions(pe_resource_t *rsc, gboolean *demoting,
107 gboolean *promoting)
108{
109 GList *gIter = NULL;
110
111 if (rsc->children) {
112 gIter = rsc->children;
113 for (; gIter != NULL; gIter = gIter->next) {
114 pe_resource_t *child = (pe_resource_t *) gIter->data;
115
116 check_promotable_actions(child, demoting, promoting);
117 }
118 return;
119 }
120
121 CRM_ASSERT(demoting != NULL);
122 CRM_ASSERT(promoting != NULL);
123
124 gIter = rsc->actions;
125 for (; gIter != NULL; gIter = gIter->next) {
126 pe_action_t *action = (pe_action_t *) gIter->data;
127
128 if (*promoting && *demoting) {
129 return;
130
131 } else if (pcmk_is_set(action->flags, pe_action_optional)) {
132 continue;
133
134 } else if (pcmk__str_eq(RSC_DEMOTE, action->task, pcmk__str_casei)) {
135 *demoting = TRUE;
136
137 } else if (pcmk__str_eq(RSC_PROMOTE, action->task, pcmk__str_casei)) {
138 *promoting = TRUE;
139 }
140 }
141}
142
143static void
144apply_promoted_location(pe_resource_t *child, GList *location_constraints,
145 pe_node_t *chosen)
146{
147 CRM_CHECK(child && chosen, return);
148 for (GList *gIter = location_constraints; gIter; gIter = gIter->next) {
149 pe_node_t *cons_node = NULL;
150 pe__location_t *cons = gIter->data;
151
152 if (cons->role_filter == RSC_ROLE_PROMOTED) {
153 pe_rsc_trace(child, "Applying %s to %s", cons->id, child->id);
154 cons_node = pe_find_node_id(cons->node_list_rh, chosen->details->id);
155 }
156 if (cons_node != NULL) {
157 int new_priority = pcmk__add_scores(child->priority,
158 cons_node->weight);
159
160 pe_rsc_trace(child, "\t%s[%s]: %d -> %d (%d)",
161 child->id, cons_node->details->uname, child->priority,
162 new_priority, cons_node->weight);
163 child->priority = new_priority;
164 }
165 }
166}
167
168static pe_node_t *
169guest_location(pe_node_t *guest_node)
170{
171 pe_resource_t *guest = guest_node->details->remote_rsc->container;
172
173 return guest->fns->location(guest, NULL, FALSE);
174}
175
176static pe_node_t *
177node_to_be_promoted_on(pe_resource_t *rsc)
178{
179 pe_node_t *node = NULL;
180 pe_node_t *local_node = NULL;
182 clone_variant_data_t *clone_data = NULL;
183
184#if 0
185 enum rsc_role_e role = RSC_ROLE_UNKNOWN;
186
187 role = rsc->fns->state(rsc, FALSE);
188 crm_info("%s role: %s", rsc->id, role2text(role));
189#endif
190
191 if (rsc->children) {
192 GList *gIter = rsc->children;
193
194 for (; gIter != NULL; gIter = gIter->next) {
195 pe_resource_t *child = (pe_resource_t *) gIter->data;
196
197 if (node_to_be_promoted_on(child) == NULL) {
198 pe_rsc_trace(rsc, "Child %s of %s can't be promoted", child->id, rsc->id);
199 return NULL;
200 }
201 }
202 }
203
204 node = rsc->fns->location(rsc, NULL, FALSE);
205 if (node == NULL) {
206 pe_rsc_trace(rsc, "%s cannot be promoted: not allocated", rsc->id);
207 return NULL;
208
209 } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
210 if (rsc->fns->state(rsc, TRUE) == RSC_ROLE_PROMOTED) {
211 crm_notice("Forcing unmanaged instance %s to remain promoted on %s",
212 rsc->id, node->details->uname);
213
214 } else {
215 return NULL;
216 }
217
218 } else if (rsc->priority < 0) {
219 pe_rsc_trace(rsc, "%s cannot be promoted: preference: %d",
220 rsc->id, rsc->priority);
221 return NULL;
222
223 } else if (!pcmk__node_available(node)) {
224 crm_trace("Node can't run any resources: %s", node->details->uname);
225 return NULL;
226
227 /* @TODO It's possible this check should be done in pcmk__node_available()
228 * instead. We should investigate all its callers to figure out whether that
229 * would be a good idea.
230 */
231 } else if (pe__is_guest_node(node) && (guest_location(node) == NULL)) {
232 pe_rsc_trace(rsc, "%s cannot be promoted: guest %s not allocated",
233 rsc->id, node->details->remote_rsc->container->id);
234 return NULL;
235 }
236
237 get_clone_variant_data(clone_data, parent);
238 local_node = pe_hash_table_lookup(parent->allowed_nodes, node->details->id);
239
240 if (local_node == NULL) {
241 crm_err("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
242 return NULL;
243
244 } else if ((local_node->count < clone_data->promoted_node_max)
245 || !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
246 return local_node;
247
248 } else {
249 pe_rsc_trace(rsc, "%s cannot be promoted on %s: node full",
250 rsc->id, node->details->uname);
251 }
252
253 return NULL;
254}
255
256static gint
257sort_promotable_instance(gconstpointer a, gconstpointer b, gpointer data_set)
258{
259 int rc;
260 enum rsc_role_e role1 = RSC_ROLE_UNKNOWN;
261 enum rsc_role_e role2 = RSC_ROLE_UNKNOWN;
262
263 const pe_resource_t *resource1 = (const pe_resource_t *)a;
264 const pe_resource_t *resource2 = (const pe_resource_t *)b;
265
266 CRM_ASSERT(resource1 != NULL);
267 CRM_ASSERT(resource2 != NULL);
268
269 role1 = resource1->fns->state(resource1, TRUE);
270 role2 = resource2->fns->state(resource2, TRUE);
271
272 rc = sort_rsc_index(a, b);
273 if (rc != 0) {
274 crm_trace("%s %c %s (index)", resource1->id, rc < 0 ? '<' : '>', resource2->id);
275 return rc;
276 }
277
278 if (role1 > role2) {
279 crm_trace("%s %c %s (role)", resource1->id, '<', resource2->id);
280 return -1;
281
282 } else if (role1 < role2) {
283 crm_trace("%s %c %s (role)", resource1->id, '>', resource2->id);
284 return 1;
285 }
286
287 return sort_clone_instance(a, b, data_set);
288}
289
290static void
291promotion_order(pe_resource_t *rsc, pe_working_set_t *data_set)
292{
293 GList *gIter = NULL;
294 pe_node_t *node = NULL;
295 pe_node_t *chosen = NULL;
296 clone_variant_data_t *clone_data = NULL;
297 char score[33];
298 size_t len = sizeof(score);
299
300 get_clone_variant_data(clone_data, rsc);
301
302 if (clone_data->added_promoted_constraints) {
303 return;
304 }
305 clone_data->added_promoted_constraints = true;
306 pe_rsc_trace(rsc, "Merging weights for %s", rsc->id);
308
309 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
310 pe_resource_t *child = (pe_resource_t *) gIter->data;
311
312 pe_rsc_trace(rsc, "Sort index: %s = %d", child->id, child->sort_index);
313 }
314 pe__show_node_weights(true, rsc, "Before", rsc->allowed_nodes, data_set);
315
316 gIter = rsc->children;
317 for (; gIter != NULL; gIter = gIter->next) {
318 pe_resource_t *child = (pe_resource_t *) gIter->data;
319
320 chosen = child->fns->location(child, NULL, FALSE);
321 if (chosen == NULL || child->sort_index < 0) {
322 pe_rsc_trace(rsc, "Skipping %s", child->id);
323 continue;
324 }
325
326 node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
327 CRM_ASSERT(node != NULL);
328 // Add promotion preferences and rsc_location scores when role=Promoted
329 score2char_stack(child->sort_index, score, len);
330 pe_rsc_trace(rsc, "Adding %s to %s from %s", score,
331 node->details->uname, child->id);
332 node->weight = pcmk__add_scores(child->sort_index, node->weight);
333 }
334
335 pe__show_node_weights(true, rsc, "Middle", rsc->allowed_nodes, data_set);
336
337 gIter = rsc->rsc_cons;
338 for (; gIter != NULL; gIter = gIter->next) {
339 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
340
341 /* (Re-)add location preferences of resources that a promoted instance
342 * should/must be colocated with.
343 */
344 if (constraint->dependent_role == RSC_ROLE_PROMOTED) {
345 enum pe_weights flags = constraint->score == INFINITY ? 0 : pe_weights_rollback;
346
347 pe_rsc_trace(rsc, "RHS: %s with %s: %d",
348 constraint->dependent->id, constraint->primary->id,
349 constraint->score);
350 rsc->allowed_nodes = constraint->primary->cmds->merge_weights(
351 constraint->primary, rsc->id, rsc->allowed_nodes,
352 constraint->node_attribute,
353 constraint->score / (float) INFINITY, flags);
354 }
355 }
356
357 gIter = rsc->rsc_cons_lhs;
358 for (; gIter != NULL; gIter = gIter->next) {
359 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
360
361 if (!pcmk__colocation_has_influence(constraint, NULL)) {
362 continue;
363 }
364
365 /* (Re-)add location preferences of resources that wish to be colocated
366 * with a promoted instance.
367 */
368 if (constraint->primary_role == RSC_ROLE_PROMOTED) {
369 pe_rsc_trace(rsc, "LHS: %s with %s: %d",
370 constraint->dependent->id, constraint->primary->id,
371 constraint->score);
372 rsc->allowed_nodes = constraint->dependent->cmds->merge_weights(
373 constraint->dependent, rsc->id, rsc->allowed_nodes,
374 constraint->node_attribute,
375 constraint->score / (float) INFINITY,
377 }
378 }
379
380 gIter = rsc->rsc_tickets;
381 for (; gIter != NULL; gIter = gIter->next) {
382 rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) gIter->data;
383
384 if ((rsc_ticket->role_lh == RSC_ROLE_PROMOTED)
385 && (rsc_ticket->ticket->granted == FALSE || rsc_ticket->ticket->standby)) {
386 resource_location(rsc, NULL, -INFINITY, "__stateful_without_ticket__", data_set);
387 }
388 }
389
390 pe__show_node_weights(true, rsc, "After", rsc->allowed_nodes, data_set);
391
392 /* write them back and sort */
393
394 gIter = rsc->children;
395 for (; gIter != NULL; gIter = gIter->next) {
396 pe_resource_t *child = (pe_resource_t *) gIter->data;
397
398 chosen = child->fns->location(child, NULL, FALSE);
399 if (!pcmk_is_set(child->flags, pe_rsc_managed)
400 && (child->next_role == RSC_ROLE_PROMOTED)) {
401 child->sort_index = INFINITY;
402
403 } else if (chosen == NULL || child->sort_index < 0) {
404 pe_rsc_trace(rsc, "%s: %d", child->id, child->sort_index);
405
406 } else {
407 node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
408 CRM_ASSERT(node != NULL);
409
410 child->sort_index = node->weight;
411 }
412 pe_rsc_trace(rsc, "Set sort index: %s = %d", child->id, child->sort_index);
413 }
414
415 rsc->children = g_list_sort_with_data(rsc->children,
416 sort_promotable_instance, data_set);
418}
419
420static gboolean
421filter_anonymous_instance(pe_resource_t *rsc, const pe_node_t *node)
422{
423 GList *rIter = NULL;
424 char *key = clone_strip(rsc->id);
426
427 for (rIter = parent->children; rIter; rIter = rIter->next) {
428 /* If there is an active instance on the node, only it receives the
429 * promotion score. Use ->find_rsc() in case this is a cloned group.
430 */
431 pe_resource_t *child = rIter->data;
432 pe_resource_t *active = parent->fns->find_rsc(child, key, node, pe_find_clone|pe_find_current);
433
434 if(rsc == active) {
435 pe_rsc_trace(rsc, "Found %s for %s active on %s: done", active->id, key, node->details->uname);
436 free(key);
437 return TRUE;
438 } else if(active) {
439 pe_rsc_trace(rsc, "Found %s for %s on %s: not %s", active->id, key, node->details->uname, rsc->id);
440 free(key);
441 return FALSE;
442 } else {
443 pe_rsc_trace(rsc, "%s on %s: not active", key, node->details->uname);
444 }
445 }
446
447 for (rIter = parent->children; rIter; rIter = rIter->next) {
448 pe_resource_t *child = rIter->data;
449
450 /*
451 * We know it's not running, but any score will still count if
452 * the instance has been probed on $node
453 *
454 * Again use ->find_rsc() because we might be a cloned group
455 * and knowing that other members of the group are known here
456 * implies nothing
457 */
458 rsc = parent->fns->find_rsc(child, key, NULL, pe_find_clone);
459 CRM_LOG_ASSERT(rsc);
460 if(rsc) {
461 pe_rsc_trace(rsc, "Checking %s for %s on %s", rsc->id, key, node->details->uname);
462 if (g_hash_table_lookup(rsc->known_on, node->details->id)) {
463 free(key);
464 return TRUE;
465 }
466 }
467 }
468 free(key);
469 return FALSE;
470}
471
472static const char *
473lookup_promotion_score(pe_resource_t *rsc, const pe_node_t *node, const char *name)
474{
475 const char *attr_value = NULL;
476
477 if (node && name) {
478 char *attr_name = pcmk_promotion_score_name(name);
479
480 attr_value = pe_node_attribute_calculated(node, attr_name, rsc);
481 free(attr_name);
482 }
483 return attr_value;
484}
485
486static int
487promotion_score(pe_resource_t *rsc, const pe_node_t *node, int not_set_value)
488{
489 char *name = rsc->id;
490 const char *attr_value = NULL;
491 int score = not_set_value;
492 pe_node_t *match = NULL;
493
494 CRM_CHECK(node != NULL, return not_set_value);
495
496 if (rsc->children) {
497 GList *gIter = rsc->children;
498
499 for (; gIter != NULL; gIter = gIter->next) {
500 pe_resource_t *child = (pe_resource_t *) gIter->data;
501 int c_score = promotion_score(child, node, not_set_value);
502
503 if (score == not_set_value) {
504 score = c_score;
505 } else {
506 score += c_score;
507 }
508 }
509 return score;
510 }
511
513 && filter_anonymous_instance(rsc, node)) {
514
515 pe_rsc_trace(rsc, "Anonymous clone %s is allowed on %s", rsc->id, node->details->uname);
516
517 } else if (rsc->running_on || g_hash_table_size(rsc->known_on)) {
518 /* If we've probed and/or started the resource anywhere, consider
519 * promotion scores only from nodes where we know the status. However,
520 * if the status of all nodes is unknown (e.g. cluster startup),
521 * skip this code, to make sure we take into account any permanent
522 * promotion scores set previously.
523 */
524 pe_node_t *known = pe_hash_table_lookup(rsc->known_on, node->details->id);
525
526 match = pe_find_node_id(rsc->running_on, node->details->id);
527 if ((match == NULL) && (known == NULL)) {
528 pe_rsc_trace(rsc, "skipping %s (aka. %s) promotion score on %s because inactive",
529 rsc->id, rsc->clone_name, node->details->uname);
530 return score;
531 }
532 }
533
534 match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
535 if (match == NULL) {
536 return score;
537
538 } else if (match->weight < 0) {
539 pe_rsc_trace(rsc, "%s on %s has score: %d - ignoring",
540 rsc->id, match->details->uname, match->weight);
541 return score;
542 }
543
544 if (rsc->clone_name) {
545 /* Use the name the lrm knows this resource as,
546 * since that's what crm_attribute --promotion would have used
547 */
548 name = rsc->clone_name;
549 }
550
551 attr_value = lookup_promotion_score(rsc, node, name);
552 pe_rsc_trace(rsc, "promotion score for %s on %s = %s",
553 name, node->details->uname, crm_str(attr_value));
554
555 if ((attr_value == NULL) && !pcmk_is_set(rsc->flags, pe_rsc_unique)) {
556 /* If we don't have any LRM history yet, we won't have clone_name -- in
557 * that case, for anonymous clones, try the resource name without any
558 * instance number.
559 */
560 name = clone_strip(rsc->id);
561 if (strcmp(rsc->id, name)) {
562 attr_value = lookup_promotion_score(rsc, node, name);
563 pe_rsc_trace(rsc, "stripped promotion score for %s on %s = %s",
564 name, node->details->uname, crm_str(attr_value));
565 }
566 free(name);
567 }
568
569 if (attr_value != NULL) {
570 score = char2score(attr_value);
571 }
572
573 return score;
574}
575
576void
578{
579 int score, new_score;
580 GList *gIter = rsc->children;
581 clone_variant_data_t *clone_data = NULL;
582
583 get_clone_variant_data(clone_data, rsc);
584
585 if (clone_data->added_promotion_scores) {
586 /* Make sure we only do this once */
587 return;
588 }
589
590 clone_data->added_promotion_scores = true;
591
592 for (; gIter != NULL; gIter = gIter->next) {
593 GHashTableIter iter;
594 pe_node_t *node = NULL;
595 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
596
597 g_hash_table_iter_init(&iter, child_rsc->allowed_nodes);
598 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
599 if (!pcmk__node_available(node)) {
600 /* This node will never be promoted, so don't apply the
601 * promotion score, as that may lead to clone shuffling.
602 */
603 continue;
604 }
605
606 score = promotion_score(child_rsc, node, 0);
607 if (score > 0) {
608 new_score = pcmk__add_scores(node->weight, score);
609 if (new_score != node->weight) {
610 pe_rsc_trace(rsc, "\t%s: Updating preference for %s (%d->%d)",
611 child_rsc->id, node->details->uname, node->weight, new_score);
612 node->weight = new_score;
613 }
614 }
615
616 new_score = QB_MAX(child_rsc->priority, score);
617 if (new_score != child_rsc->priority) {
618 pe_rsc_trace(rsc, "\t%s: Updating priority (%d->%d)",
619 child_rsc->id, child_rsc->priority, new_score);
620 child_rsc->priority = new_score;
621 }
622 }
623 }
624}
625
626static void
627set_role_unpromoted(pe_resource_t *rsc, bool current)
628{
629 GList *gIter = rsc->children;
630
631 if (current) {
632 if (rsc->role == RSC_ROLE_STARTED) {
634 }
635
636 } else {
637 GList *allocated = NULL;
638
639 rsc->fns->location(rsc, &allocated, FALSE);
641 "unpromoted instance");
642 g_list_free(allocated);
643 }
644
645 for (; gIter != NULL; gIter = gIter->next) {
646 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
647
648 set_role_unpromoted(child_rsc, current);
649 }
650}
651
652static void
653set_role_promoted(pe_resource_t *rsc, gpointer user_data)
654{
655 if (rsc->next_role == RSC_ROLE_UNKNOWN) {
656 pe__set_next_role(rsc, RSC_ROLE_PROMOTED, "promoted instance");
657 }
658
659 g_list_foreach(rsc->children, (GFunc) set_role_promoted, NULL);
660}
661
662pe_node_t *
664{
665 int promoted = 0;
666 GList *gIter = NULL;
667 GList *gIter2 = NULL;
668 GHashTableIter iter;
669 pe_node_t *node = NULL;
670 pe_node_t *chosen = NULL;
671 enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
672 char score[33];
673 size_t len = sizeof(score);
674 clone_variant_data_t *clone_data = NULL;
675
676 get_clone_variant_data(clone_data, rsc);
677
678 // Repurpose count to track the number of promoted instances allocated
679 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
680 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
681 node->count = 0;
682 }
683
684 /*
685 * assign priority
686 */
687 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
688 GList *list = NULL;
689 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
690
691 pe_rsc_trace(rsc, "Assigning priority for %s: %s", child_rsc->id,
692 role2text(child_rsc->next_role));
693
694 if (child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) {
695 set_role_unpromoted(child_rsc, true);
696 }
697
698 chosen = child_rsc->fns->location(child_rsc, &list, FALSE);
699 if (pcmk__list_of_multiple(list)) {
700 pcmk__config_err("Cannot promote non-colocated child %s",
701 child_rsc->id);
702 }
703
704 g_list_free(list);
705 if (chosen == NULL) {
706 continue;
707 }
708
709 next_role = child_rsc->fns->state(child_rsc, FALSE);
710 switch (next_role) {
711 case RSC_ROLE_STARTED:
712 case RSC_ROLE_UNKNOWN:
713 /*
714 * Default to -1 if no value is set
715 *
716 * This allows instances eligible for promotion to be specified
717 * based solely on rsc_location constraints,
718 * but prevents anyone from being promoted if
719 * neither a constraint nor a promotion score is present
720 */
721 child_rsc->priority = promotion_score(child_rsc, chosen, -1);
722 break;
723
725 case RSC_ROLE_STOPPED:
726 child_rsc->priority = -INFINITY;
727 break;
729 /* We will arrive here if we're re-creating actions after a stonith
730 */
731 break;
732 default:
733 CRM_CHECK(FALSE /* unhandled */ ,
734 crm_err("Unknown resource role: %d for %s", next_role, child_rsc->id));
735 }
736
737 apply_promoted_location(child_rsc, child_rsc->rsc_location, chosen);
738 apply_promoted_location(child_rsc, rsc->rsc_location, chosen);
739
740 for (gIter2 = child_rsc->rsc_cons; gIter2 != NULL; gIter2 = gIter2->next) {
741 pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter2->data;
742
743 child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->primary, cons,
744 data_set);
745 }
746
747 child_rsc->sort_index = child_rsc->priority;
748 pe_rsc_trace(rsc, "Assigning priority for %s: %d", child_rsc->id, child_rsc->priority);
749
750 if (next_role == RSC_ROLE_PROMOTED) {
751 child_rsc->sort_index = INFINITY;
752 }
753 }
754
755 pe__show_node_weights(true, rsc, "Pre merge", rsc->allowed_nodes, data_set);
756 promotion_order(rsc, data_set);
757
758 // Choose the first N eligible instances to be promoted
759 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
760 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
761 score2char_stack(child_rsc->sort_index, score, len);
762
763 chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
765 if (data_set->priv != NULL) {
767 out->message(out, "promotion-score", child_rsc, chosen, score);
768 }
769
770 } else {
771 pe_rsc_trace(rsc, "%s promotion score on %s: %s", child_rsc->id,
772 (chosen? chosen->details->uname : "none"), score);
773 }
774
775 chosen = NULL; /* nuke 'chosen' so that we don't promote more than the
776 * required number of instances
777 */
778
779 if (child_rsc->sort_index < 0) {
780 pe_rsc_trace(rsc, "Not supposed to promote child: %s", child_rsc->id);
781
782 } else if ((promoted < clone_data->promoted_max)
783 || !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
784 chosen = node_to_be_promoted_on(child_rsc);
785 }
786
787 pe_rsc_debug(rsc, "%s promotion score: %d", child_rsc->id, child_rsc->priority);
788
789 if (chosen == NULL) {
790 set_role_unpromoted(child_rsc, false);
791 continue;
792
793 } else if ((child_rsc->role < RSC_ROLE_PROMOTED)
796 crm_notice("Resource %s cannot be elevated from %s to %s: no-quorum-policy=freeze",
797 child_rsc->id, role2text(child_rsc->role), role2text(child_rsc->next_role));
798 set_role_unpromoted(child_rsc, false);
799 continue;
800 }
801
802 chosen->count++;
803 pe_rsc_info(rsc, "Promoting %s (%s %s)",
804 child_rsc->id, role2text(child_rsc->role), chosen->details->uname);
805 set_role_promoted(child_rsc, NULL);
806 promoted++;
807 }
808
809 pe_rsc_info(rsc, "%s: Promoted %d instances of a possible %d",
810 rsc->id, promoted, clone_data->promoted_max);
811
812 return NULL;
813}
814
815void
817{
818 pe_action_t *action = NULL;
819 GList *gIter = rsc->children;
820 pe_action_t *action_complete = NULL;
821 gboolean any_promoting = FALSE;
822 gboolean any_demoting = FALSE;
823 pe_resource_t *last_promote_rsc = NULL;
824 pe_resource_t *last_demote_rsc = NULL;
825
826 clone_variant_data_t *clone_data = NULL;
827
828 get_clone_variant_data(clone_data, rsc);
829
830 pe_rsc_debug(rsc, "Creating actions for %s", rsc->id);
831
832 for (; gIter != NULL; gIter = gIter->next) {
833 gboolean child_promoting = FALSE;
834 gboolean child_demoting = FALSE;
835 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
836
837 pe_rsc_trace(rsc, "Creating actions for %s", child_rsc->id);
838 child_rsc->cmds->create_actions(child_rsc, data_set);
839 check_promotable_actions(child_rsc, &child_demoting, &child_promoting);
840
841 any_demoting = any_demoting || child_demoting;
842 any_promoting = any_promoting || child_promoting;
843 pe_rsc_trace(rsc, "Created actions for %s: %d %d", child_rsc->id, child_promoting,
844 child_demoting);
845 }
846
847 /* promote */
848 action = pcmk__new_rsc_pseudo_action(rsc, RSC_PROMOTE, !any_promoting,
849 true);
850 action_complete = pcmk__new_rsc_pseudo_action(rsc, RSC_PROMOTED,
851 !any_promoting, true);
852 action_complete->priority = INFINITY;
853
854 child_promoting_constraints(clone_data, pe_order_optional,
855 rsc, NULL, last_promote_rsc, data_set);
856
857 if (clone_data->promote_notify == NULL) {
858 clone_data->promote_notify = pcmk__clone_notif_pseudo_ops(rsc,
860 action,
861 action_complete);
862 }
863
864 /* demote */
865 action = pcmk__new_rsc_pseudo_action(rsc, RSC_DEMOTE, !any_demoting, true);
866 action_complete = pcmk__new_rsc_pseudo_action(rsc, RSC_DEMOTED,
867 !any_demoting, true);
868 action_complete->priority = INFINITY;
869
870 child_demoting_constraints(clone_data, pe_order_optional, rsc, NULL, last_demote_rsc, data_set);
871
872 if (clone_data->demote_notify == NULL) {
873 clone_data->demote_notify = pcmk__clone_notif_pseudo_ops(rsc,
875 action,
876 action_complete);
877
878 if (clone_data->promote_notify) {
879 /* If we ever wanted groups to have notifications we'd need to move this to native_internal_constraints() one day
880 * Requires exposing *_notify
881 */
882 order_actions(clone_data->stop_notify->post_done, clone_data->promote_notify->pre,
884 order_actions(clone_data->start_notify->post_done, clone_data->promote_notify->pre,
886 order_actions(clone_data->demote_notify->post_done, clone_data->promote_notify->pre,
888 order_actions(clone_data->demote_notify->post_done, clone_data->start_notify->pre,
890 order_actions(clone_data->demote_notify->post_done, clone_data->stop_notify->pre,
892 }
893 }
894
895 /* restore the correct priority */
896
897 gIter = rsc->children;
898 for (; gIter != NULL; gIter = gIter->next) {
899 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
900
901 child_rsc->priority = rsc->priority;
902 }
903}
904
905void
907{
908 /* global stopped before start */
911
912 /* global stopped before promote */
915
916 /* global demoted before start */
919
920 /* global started before promote */
923
924 /* global demoted before stop */
927
928 /* global demote before demoted */
931
932 /* global demoted before promote */
935}
936
937
938void
940{
941 GList *gIter = rsc->children;
942 pe_resource_t *last_rsc = NULL;
943 clone_variant_data_t *clone_data = NULL;
944
945 get_clone_variant_data(clone_data, rsc);
946
948
949 for (; gIter != NULL; gIter = gIter->next) {
950 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
951
952 /* child demote before promote */
953 pcmk__order_resource_actions(child_rsc, RSC_DEMOTE, child_rsc,
955
956 child_promoting_constraints(clone_data, pe_order_optional,
957 rsc, child_rsc, last_rsc, data_set);
958
959 child_demoting_constraints(clone_data, pe_order_optional,
960 rsc, child_rsc, last_rsc, data_set);
961
962 last_rsc = child_rsc;
963 }
964}
965
966static void
967node_hash_update_one(GHashTable * hash, pe_node_t * other, const char *attr, int score)
968{
969 GHashTableIter iter;
970 pe_node_t *node = NULL;
971 const char *value = NULL;
972
973 if (other == NULL) {
974 return;
975
976 } else if (attr == NULL) {
977 attr = CRM_ATTR_UNAME;
978 }
979
980 value = pe_node_attribute_raw(other, attr);
981 g_hash_table_iter_init(&iter, hash);
982 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
983 const char *tmp = pe_node_attribute_raw(node, attr);
984
985 if (pcmk__str_eq(value, tmp, pcmk__str_casei)) {
986 crm_trace("%s: %d + %d", node->details->uname, node->weight, other->weight);
987 node->weight = pcmk__add_scores(node->weight, score);
988 }
989 }
990}
991
992void
994 pcmk__colocation_t *constraint,
996{
997 GList *gIter = NULL;
998
999 if (pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
1000 GList *affected_nodes = NULL;
1001
1002 for (gIter = primary->children; gIter != NULL; gIter = gIter->next) {
1003 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1004 pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1005 enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, FALSE);
1006
1007 pe_rsc_trace(primary, "Processing: %s", child_rsc->id);
1008 if ((chosen != NULL) && (next_role == constraint->primary_role)) {
1009 pe_rsc_trace(primary, "Applying: %s %s %s %d", child_rsc->id,
1010 role2text(next_role), chosen->details->uname, constraint->score);
1011 if (constraint->score < INFINITY) {
1012 node_hash_update_one(dependent->allowed_nodes, chosen,
1013 constraint->node_attribute, constraint->score);
1014 }
1015 affected_nodes = g_list_prepend(affected_nodes, chosen);
1016 }
1017 }
1018
1019 /* Only do this if it's not a promoted-with-promoted colocation. Doing
1020 * this unconditionally would prevent unpromoted instances from being
1021 * started.
1022 */
1023 if ((constraint->dependent_role != RSC_ROLE_PROMOTED)
1024 || (constraint->primary_role != RSC_ROLE_PROMOTED)) {
1025
1026 if (constraint->score >= INFINITY) {
1027 node_list_exclude(dependent->allowed_nodes, affected_nodes,
1028 TRUE);
1029 }
1030 }
1031 g_list_free(affected_nodes);
1032
1033 } else if (constraint->dependent_role == RSC_ROLE_PROMOTED) {
1034 pe_resource_t *primary_instance;
1035
1036 primary_instance = find_compatible_child(dependent, primary,
1037 constraint->primary_role,
1038 FALSE, data_set);
1039 if ((primary_instance == NULL) && (constraint->score >= INFINITY)) {
1040 pe_rsc_trace(dependent, "%s can't be promoted %s",
1041 dependent->id, constraint->id);
1042 dependent->priority = -INFINITY;
1043
1044 } else if (primary_instance != NULL) {
1045 int new_priority = pcmk__add_scores(dependent->priority,
1046 constraint->score);
1047
1048 pe_rsc_debug(dependent, "Applying %s to %s",
1049 constraint->id, dependent->id);
1050 pe_rsc_debug(dependent, "\t%s: %d->%d",
1051 dependent->id, dependent->priority, new_priority);
1052 dependent->priority = new_priority;
1053 }
1054 }
1055
1056 return;
1057}
const char * parent
Definition: cib.c:25
const char * name
Definition: cib.c:24
uint64_t flags
Definition: remote.c:3
char * score2char_stack(int score, char *buf, size_t len)
Convert an integer score to a string, using a provided buffer.
Definition: scores.c:85
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:140
int char2score(const char *score)
Get the integer value of a score string.
Definition: scores.c:36
char * pcmk_promotion_score_name(const char *rsc_id)
Return the name of the node attribute used as a promotion score.
Definition: attrd_client.c:320
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:122
const char * role2text(enum rsc_role_e role)
Definition: common.c:454
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
@ RSC_ROLE_STARTED
Definition: common.h:95
@ RSC_ROLE_STOPPED
Definition: common.h:94
@ RSC_ROLE_PROMOTED
Definition: common.h:97
@ RSC_ROLE_UNKNOWN
Definition: common.h:93
@ RSC_ROLE_UNPROMOTED
Definition: common.h:96
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:913
enum crm_ais_msg_types type
Definition: cpg.c:3
#define RSC_PROMOTE
Definition: crm.h:207
#define RSC_DEMOTE
Definition: crm.h:209
#define RSC_STARTED
Definition: crm.h:202
#define RSC_STOPPED
Definition: crm.h:205
#define RSC_START
Definition: crm.h:201
#define INFINITY
Definition: crm.h:99
#define RSC_STOP
Definition: crm.h:204
#define RSC_PROMOTED
Definition: crm.h:208
#define CRM_ATTR_UNAME
Definition: crm.h:114
#define RSC_DEMOTED
Definition: crm.h:210
G_GNUC_INTERNAL notify_data_t * pcmk__clone_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
#define pcmk__order_resource_actions(lh_rsc, lh_task, rh_rsc, rh_task, flags, data_set)
#define pcmk__order_starts(rsc1, rsc2, type, data_set)
G_GNUC_INTERNAL pe_action_t * pcmk__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
G_GNUC_INTERNAL bool pcmk__node_available(const pe_node_t *node)
#define crm_str(x)
Definition: logging.h:384
#define crm_info(fmt, args...)
Definition: logging.h:361
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:210
#define crm_notice(fmt, args...)
Definition: logging.h:360
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
#define crm_err(fmt, args...)
Definition: logging.h:358
#define crm_trace(fmt, args...)
Definition: logging.h:364
#define pcmk__config_err(fmt...)
pe_working_set_t * data_set
const char * action
Definition: pcmk_fence.c:29
void pcmk__add_promotion_scores(pe_resource_t *rsc)
void promotable_colocation_rh(pe_resource_t *dependent, pe_resource_t *primary, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
void promotable_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
void create_promotable_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
bool pcmk__is_daemon
Definition: logging.c:47
void promote_demote_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
pe_node_t * pcmk__set_instance_roles(pe_resource_t *rsc, pe_working_set_t *data_set)
pe_resource_t * find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current, pe_working_set_t *data_set)
pe_weights
@ pe_weights_positive
@ pe_weights_rollback
@ no_quorum_freeze
Definition: pe_types.h:64
#define pe_flag_have_quorum
Definition: pe_types.h:95
#define pe_rsc_managed
Definition: pe_types.h:257
pe_ordering
Definition: pe_types.h:497
@ pe_order_implies_first_printed
Definition: pe_types.h:526
@ pe_order_implies_then_printed
Definition: pe_types.h:527
@ pe_order_optional
Definition: pe_types.h:499
#define pe_rsc_provisional
Definition: pe_types.h:266
#define pe_rsc_unique
Definition: pe_types.h:262
#define pe_flag_show_scores
Definition: pe_types.h:134
@ pe_action_optional
Definition: pe_types.h:308
@ pe_find_clone
match only clone instances
Definition: pe_types.h:87
@ pe_find_current
match resource active on specified node
Definition: pe_types.h:88
#define pe_rsc_merging
Definition: pe_types.h:268
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:355
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:160
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition: common.c:560
void pe__set_next_role(pe_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition: complex.c:1126
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:55
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:21
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1906
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:22
void resource_location(pe_resource_t *rsc, pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:1692
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:49
gint sort_rsc_index(gconstpointer a, gconstpointer b)
Definition: utils.c:334
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:20
const char * pe_node_attribute_calculated(const pe_node_t *node, const char *name, const pe_resource_t *rsc)
Definition: common.c:521
char * clone_strip(const char *last_rsc_id)
Definition: unpack.c:1635
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
#define CRM_ASSERT(expr)
Definition: results.h:42
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition: status.c:427
@ pcmk__str_casei
pe_resource_t * primary
const char * node_attribute
pe_resource_t * dependent
This structure contains everything that makes up a single output formatter.
int(* message)(pcmk__output_t *out, const char *message_id,...)
enum rsc_role_e role_filter
Definition: internal.h:174
int priority
Definition: pe_types.h:422
int weight
Definition: pe_types.h:249
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
pe_resource_t * remote_rsc
Definition: pe_types.h:237
GList * running_on
Definition: pe_types.h:380
GList * actions
Definition: pe_types.h:373
GList * rsc_location
Definition: pe_types.h:372
GList * rsc_cons
Definition: pe_types.h:371
GList * rsc_cons_lhs
Definition: pe_types.h:370
GList * children
Definition: pe_types.h:391
GHashTable * known_on
Definition: pe_types.h:381
pe_resource_t * container
Definition: pe_types.h:394
char * clone_name
Definition: pe_types.h:337
char * id
Definition: pe_types.h:336
GHashTable * allowed_nodes
Definition: pe_types.h:382
int sort_index
Definition: pe_types.h:356
GList * rsc_tickets
Definition: pe_types.h:374
unsigned long long flags
Definition: pe_types.h:362
resource_alloc_functions_t * cmds
Definition: pe_types.h:348
enum rsc_role_e next_role
Definition: pe_types.h:385
enum rsc_role_e role
Definition: pe_types.h:384
resource_object_functions_t * fns
Definition: pe_types.h:347
gboolean standby
Definition: pe_types.h:474
gboolean granted
Definition: pe_types.h:472
unsigned long long flags
Definition: pe_types.h:153
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:156
void(* rsc_colocation_lh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
GHashTable *(* merge_weights)(pe_resource_t *, const char *, GHashTable *, const char *, float, enum pe_weights)
void(* create_actions)(pe_resource_t *, pe_working_set_t *)
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition: pe_types.h:54
pe_ticket_t * ticket