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