pacemaker 2.1.6-6fdc9deea29
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_colocation.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2023 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 <stdbool.h>
13#include <glib.h>
14
15#include <crm/crm.h>
16#include <crm/pengine/status.h>
17#include <pacemaker-internal.h>
18
19#include "crm/common/util.h"
21#include "crm/msg_xml.h"
23
24#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name) do { \
25 __rsc = pcmk__find_constraint_resource(data_set->resources, __name); \
26 if (__rsc == NULL) { \
27 pcmk__config_err("%s: No resource found for %s", __set, __name); \
28 return; \
29 } \
30 } while(0)
31
32// Used to temporarily mark a node as unusable
33#define INFINITY_HACK (INFINITY * -100)
34
35static gint
36cmp_dependent_priority(gconstpointer a, gconstpointer b)
37{
38 const pcmk__colocation_t *rsc_constraint1 = (const pcmk__colocation_t *) a;
39 const pcmk__colocation_t *rsc_constraint2 = (const pcmk__colocation_t *) b;
40
41 if (a == NULL) {
42 return 1;
43 }
44 if (b == NULL) {
45 return -1;
46 }
47
48 CRM_ASSERT(rsc_constraint1->dependent != NULL);
49 CRM_ASSERT(rsc_constraint1->primary != NULL);
50
51 if (rsc_constraint1->dependent->priority > rsc_constraint2->dependent->priority) {
52 return -1;
53 }
54
55 if (rsc_constraint1->dependent->priority < rsc_constraint2->dependent->priority) {
56 return 1;
57 }
58
59 /* Process clones before primitives and groups */
60 if (rsc_constraint1->dependent->variant > rsc_constraint2->dependent->variant) {
61 return -1;
62 }
63 if (rsc_constraint1->dependent->variant < rsc_constraint2->dependent->variant) {
64 return 1;
65 }
66
67 /* @COMPAT scheduler <2.0.0: Process promotable clones before nonpromotable
68 * clones (probably unnecessary, but avoids having to update regression
69 * tests)
70 */
71 if (rsc_constraint1->dependent->variant == pe_clone) {
72 if (pcmk_is_set(rsc_constraint1->dependent->flags, pe_rsc_promotable)
73 && !pcmk_is_set(rsc_constraint2->dependent->flags, pe_rsc_promotable)) {
74 return -1;
75 } else if (!pcmk_is_set(rsc_constraint1->dependent->flags, pe_rsc_promotable)
76 && pcmk_is_set(rsc_constraint2->dependent->flags, pe_rsc_promotable)) {
77 return 1;
78 }
79 }
80
81 return strcmp(rsc_constraint1->dependent->id,
82 rsc_constraint2->dependent->id);
83}
84
85static gint
86cmp_primary_priority(gconstpointer a, gconstpointer b)
87{
88 const pcmk__colocation_t *rsc_constraint1 = (const pcmk__colocation_t *) a;
89 const pcmk__colocation_t *rsc_constraint2 = (const pcmk__colocation_t *) b;
90
91 if (a == NULL) {
92 return 1;
93 }
94 if (b == NULL) {
95 return -1;
96 }
97
98 CRM_ASSERT(rsc_constraint1->dependent != NULL);
99 CRM_ASSERT(rsc_constraint1->primary != NULL);
100
101 if (rsc_constraint1->primary->priority > rsc_constraint2->primary->priority) {
102 return -1;
103 }
104
105 if (rsc_constraint1->primary->priority < rsc_constraint2->primary->priority) {
106 return 1;
107 }
108
109 /* Process clones before primitives and groups */
110 if (rsc_constraint1->primary->variant > rsc_constraint2->primary->variant) {
111 return -1;
112 } else if (rsc_constraint1->primary->variant < rsc_constraint2->primary->variant) {
113 return 1;
114 }
115
116 /* @COMPAT scheduler <2.0.0: Process promotable clones before nonpromotable
117 * clones (probably unnecessary, but avoids having to update regression
118 * tests)
119 */
120 if (rsc_constraint1->primary->variant == pe_clone) {
121 if (pcmk_is_set(rsc_constraint1->primary->flags, pe_rsc_promotable)
122 && !pcmk_is_set(rsc_constraint2->primary->flags, pe_rsc_promotable)) {
123 return -1;
124 } else if (!pcmk_is_set(rsc_constraint1->primary->flags, pe_rsc_promotable)
125 && pcmk_is_set(rsc_constraint2->primary->flags, pe_rsc_promotable)) {
126 return 1;
127 }
128 }
129
130 return strcmp(rsc_constraint1->primary->id, rsc_constraint2->primary->id);
131}
132
142void
143pcmk__add_this_with(GList **list, const pcmk__colocation_t *colocation)
144{
145 CRM_ASSERT((list != NULL) && (colocation != NULL));
146
147 crm_trace("Adding colocation %s (%s with %s%s%s @%d) "
148 "to 'this with' list",
149 colocation->id, colocation->dependent->id,
150 colocation->primary->id,
151 (colocation->node_attribute == NULL)? "" : " using ",
152 pcmk__s(colocation->node_attribute, ""),
153 colocation->score);
154 *list = g_list_insert_sorted(*list, (gpointer) colocation,
155 cmp_primary_priority);
156}
157
167void
168pcmk__add_this_with_list(GList **list, GList *addition)
169{
170 CRM_CHECK((list != NULL), return);
171
172 if (*list == NULL) { // Trivial case for efficiency
173 crm_trace("Copying %u 'this with' colocations to new list",
174 g_list_length(addition));
175 *list = g_list_copy(addition);
176 } else {
177 while (addition != NULL) {
178 pcmk__add_this_with(list, addition->data);
179 addition = addition->next;
180 }
181 }
182}
183
193void
194pcmk__add_with_this(GList **list, const pcmk__colocation_t *colocation)
195{
196 CRM_ASSERT((list != NULL) && (colocation != NULL));
197
198 crm_trace("Adding colocation %s (%s with %s%s%s @%d) "
199 "to 'with this' list",
200 colocation->id, colocation->dependent->id,
201 colocation->primary->id,
202 (colocation->node_attribute == NULL)? "" : " using ",
203 pcmk__s(colocation->node_attribute, ""),
204 colocation->score);
205 *list = g_list_insert_sorted(*list, (gpointer) colocation,
206 cmp_dependent_priority);
207}
208
218void
219pcmk__add_with_this_list(GList **list, GList *addition)
220{
221 CRM_CHECK((list != NULL), return);
222
223 if (*list == NULL) { // Trivial case for efficiency
224 crm_trace("Copying %u 'with this' colocations to new list",
225 g_list_length(addition));
226 *list = g_list_copy(addition);
227 } else {
228 while (addition != NULL) {
229 pcmk__add_with_this(list, addition->data);
230 addition = addition->next;
231 }
232 }
233}
234
244static void
245anti_colocation_order(pe_resource_t *first_rsc, int first_role,
246 pe_resource_t *then_rsc, int then_role)
247{
248 const char *first_tasks[] = { NULL, NULL };
249 const char *then_tasks[] = { NULL, NULL };
250
251 /* Actions to make first_rsc lose first_role */
252 if (first_role == RSC_ROLE_PROMOTED) {
253 first_tasks[0] = CRMD_ACTION_DEMOTE;
254
255 } else {
256 first_tasks[0] = CRMD_ACTION_STOP;
257
258 if (first_role == RSC_ROLE_UNPROMOTED) {
259 first_tasks[1] = CRMD_ACTION_PROMOTE;
260 }
261 }
262
263 /* Actions to make then_rsc gain then_role */
264 if (then_role == RSC_ROLE_PROMOTED) {
265 then_tasks[0] = CRMD_ACTION_PROMOTE;
266
267 } else {
268 then_tasks[0] = CRMD_ACTION_START;
269
270 if (then_role == RSC_ROLE_UNPROMOTED) {
271 then_tasks[1] = CRMD_ACTION_DEMOTE;
272 }
273 }
274
275 for (int first_lpc = 0;
276 (first_lpc <= 1) && (first_tasks[first_lpc] != NULL); first_lpc++) {
277
278 for (int then_lpc = 0;
279 (then_lpc <= 1) && (then_tasks[then_lpc] != NULL); then_lpc++) {
280
281 pcmk__order_resource_actions(first_rsc, first_tasks[first_lpc],
282 then_rsc, then_tasks[then_lpc],
284 }
285 }
286}
287
302void
303pcmk__new_colocation(const char *id, const char *node_attr, int score,
304 pe_resource_t *dependent, pe_resource_t *primary,
305 const char *dependent_role, const char *primary_role,
306 bool influence, pe_working_set_t *data_set)
307{
308 pcmk__colocation_t *new_con = NULL;
309
310 if (score == 0) {
311 crm_trace("Ignoring colocation '%s' because score is 0", id);
312 return;
313 }
314 if ((dependent == NULL) || (primary == NULL)) {
315 pcmk__config_err("Ignoring colocation '%s' because resource "
316 "does not exist", id);
317 return;
318 }
319
320 new_con = calloc(1, sizeof(pcmk__colocation_t));
321 if (new_con == NULL) {
322 return;
323 }
324
325 if (pcmk__str_eq(dependent_role, RSC_ROLE_STARTED_S,
327 dependent_role = RSC_ROLE_UNKNOWN_S;
328 }
329
330 if (pcmk__str_eq(primary_role, RSC_ROLE_STARTED_S,
332 primary_role = RSC_ROLE_UNKNOWN_S;
333 }
334
335 new_con->id = id;
336 new_con->dependent = dependent;
337 new_con->primary = primary;
338 new_con->score = score;
339 new_con->dependent_role = text2role(dependent_role);
340 new_con->primary_role = text2role(primary_role);
341 new_con->node_attribute = node_attr;
342 new_con->influence = influence;
343
344 if (node_attr == NULL) {
345 node_attr = CRM_ATTR_UNAME;
346 }
347
348 pe_rsc_trace(dependent, "%s ==> %s (%s %d)",
349 dependent->id, primary->id, node_attr, score);
350
351 pcmk__add_this_with(&(dependent->rsc_cons), new_con);
352 pcmk__add_with_this(&(primary->rsc_cons_lhs), new_con);
353
355 new_con);
356
357 if (score <= -INFINITY) {
358 anti_colocation_order(dependent, new_con->dependent_role, primary,
359 new_con->primary_role);
360 anti_colocation_order(primary, new_con->primary_role, dependent,
361 new_con->dependent_role);
362 }
363}
364
376static bool
377unpack_influence(const char *coloc_id, const pe_resource_t *rsc,
378 const char *influence_s)
379{
380 if (influence_s != NULL) {
381 int influence_i = 0;
382
383 if (crm_str_to_boolean(influence_s, &influence_i) < 0) {
384 pcmk__config_err("Constraint '%s' has invalid value for "
385 XML_COLOC_ATTR_INFLUENCE " (using default)",
386 coloc_id);
387 } else {
388 return (influence_i != 0);
389 }
390 }
391 return pcmk_is_set(rsc->flags, pe_rsc_critical);
392}
393
394static void
395unpack_colocation_set(xmlNode *set, int score, const char *coloc_id,
396 const char *influence_s, pe_working_set_t *data_set)
397{
398 xmlNode *xml_rsc = NULL;
399 pe_resource_t *with = NULL;
400 pe_resource_t *resource = NULL;
401 const char *set_id = ID(set);
402 const char *role = crm_element_value(set, "role");
403 const char *ordering = crm_element_value(set, "ordering");
404 int local_score = score;
405 bool sequential = false;
406
407 const char *score_s = crm_element_value(set, XML_RULE_ATTR_SCORE);
408
409 if (score_s) {
410 local_score = char2score(score_s);
411 }
412 if (local_score == 0) {
413 crm_trace("Ignoring colocation '%s' for set '%s' because score is 0",
414 coloc_id, set_id);
415 return;
416 }
417
418 if (ordering == NULL) {
419 ordering = "group";
420 }
421
422 if (pcmk__xe_get_bool_attr(set, "sequential", &sequential) == pcmk_rc_ok && !sequential) {
423 return;
424
425 } else if ((local_score > 0)
426 && pcmk__str_eq(ordering, "group", pcmk__str_casei)) {
427 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
428 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
429
430 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
431 if (with != NULL) {
432 pe_rsc_trace(resource, "Colocating %s with %s", resource->id, with->id);
433 pcmk__new_colocation(set_id, NULL, local_score, resource,
434 with, role, role,
435 unpack_influence(coloc_id, resource,
436 influence_s), data_set);
437 }
438 with = resource;
439 }
440
441 } else if (local_score > 0) {
442 pe_resource_t *last = NULL;
443
444 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
445 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
446
447 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
448 if (last != NULL) {
449 pe_rsc_trace(resource, "Colocating %s with %s",
450 last->id, resource->id);
451 pcmk__new_colocation(set_id, NULL, local_score, last,
452 resource, role, role,
453 unpack_influence(coloc_id, last,
454 influence_s), data_set);
455 }
456
457 last = resource;
458 }
459
460 } else {
461 /* Anti-colocating with every prior resource is
462 * the only way to ensure the intuitive result
463 * (i.e. that no one in the set can run with anyone else in the set)
464 */
465
466 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
467 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
468
469 xmlNode *xml_rsc_with = NULL;
470 bool influence = true;
471
472 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
473 influence = unpack_influence(coloc_id, resource, influence_s);
474
475 for (xml_rsc_with = first_named_child(set, XML_TAG_RESOURCE_REF);
476 xml_rsc_with != NULL;
477 xml_rsc_with = crm_next_same_xml(xml_rsc_with)) {
478
479 if (pcmk__str_eq(resource->id, ID(xml_rsc_with),
481 break;
482 }
483 EXPAND_CONSTRAINT_IDREF(set_id, with, ID(xml_rsc_with));
484 pe_rsc_trace(resource, "Anti-Colocating %s with %s", resource->id,
485 with->id);
486 pcmk__new_colocation(set_id, NULL, local_score,
487 resource, with, role, role,
488 influence, data_set);
489 }
490 }
491 }
492}
493
494static void
495colocate_rsc_sets(const char *id, xmlNode *set1, xmlNode *set2, int score,
496 const char *influence_s, pe_working_set_t *data_set)
497{
498 xmlNode *xml_rsc = NULL;
499 pe_resource_t *rsc_1 = NULL;
500 pe_resource_t *rsc_2 = NULL;
501
502 const char *role_1 = crm_element_value(set1, "role");
503 const char *role_2 = crm_element_value(set2, "role");
504
505 int rc = pcmk_rc_ok;
506 bool sequential = false;
507
508 if (score == 0) {
509 crm_trace("Ignoring colocation '%s' between sets because score is 0",
510 id);
511 return;
512 }
513
514 rc = pcmk__xe_get_bool_attr(set1, "sequential", &sequential);
515 if (rc != pcmk_rc_ok || sequential) {
516 // Get the first one
518 if (xml_rsc != NULL) {
519 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
520 }
521 }
522
523 rc = pcmk__xe_get_bool_attr(set2, "sequential", &sequential);
524 if (rc != pcmk_rc_ok || sequential) {
525 // Get the last one
526 const char *rid = NULL;
527
528 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
529 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
530
531 rid = ID(xml_rsc);
532 }
533 EXPAND_CONSTRAINT_IDREF(id, rsc_2, rid);
534 }
535
536 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
537 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1, role_2,
538 unpack_influence(id, rsc_1, influence_s),
539 data_set);
540
541 } else if (rsc_1 != NULL) {
542 bool influence = unpack_influence(id, rsc_1, influence_s);
543
544 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
545 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
546
547 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
548 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
549 role_2, influence, data_set);
550 }
551
552 } else if (rsc_2 != NULL) {
553 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
554 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
555
556 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
557 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
558 role_2,
559 unpack_influence(id, rsc_1, influence_s),
560 data_set);
561 }
562
563 } else {
564 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
565 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
566
567 xmlNode *xml_rsc_2 = NULL;
568 bool influence = true;
569
570 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
571 influence = unpack_influence(id, rsc_1, influence_s);
572
573 for (xml_rsc_2 = first_named_child(set2, XML_TAG_RESOURCE_REF);
574 xml_rsc_2 != NULL;
575 xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
576
577 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
578 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2,
579 role_1, role_2, influence,
580 data_set);
581 }
582 }
583 }
584}
585
586static void
587unpack_simple_colocation(xmlNode *xml_obj, const char *id,
588 const char *influence_s, pe_working_set_t *data_set)
589{
590 int score_i = 0;
591
592 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
593 const char *dependent_id = crm_element_value(xml_obj,
595 const char *primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
596 const char *dependent_role = crm_element_value(xml_obj,
598 const char *primary_role = crm_element_value(xml_obj,
600 const char *attr = crm_element_value(xml_obj, XML_COLOC_ATTR_NODE_ATTR);
601
602 // @COMPAT: Deprecated since 2.1.5
603 const char *dependent_instance = crm_element_value(xml_obj,
605 // @COMPAT: Deprecated since 2.1.5
606 const char *primary_instance = crm_element_value(xml_obj,
608
610 dependent_id);
612 primary_id);
613
614 if (dependent_instance != NULL) {
616 "Support for " XML_COLOC_ATTR_SOURCE_INSTANCE " is "
617 "deprecated and will be removed in a future release.");
618 }
619
620 if (primary_instance != NULL) {
622 "Support for " XML_COLOC_ATTR_TARGET_INSTANCE " is "
623 "deprecated and will be removed in a future release.");
624 }
625
626 if (dependent == NULL) {
627 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
628 "does not exist", id, dependent_id);
629 return;
630
631 } else if (primary == NULL) {
632 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
633 "does not exist", id, primary_id);
634 return;
635
636 } else if ((dependent_instance != NULL) && !pe_rsc_is_clone(dependent)) {
637 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
638 "is not a clone but instance '%s' was requested",
639 id, dependent_id, dependent_instance);
640 return;
641
642 } else if ((primary_instance != NULL) && !pe_rsc_is_clone(primary)) {
643 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
644 "is not a clone but instance '%s' was requested",
645 id, primary_id, primary_instance);
646 return;
647 }
648
649 if (dependent_instance != NULL) {
650 dependent = find_clone_instance(dependent, dependent_instance);
651 if (dependent == NULL) {
652 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
653 "does not have an instance '%s'",
654 id, dependent_id, dependent_instance);
655 return;
656 }
657 }
658
659 if (primary_instance != NULL) {
660 primary = find_clone_instance(primary, primary_instance);
661 if (primary == NULL) {
662 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
663 "does not have an instance '%s'",
664 "'%s'", id, primary_id, primary_instance);
665 return;
666 }
667 }
668
670 pcmk__config_warn("The colocation constraint '"
672 "' attribute has been removed");
673 }
674
675 if (score) {
676 score_i = char2score(score);
677 }
678
679 pcmk__new_colocation(id, attr, score_i, dependent, primary,
680 dependent_role, primary_role,
681 unpack_influence(id, dependent, influence_s), data_set);
682}
683
684// \return Standard Pacemaker return code
685static int
686unpack_colocation_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
688{
689 const char *id = NULL;
690 const char *dependent_id = NULL;
691 const char *primary_id = NULL;
692 const char *dependent_role = NULL;
693 const char *primary_role = NULL;
694
695 pe_resource_t *dependent = NULL;
696 pe_resource_t *primary = NULL;
697
698 pe_tag_t *dependent_tag = NULL;
699 pe_tag_t *primary_tag = NULL;
700
701 xmlNode *dependent_set = NULL;
702 xmlNode *primary_set = NULL;
703 bool any_sets = false;
704
705 *expanded_xml = NULL;
706
707 CRM_CHECK(xml_obj != NULL, return EINVAL);
708
709 id = ID(xml_obj);
710 if (id == NULL) {
711 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
712 crm_element_name(xml_obj));
714 }
715
716 // Check whether there are any resource sets with template or tag references
717 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, data_set);
718 if (*expanded_xml != NULL) {
719 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
720 return pcmk_rc_ok;
721 }
722
723 dependent_id = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
724 primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
725 if ((dependent_id == NULL) || (primary_id == NULL)) {
726 return pcmk_rc_ok;
727 }
728
729 if (!pcmk__valid_resource_or_tag(data_set, dependent_id, &dependent,
730 &dependent_tag)) {
731 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
732 "valid resource or tag", id, dependent_id);
734 }
735
736 if (!pcmk__valid_resource_or_tag(data_set, primary_id, &primary,
737 &primary_tag)) {
738 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
739 "valid resource or tag", id, primary_id);
741 }
742
743 if ((dependent != NULL) && (primary != NULL)) {
744 /* Neither side references any template/tag. */
745 return pcmk_rc_ok;
746 }
747
748 if ((dependent_tag != NULL) && (primary_tag != NULL)) {
749 // A colocation constraint between two templates/tags makes no sense
750 pcmk__config_err("Ignoring constraint '%s' because two templates or "
751 "tags cannot be colocated", id);
753 }
754
755 dependent_role = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
756 primary_role = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE);
757
758 *expanded_xml = copy_xml(xml_obj);
759
760 // Convert template/tag reference in "rsc" into resource_set under constraint
761 if (!pcmk__tag_to_set(*expanded_xml, &dependent_set, XML_COLOC_ATTR_SOURCE,
762 true, data_set)) {
763 free_xml(*expanded_xml);
764 *expanded_xml = NULL;
766 }
767
768 if (dependent_set != NULL) {
769 if (dependent_role != NULL) {
770 // Move "rsc-role" into converted resource_set as "role"
771 crm_xml_add(dependent_set, "role", dependent_role);
773 }
774 any_sets = true;
775 }
776
777 // Convert template/tag reference in "with-rsc" into resource_set under constraint
778 if (!pcmk__tag_to_set(*expanded_xml, &primary_set, XML_COLOC_ATTR_TARGET,
779 true, data_set)) {
780 free_xml(*expanded_xml);
781 *expanded_xml = NULL;
783 }
784
785 if (primary_set != NULL) {
786 if (primary_role != NULL) {
787 // Move "with-rsc-role" into converted resource_set as "role"
788 crm_xml_add(primary_set, "role", primary_role);
790 }
791 any_sets = true;
792 }
793
794 if (any_sets) {
795 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
796 } else {
797 free_xml(*expanded_xml);
798 *expanded_xml = NULL;
799 }
800
801 return pcmk_rc_ok;
802}
803
811void
813{
814 int score_i = 0;
815 xmlNode *set = NULL;
816 xmlNode *last = NULL;
817
818 xmlNode *orig_xml = NULL;
819 xmlNode *expanded_xml = NULL;
820
821 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
822 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
823 const char *influence_s = crm_element_value(xml_obj,
825
826 if (score) {
827 score_i = char2score(score);
828 }
829
830 if (unpack_colocation_tags(xml_obj, &expanded_xml,
831 data_set) != pcmk_rc_ok) {
832 return;
833 }
834 if (expanded_xml) {
835 orig_xml = xml_obj;
836 xml_obj = expanded_xml;
837 }
838
839 for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
840 set = crm_next_same_xml(set)) {
841
842 set = expand_idref(set, data_set->input);
843 if (set == NULL) { // Configuration error, message already logged
844 if (expanded_xml != NULL) {
845 free_xml(expanded_xml);
846 }
847 return;
848 }
849
850 unpack_colocation_set(set, score_i, id, influence_s, data_set);
851
852 if (last != NULL) {
853 colocate_rsc_sets(id, last, set, score_i, influence_s, data_set);
854 }
855 last = set;
856 }
857
858 if (expanded_xml) {
859 free_xml(expanded_xml);
860 xml_obj = orig_xml;
861 }
862
863 if (last == NULL) {
864 unpack_simple_colocation(xml_obj, id, influence_s, data_set);
865 }
866}
867
876static void
877mark_action_blocked(pe_resource_t *rsc, const char *task,
878 const pe_resource_t *reason)
879{
880 char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
881
882 for (GList *gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
883 pe_action_t *action = (pe_action_t *) gIter->data;
884
886 && pcmk__str_eq(action->task, task, pcmk__str_casei)) {
887
889 pe_action_set_reason(action, reason_text, false);
892 }
893 }
894
895 // If parent resource can't perform an action, neither can any children
896 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
897 mark_action_blocked((pe_resource_t *) (iter->data), task, reason);
898 }
899 free(reason_text);
900}
901
913void
916{
917 GList *gIter = NULL;
918 GList *colocations = NULL;
919 pe_resource_t *rsc = NULL;
920 bool is_start = false;
921
923 return; // Only unrunnable actions block dependents
924 }
925
926 is_start = pcmk__str_eq(action->task, RSC_START, pcmk__str_none);
927 if (!is_start && !pcmk__str_eq(action->task, RSC_PROMOTE, pcmk__str_none)) {
928 return; // Only unrunnable starts and promotes block dependents
929 }
930
931 CRM_ASSERT(action->rsc != NULL); // Start and promote are resource actions
932
933 /* If this resource is part of a collective resource, dependents are blocked
934 * only if all instances of the collective are unrunnable, so check the
935 * collective resource.
936 */
937 rsc = uber_parent(action->rsc);
938 if (rsc->parent != NULL) {
939 rsc = rsc->parent; // Bundle
940 }
941
942 // Colocation fails only if entire primary can't reach desired role
943 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
944 pe_resource_t *child = (pe_resource_t *) gIter->data;
945 pe_action_t *child_action = find_first_action(child->actions, NULL,
946 action->task, NULL);
947
948 if ((child_action == NULL)
949 || pcmk_is_set(child_action->flags, pe_action_runnable)) {
950 crm_trace("Not blocking %s colocation dependents because "
951 "at least %s has runnable %s",
952 rsc->id, child->id, action->task);
953 return; // At least one child can reach desired role
954 }
955 }
956
957 crm_trace("Blocking %s colocation dependents due to unrunnable %s %s",
958 rsc->id, action->rsc->id, action->task);
959
960 // Check each colocation where this resource is primary
961 colocations = pcmk__with_this_colocations(rsc);
962 for (gIter = colocations; gIter != NULL; gIter = gIter->next) {
963 pcmk__colocation_t *colocation = (pcmk__colocation_t *) gIter->data;
964
965 if (colocation->score < INFINITY) {
966 continue; // Only mandatory colocations block dependent
967 }
968
969 /* If the primary can't start, the dependent can't reach its colocated
970 * role, regardless of what the primary or dependent colocation role is.
971 *
972 * If the primary can't be promoted, the dependent can't reach its
973 * colocated role if the primary's colocation role is promoted.
974 */
975 if (!is_start && (colocation->primary_role != RSC_ROLE_PROMOTED)) {
976 continue;
977 }
978
979 // Block the dependent from reaching its colocated role
980 if (colocation->dependent_role == RSC_ROLE_PROMOTED) {
981 mark_action_blocked(colocation->dependent, RSC_PROMOTE,
982 action->rsc);
983 } else {
984 mark_action_blocked(colocation->dependent, RSC_START, action->rsc);
985 }
986 }
987 g_list_free(colocations);
988}
989
1010 const pe_resource_t *primary,
1011 const pcmk__colocation_t *colocation, bool preview)
1012{
1013 if (!preview && pcmk_is_set(primary->flags, pe_rsc_provisional)) {
1014 // Primary resource has not been allocated yet, so we can't do anything
1016 }
1017
1018 if ((colocation->dependent_role >= RSC_ROLE_UNPROMOTED)
1019 && (dependent->parent != NULL)
1020 && pcmk_is_set(dependent->parent->flags, pe_rsc_promotable)
1021 && !pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
1022
1023 /* This is a colocation by role, and the dependent is a promotable clone
1024 * that has already been allocated, so the colocation should now affect
1025 * the role.
1026 */
1028 }
1029
1030 if (!preview && !pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
1031 /* The dependent resource has already been through allocation, so the
1032 * constraint no longer has any effect. Log an error if a mandatory
1033 * colocation constraint has been violated.
1034 */
1035
1036 const pe_node_t *primary_node = primary->allocated_to;
1037
1038 if (dependent->allocated_to == NULL) {
1039 crm_trace("Skipping colocation '%s': %s will not run anywhere",
1040 colocation->id, dependent->id);
1041
1042 } else if (colocation->score >= INFINITY) {
1043 // Dependent resource must colocate with primary resource
1044
1045 if ((primary_node == NULL) ||
1046 (primary_node->details != dependent->allocated_to->details)) {
1047 crm_err("%s must be colocated with %s but is not (%s vs. %s)",
1048 dependent->id, primary->id,
1049 pe__node_name(dependent->allocated_to),
1050 pe__node_name(primary_node));
1051 }
1052
1053 } else if (colocation->score <= -CRM_SCORE_INFINITY) {
1054 // Dependent resource must anti-colocate with primary resource
1055
1056 if ((primary_node != NULL) &&
1057 (dependent->allocated_to->details == primary_node->details)) {
1058 crm_err("%s and %s must be anti-colocated but are allocated "
1059 "to the same node (%s)",
1060 dependent->id, primary->id, pe__node_name(primary_node));
1061 }
1062 }
1064 }
1065
1066 if ((colocation->score > 0)
1067 && (colocation->dependent_role != RSC_ROLE_UNKNOWN)
1068 && (colocation->dependent_role != dependent->next_role)) {
1069
1070 crm_trace("Skipping colocation '%s': dependent limited to %s role "
1071 "but %s next role is %s",
1072 colocation->id, role2text(colocation->dependent_role),
1073 dependent->id, role2text(dependent->next_role));
1075 }
1076
1077 if ((colocation->score > 0)
1078 && (colocation->primary_role != RSC_ROLE_UNKNOWN)
1079 && (colocation->primary_role != primary->next_role)) {
1080
1081 crm_trace("Skipping colocation '%s': primary limited to %s role "
1082 "but %s next role is %s",
1083 colocation->id, role2text(colocation->primary_role),
1084 primary->id, role2text(primary->next_role));
1086 }
1087
1088 if ((colocation->score < 0)
1089 && (colocation->dependent_role != RSC_ROLE_UNKNOWN)
1090 && (colocation->dependent_role == dependent->next_role)) {
1091 crm_trace("Skipping anti-colocation '%s': dependent role %s matches",
1092 colocation->id, role2text(colocation->dependent_role));
1094 }
1095
1096 if ((colocation->score < 0)
1097 && (colocation->primary_role != RSC_ROLE_UNKNOWN)
1098 && (colocation->primary_role == primary->next_role)) {
1099 crm_trace("Skipping anti-colocation '%s': primary role %s matches",
1100 colocation->id, role2text(colocation->primary_role));
1102 }
1103
1105}
1106
1118void
1120 const pe_resource_t *primary,
1121 const pcmk__colocation_t *colocation)
1122{
1123 const char *attribute = CRM_ATTR_ID;
1124 const char *value = NULL;
1125 GHashTable *work = NULL;
1126 GHashTableIter iter;
1127 pe_node_t *node = NULL;
1128
1129 if (colocation->node_attribute != NULL) {
1130 attribute = colocation->node_attribute;
1131 }
1132
1133 if (primary->allocated_to != NULL) {
1134 value = pe_node_attribute_raw(primary->allocated_to, attribute);
1135
1136 } else if (colocation->score < 0) {
1137 // Nothing to do (anti-colocation with something that is not running)
1138 return;
1139 }
1140
1141 work = pcmk__copy_node_table(dependent->allowed_nodes);
1142
1143 g_hash_table_iter_init(&iter, work);
1144 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1145 if (primary->allocated_to == NULL) {
1146 node->weight = pcmk__add_scores(-colocation->score, node->weight);
1147 pe_rsc_trace(dependent,
1148 "Applied %s to %s score on %s (now %s after "
1149 "subtracting %s because primary %s inactive)",
1150 colocation->id, dependent->id, pe__node_name(node),
1152 pcmk_readable_score(colocation->score), primary->id);
1153
1154 } else if (pcmk__str_eq(pe_node_attribute_raw(node, attribute), value,
1155 pcmk__str_casei)) {
1156 /* Add colocation score only if optional (or minus infinity). A
1157 * mandatory colocation is a requirement rather than a preference,
1158 * so we don't need to consider it for relative assignment purposes.
1159 * The resource will simply be forbidden from running on the node if
1160 * the primary isn't active there (via the condition above).
1161 */
1162 if (colocation->score < CRM_SCORE_INFINITY) {
1163 node->weight = pcmk__add_scores(colocation->score,
1164 node->weight);
1165 pe_rsc_trace(dependent,
1166 "Applied %s to %s score on %s (now %s after "
1167 "adding %s)",
1168 colocation->id, dependent->id, pe__node_name(node),
1170 pcmk_readable_score(colocation->score));
1171 }
1172
1173 } else if (colocation->score >= CRM_SCORE_INFINITY) {
1174 /* Only mandatory colocations are relevant when the colocation
1175 * attribute doesn't match, because an attribute not matching is not
1176 * a negative preference -- the colocation is simply relevant only
1177 * where it matches.
1178 */
1179 node->weight = -CRM_SCORE_INFINITY;
1180 pe_rsc_trace(dependent,
1181 "Banned %s from %s because colocation %s attribute %s "
1182 "does not match",
1183 dependent->id, pe__node_name(node), colocation->id,
1184 attribute);
1185 }
1186 }
1187
1188 if ((colocation->score <= -INFINITY) || (colocation->score >= INFINITY)
1189 || pcmk__any_node_available(work)) {
1190
1191 g_hash_table_destroy(dependent->allowed_nodes);
1192 dependent->allowed_nodes = work;
1193 work = NULL;
1194
1195 } else {
1196 pe_rsc_info(dependent,
1197 "%s: Rolling back scores from %s (no available nodes)",
1198 dependent->id, primary->id);
1199 }
1200
1201 if (work != NULL) {
1202 g_hash_table_destroy(work);
1203 }
1204}
1205
1217void
1219 const pe_resource_t *primary,
1220 const pcmk__colocation_t *colocation)
1221{
1222 const char *dependent_value = NULL;
1223 const char *primary_value = NULL;
1224 const char *attribute = CRM_ATTR_ID;
1225 int score_multiplier = 1;
1226
1227 if ((primary->allocated_to == NULL) || (dependent->allocated_to == NULL)) {
1228 return;
1229 }
1230
1231 if (colocation->node_attribute != NULL) {
1232 attribute = colocation->node_attribute;
1233 }
1234
1235 dependent_value = pe_node_attribute_raw(dependent->allocated_to, attribute);
1236 primary_value = pe_node_attribute_raw(primary->allocated_to, attribute);
1237
1238 if (!pcmk__str_eq(dependent_value, primary_value, pcmk__str_casei)) {
1239 if ((colocation->score == INFINITY)
1240 && (colocation->dependent_role == RSC_ROLE_PROMOTED)) {
1241 dependent->priority = -INFINITY;
1242 }
1243 return;
1244 }
1245
1246 if ((colocation->primary_role != RSC_ROLE_UNKNOWN)
1247 && (colocation->primary_role != primary->next_role)) {
1248 return;
1249 }
1250
1251 if (colocation->dependent_role == RSC_ROLE_UNPROMOTED) {
1252 score_multiplier = -1;
1253 }
1254
1255 dependent->priority = pcmk__add_scores(score_multiplier * colocation->score,
1256 dependent->priority);
1257 pe_rsc_trace(dependent,
1258 "Applied %s to %s promotion priority (now %s after %s %s)",
1259 colocation->id, dependent->id,
1260 pcmk_readable_score(dependent->priority),
1261 ((score_multiplier == 1)? "adding" : "subtracting"),
1262 pcmk_readable_score(colocation->score));
1263}
1264
1273static int
1274best_node_score_matching_attr(const pe_resource_t *rsc, const char *attr,
1275 const char *value)
1276{
1277 GHashTableIter iter;
1278 pe_node_t *node = NULL;
1279 int best_score = -INFINITY;
1280 const char *best_node = NULL;
1281
1282 // Find best allowed node with matching attribute
1283 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1284 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1285
1286 if ((node->weight > best_score) && pcmk__node_available(node, false, false)
1287 && pcmk__str_eq(value, pe_node_attribute_raw(node, attr), pcmk__str_casei)) {
1288
1289 best_score = node->weight;
1290 best_node = node->details->uname;
1291 }
1292 }
1293
1294 if (!pcmk__str_eq(attr, CRM_ATTR_UNAME, pcmk__str_casei)) {
1295 if (best_node == NULL) {
1296 crm_info("No allowed node for %s matches node attribute %s=%s",
1297 rsc->id, attr, value);
1298 } else {
1299 crm_info("Allowed node %s for %s had best score (%d) "
1300 "of those matching node attribute %s=%s",
1301 best_node, rsc->id, best_score, attr, value);
1302 }
1303 }
1304 return best_score;
1305}
1306
1321static void
1322add_node_scores_matching_attr(GHashTable *nodes, const pe_resource_t *rsc,
1323 const char *attr, float factor,
1324 bool only_positive)
1325{
1326 GHashTableIter iter;
1327 pe_node_t *node = NULL;
1328
1329 if (attr == NULL) {
1330 attr = CRM_ATTR_UNAME;
1331 }
1332
1333 // Iterate through each node
1334 g_hash_table_iter_init(&iter, nodes);
1335 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1336 float weight_f = 0;
1337 int weight = 0;
1338 int score = 0;
1339 int new_score = 0;
1340
1341 score = best_node_score_matching_attr(rsc, attr,
1342 pe_node_attribute_raw(node, attr));
1343
1344 if ((factor < 0) && (score < 0)) {
1345 /* Negative preference for a node with a negative score
1346 * should not become a positive preference.
1347 *
1348 * @TODO Consider filtering only if weight is -INFINITY
1349 */
1350 crm_trace("%s: Filtering %d + %f * %d (double negative disallowed)",
1351 pe__node_name(node), node->weight, factor, score);
1352 continue;
1353 }
1354
1355 if (node->weight == INFINITY_HACK) {
1356 crm_trace("%s: Filtering %d + %f * %d (node was marked unusable)",
1357 pe__node_name(node), node->weight, factor, score);
1358 continue;
1359 }
1360
1361 weight_f = factor * score;
1362
1363 // Round the number; see http://c-faq.com/fp/round.html
1364 weight = (int) ((weight_f < 0)? (weight_f - 0.5) : (weight_f + 0.5));
1365
1366 /* Small factors can obliterate the small scores that are often actually
1367 * used in configurations. If the score and factor are nonzero, ensure
1368 * that the result is nonzero as well.
1369 */
1370 if ((weight == 0) && (score != 0)) {
1371 if (factor > 0.0) {
1372 weight = 1;
1373 } else if (factor < 0.0) {
1374 weight = -1;
1375 }
1376 }
1377
1378 new_score = pcmk__add_scores(weight, node->weight);
1379
1380 if (only_positive && (new_score < 0) && (node->weight > 0)) {
1381 crm_trace("%s: Filtering %d + %f * %d = %d "
1382 "(negative disallowed, marking node unusable)",
1383 pe__node_name(node), node->weight, factor, score,
1384 new_score);
1385 node->weight = INFINITY_HACK;
1386 continue;
1387 }
1388
1389 if (only_positive && (new_score < 0) && (node->weight == 0)) {
1390 crm_trace("%s: Filtering %d + %f * %d = %d (negative disallowed)",
1391 pe__node_name(node), node->weight, factor, score,
1392 new_score);
1393 continue;
1394 }
1395
1396 crm_trace("%s: %d + %f * %d = %d", pe__node_name(node),
1397 node->weight, factor, score, new_score);
1398 node->weight = new_score;
1399 }
1400}
1401
1419void
1421 GHashTable **nodes, const char *attr,
1422 float factor, uint32_t flags)
1423{
1424 GHashTable *work = NULL;
1425
1426 CRM_CHECK((rsc != NULL) && (nodes != NULL), return);
1427
1428 if (log_id == NULL) {
1429 log_id = rsc->id;
1430 }
1431
1432 // Avoid infinite recursion
1433 if (pcmk_is_set(rsc->flags, pe_rsc_merging)) {
1434 pe_rsc_info(rsc, "%s: Breaking dependency loop at %s",
1435 log_id, rsc->id);
1436 return;
1437 }
1439
1440 if (*nodes == NULL) {
1441 /* Only cmp_resources() passes a NULL nodes table, which indicates we
1442 * should initialize it with the resource's allowed node scores.
1443 */
1445 } else {
1446 pe_rsc_trace(rsc, "%s: Merging scores from %s (at %.6f)",
1447 log_id, rsc->id, factor);
1448 work = pcmk__copy_node_table(*nodes);
1449 add_node_scores_matching_attr(work, rsc, attr, factor,
1452 }
1453
1454 if (work == NULL) {
1456 return;
1457 }
1458
1459 if (pcmk__any_node_available(work)) {
1460 GList *colocations = NULL;
1461
1463 colocations = pcmk__this_with_colocations(rsc);
1464 pe_rsc_trace(rsc,
1465 "Checking additional %d optional '%s with' constraints",
1466 g_list_length(colocations), rsc->id);
1467 } else {
1468 colocations = pcmk__with_this_colocations(rsc);
1469 pe_rsc_trace(rsc,
1470 "Checking additional %d optional 'with %s' constraints",
1471 g_list_length(colocations), rsc->id);
1472 }
1474
1475 for (GList *iter = colocations; iter != NULL; iter = iter->next) {
1476 pcmk__colocation_t *constraint = (pcmk__colocation_t *) iter->data;
1477
1478 pe_resource_t *other = NULL;
1479 float other_factor = factor * constraint->score / (float) INFINITY;
1480
1482 other = constraint->primary;
1483 } else if (!pcmk__colocation_has_influence(constraint, NULL)) {
1484 continue;
1485 } else {
1486 other = constraint->dependent;
1487 }
1488
1489 pe_rsc_trace(rsc, "Optionally merging score of '%s' constraint (%s with %s)",
1490 constraint->id, constraint->dependent->id,
1491 constraint->primary->id);
1492 other->cmds->add_colocated_node_scores(other, log_id, &work,
1493 constraint->node_attribute,
1494 other_factor, flags);
1495 pe__show_node_weights(true, NULL, log_id, work, rsc->cluster);
1496 }
1497 g_list_free(colocations);
1498
1500 pe_rsc_info(rsc, "%s: Rolling back optional scores from %s",
1501 log_id, rsc->id);
1502 g_hash_table_destroy(work);
1504 return;
1505 }
1506
1507
1509 pe_node_t *node = NULL;
1510 GHashTableIter iter;
1511
1512 g_hash_table_iter_init(&iter, work);
1513 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1514 if (node->weight == INFINITY_HACK) {
1515 node->weight = 1;
1516 }
1517 }
1518 }
1519
1520 if (*nodes != NULL) {
1521 g_hash_table_destroy(*nodes);
1522 }
1523 *nodes = work;
1524
1526}
1527
1535void
1536pcmk__add_dependent_scores(gpointer data, gpointer user_data)
1537{
1538 pcmk__colocation_t *colocation = (pcmk__colocation_t *) data;
1539 pe_resource_t *rsc = (pe_resource_t *) user_data;
1540
1541 pe_resource_t *other = colocation->dependent;
1542 const float factor = colocation->score / (float) INFINITY;
1544
1545 if (!pcmk__colocation_has_influence(colocation, NULL)) {
1546 return;
1547 }
1548 if (rsc->variant == pe_clone) {
1550 }
1551 pe_rsc_trace(rsc,
1552 "%s: Incorporating attenuated %s assignment scores due "
1553 "to colocation %s", rsc->id, other->id, colocation->id);
1554 other->cmds->add_colocated_node_scores(other, rsc->id, &rsc->allowed_nodes,
1555 colocation->node_attribute, factor,
1556 flags);
1557}
1558
1569GList *
1571{
1572 GList *list = NULL;
1573
1574 rsc->cmds->with_this_colocations(rsc, rsc, &list);
1575 return list;
1576}
1577
1588GList *
1590{
1591 GList *list = NULL;
1592
1593 rsc->cmds->this_with_colocations(rsc, rsc, &list);
1594 return list;
1595}
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition nvpair.c:927
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition nvpair.c:954
uint64_t flags
Definition remote.c:3
Utility functions.
int pcmk__add_scores(int score1, int score2)
Definition scores.c:116
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition scores.c:86
int char2score(const char *score)
Get the integer value of a score string.
Definition scores.c:36
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
int crm_str_to_boolean(const char *s, int *ret)
Definition strings.c:427
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:121
#define RSC_ROLE_STARTED_S
Definition common.h:112
const char * role2text(enum rsc_role_e role)
Definition common.c:450
@ RSC_ROLE_PROMOTED
Definition common.h:97
@ RSC_ROLE_UNKNOWN
Definition common.h:93
@ RSC_ROLE_UNPROMOTED
Definition common.h:96
enum rsc_role_e text2role(const char *role)
Definition common.c:479
#define RSC_ROLE_UNKNOWN_S
Definition common.h:110
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition complex.c:922
char data[0]
Definition cpg.c:10
uint32_t id
Definition cpg.c:0
A dumping ground.
#define CRMD_ACTION_STOP
Definition crm.h:177
#define CRM_SCORE_INFINITY
Definition crm.h:85
#define RSC_PROMOTE
Definition crm.h:205
#define RSC_START
Definition crm.h:199
#define CRMD_ACTION_DEMOTE
Definition crm.h:182
#define INFINITY
Definition crm.h:99
#define CRMD_ACTION_START
Definition crm.h:174
#define CRMD_ACTION_PROMOTE
Definition crm.h:180
#define CRM_ATTR_UNAME
Definition crm.h:113
#define CRM_ATTR_ID
Definition crm.h:114
G_GNUC_INTERNAL bool pcmk__valid_resource_or_tag(const pe_working_set_t *data_set, const char *id, pe_resource_t **rsc, pe_tag_t **tag)
@ pcmk__coloc_select_active
@ pcmk__coloc_select_this_with
@ pcmk__coloc_select_nonnegative
G_GNUC_INTERNAL bool pcmk__any_node_available(GHashTable *nodes)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pe_working_set_t *data_set)
G_GNUC_INTERNAL void pcmk__update_action_for_orderings(pe_action_t *action, pe_working_set_t *data_set)
pcmk__coloc_affects
@ pcmk__coloc_affects_nothing
@ pcmk__coloc_affects_location
@ pcmk__coloc_affects_role
G_GNUC_INTERNAL pe_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
G_GNUC_INTERNAL bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, const pe_working_set_t *data_set)
G_GNUC_INTERNAL bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
G_GNUC_INTERNAL GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define crm_info(fmt, args...)
Definition logging.h:378
#define CRM_CHECK(expr, failure_action)
Definition logging.h:235
#define crm_err(fmt, args...)
Definition logging.h:375
#define crm_log_xml_trace(xml, text)
Definition logging.h:389
#define crm_trace(fmt, args...)
Definition logging.h:381
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
#define XML_COLOC_ATTR_SOURCE_ROLE
Definition msg_xml.h:373
#define XML_TAG_RESOURCE_REF
Definition msg_xml.h:229
#define ID(x)
Definition msg_xml.h:480
#define XML_COLOC_ATTR_NODE_ATTR
Definition msg_xml.h:376
#define XML_RULE_ATTR_SCORE
Definition msg_xml.h:351
#define XML_CONS_TAG_RSC_SET
Definition msg_xml.h:367
#define XML_COLOC_ATTR_TARGET_ROLE
Definition msg_xml.h:375
#define XML_COLOC_ATTR_TARGET_INSTANCE
Definition msg_xml.h:383
#define XML_ATTR_ID
Definition msg_xml.h:147
#define XML_COLOC_ATTR_SOURCE_INSTANCE
Definition msg_xml.h:380
#define XML_COLOC_ATTR_INFLUENCE
Definition msg_xml.h:377
#define XML_CONS_ATTR_SYMMETRICAL
Definition msg_xml.h:368
#define XML_COLOC_ATTR_TARGET
Definition msg_xml.h:374
#define XML_COLOC_ATTR_SOURCE
Definition msg_xml.h:372
pe_working_set_t * data_set
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:496
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:302
const char * action
Definition pcmk_fence.c:30
void pcmk__block_colocation_dependents(pe_action_t *action, pe_working_set_t *data_set)
GList * pcmk__this_with_colocations(const pe_resource_t *rsc)
#define INFINITY_HACK
void pcmk__add_this_with_list(GList **list, GList *addition)
void pcmk__add_this_with(GList **list, const pcmk__colocation_t *colocation)
void pcmk__add_with_this(GList **list, const pcmk__colocation_t *colocation)
enum pcmk__coloc_affects pcmk__colocation_affects(const pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool preview)
void pcmk__apply_coloc_to_priority(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation)
#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name)
void pcmk__add_dependent_scores(gpointer data, gpointer user_data)
void pcmk__apply_coloc_to_weights(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation)
void pcmk__add_colocated_node_scores(pe_resource_t *rsc, const char *log_id, GHashTable **nodes, const char *attr, float factor, uint32_t flags)
void pcmk__new_colocation(const char *id, const char *node_attr, int score, pe_resource_t *dependent, pe_resource_t *primary, const char *dependent_role, const char *primary_role, bool influence, pe_working_set_t *data_set)
void pcmk__unpack_colocation(xmlNode *xml_obj, pe_working_set_t *data_set)
GList * pcmk__with_this_colocations(const pe_resource_t *rsc)
void pcmk__add_with_this_list(GList **list, GList *addition)
@ pe_order_anti_colocation
Definition pe_types.h:541
#define pe_rsc_provisional
Definition pe_types.h:282
@ pe_action_runnable
Definition pe_types.h:318
#define pe_rsc_merging
Definition pe_types.h:284
@ pe_clone
Definition pe_types.h:40
#define pe_rsc_promotable
Definition pe_types.h:280
#define pe_rsc_critical
Definition pe_types.h:290
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition internal.h:385
#define pe_warn_once(pe_wo_bit, fmt...)
Definition internal.h:177
const char * pe_node_attribute_raw(const pe_node_t *node, const char *name)
Definition common.c:558
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition internal.h:83
@ pe_wo_coloc_inst
Definition internal.h:168
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:50
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:77
#define pe_rsc_info(rsc, fmt, args...)
Definition internal.h:48
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:98
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
pe_resource_t * find_clone_instance(const pe_resource_t *rsc, const char *sub_id)
Definition clone.c:226
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_ok
Definition results.h:151
@ pcmk_rc_unpack_error
Definition results.h:115
Cluster status and scheduling.
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
pe_resource_t * primary
const char * node_attribute
pe_resource_t * dependent
enum pe_action_flags flags
Definition pe_types.h:442
int weight
Definition pe_types.h:265
struct pe_node_shared_s * details
Definition pe_types.h:268
GList * actions
Definition pe_types.h:391
enum pe_obj_types variant
Definition pe_types.h:356
GList * rsc_cons
Definition pe_types.h:389
GList * rsc_cons_lhs
Definition pe_types.h:388
GList * children
Definition pe_types.h:409
pe_working_set_t * cluster
Definition pe_types.h:353
GHashTable * allowed_nodes
Definition pe_types.h:400
pe_node_t * allocated_to
Definition pe_types.h:395
unsigned long long flags
Definition pe_types.h:373
pe_resource_t * parent
Definition pe_types.h:354
resource_alloc_functions_t * cmds
Definition pe_types.h:359
enum rsc_role_e next_role
Definition pe_types.h:403
GList * colocation_constraints
Definition pe_types.h:184
xmlNode * input
Definition pe_types.h:160
GList * resources
Definition pe_types.h:181
void(* add_colocated_node_scores)(pe_resource_t *rsc, const char *log_id, GHashTable **nodes, const char *attr, float factor, uint32_t flags)
void(* this_with_colocations)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
void(* with_this_colocations)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition xml.c:2593
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2521
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition xml.c:2547
void free_xml(xmlNode *child)
Definition xml.c:813
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:819
void xml_remove_prop(xmlNode *obj, const char *name)
Definition xml.c:1735