pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pcmk_sched_colocation.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 <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
140void
142{
143 rsc->rsc_cons = g_list_insert_sorted(rsc->rsc_cons, colocation,
144 cmp_primary_priority);
145}
146
154void
156{
157 rsc->rsc_cons_lhs = g_list_insert_sorted(rsc->rsc_cons_lhs, colocation,
158 cmp_dependent_priority);
159}
160
165static void
166anti_colocation_order(pe_resource_t *first_rsc, int first_role,
167 pe_resource_t *then_rsc, int then_role,
169{
170 const char *first_tasks[] = { NULL, NULL };
171 const char *then_tasks[] = { NULL, NULL };
172
173 /* Actions to make first_rsc lose first_role */
174 if (first_role == RSC_ROLE_PROMOTED) {
175 first_tasks[0] = CRMD_ACTION_DEMOTE;
176
177 } else {
178 first_tasks[0] = CRMD_ACTION_STOP;
179
180 if (first_role == RSC_ROLE_UNPROMOTED) {
181 first_tasks[1] = CRMD_ACTION_PROMOTE;
182 }
183 }
184
185 /* Actions to make then_rsc gain then_role */
186 if (then_role == RSC_ROLE_PROMOTED) {
187 then_tasks[0] = CRMD_ACTION_PROMOTE;
188
189 } else {
190 then_tasks[0] = CRMD_ACTION_START;
191
192 if (then_role == RSC_ROLE_UNPROMOTED) {
193 then_tasks[1] = CRMD_ACTION_DEMOTE;
194 }
195 }
196
197 for (int first_lpc = 0;
198 (first_lpc <= 1) && (first_tasks[first_lpc] != NULL); first_lpc++) {
199
200 for (int then_lpc = 0;
201 (then_lpc <= 1) && (then_tasks[then_lpc] != NULL); then_lpc++) {
202
203 pcmk__order_resource_actions(first_rsc, first_tasks[first_lpc],
204 then_rsc, then_tasks[then_lpc],
206 }
207 }
208}
209
224void
225pcmk__new_colocation(const char *id, const char *node_attr, int score,
226 pe_resource_t *dependent, pe_resource_t *primary,
227 const char *dependent_role, const char *primary_role,
228 bool influence, pe_working_set_t *data_set)
229{
230 pcmk__colocation_t *new_con = NULL;
231
232 if (score == 0) {
233 crm_trace("Ignoring colocation '%s' because score is 0", id);
234 return;
235 }
236 if ((dependent == NULL) || (primary == NULL)) {
237 pcmk__config_err("Ignoring colocation '%s' because resource "
238 "does not exist", id);
239 return;
240 }
241
242 new_con = calloc(1, sizeof(pcmk__colocation_t));
243 if (new_con == NULL) {
244 return;
245 }
246
247 if (pcmk__str_eq(dependent_role, RSC_ROLE_STARTED_S,
249 dependent_role = RSC_ROLE_UNKNOWN_S;
250 }
251
252 if (pcmk__str_eq(primary_role, RSC_ROLE_STARTED_S,
254 primary_role = RSC_ROLE_UNKNOWN_S;
255 }
256
257 new_con->id = id;
258 new_con->dependent = dependent;
259 new_con->primary = primary;
260 new_con->score = score;
261 new_con->dependent_role = text2role(dependent_role);
262 new_con->primary_role = text2role(primary_role);
263 new_con->node_attribute = node_attr;
264 new_con->influence = influence;
265
266 if (node_attr == NULL) {
267 node_attr = CRM_ATTR_UNAME;
268 }
269
270 pe_rsc_trace(dependent, "%s ==> %s (%s %d)",
271 dependent->id, primary->id, node_attr, score);
272
273 pcmk__add_this_with(dependent, new_con);
274 pcmk__add_with_this(primary, new_con);
275
277 new_con);
278
279 if (score <= -INFINITY) {
280 anti_colocation_order(dependent, new_con->dependent_role, primary,
281 new_con->primary_role, data_set);
282 anti_colocation_order(primary, new_con->primary_role, dependent,
283 new_con->dependent_role, data_set);
284 }
285}
286
298static bool
299unpack_influence(const char *coloc_id, const pe_resource_t *rsc,
300 const char *influence_s)
301{
302 if (influence_s != NULL) {
303 int influence_i = 0;
304
305 if (crm_str_to_boolean(influence_s, &influence_i) < 0) {
306 pcmk__config_err("Constraint '%s' has invalid value for "
307 XML_COLOC_ATTR_INFLUENCE " (using default)",
308 coloc_id);
309 } else {
310 return (influence_i != 0);
311 }
312 }
313 return pcmk_is_set(rsc->flags, pe_rsc_critical);
314}
315
316static void
317unpack_colocation_set(xmlNode *set, int score, const char *coloc_id,
318 const char *influence_s, pe_working_set_t *data_set)
319{
320 xmlNode *xml_rsc = NULL;
321 pe_resource_t *with = NULL;
322 pe_resource_t *resource = NULL;
323 const char *set_id = ID(set);
324 const char *role = crm_element_value(set, "role");
325 const char *ordering = crm_element_value(set, "ordering");
326 int local_score = score;
327 bool sequential = false;
328
329 const char *score_s = crm_element_value(set, XML_RULE_ATTR_SCORE);
330
331 if (score_s) {
332 local_score = char2score(score_s);
333 }
334 if (local_score == 0) {
335 crm_trace("Ignoring colocation '%s' for set '%s' because score is 0",
336 coloc_id, set_id);
337 return;
338 }
339
340 if (ordering == NULL) {
341 ordering = "group";
342 }
343
344 if (pcmk__xe_get_bool_attr(set, "sequential", &sequential) == pcmk_rc_ok && !sequential) {
345 return;
346
347 } else if ((local_score > 0)
348 && pcmk__str_eq(ordering, "group", pcmk__str_casei)) {
349 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
350 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
351
352 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
353 if (with != NULL) {
354 pe_rsc_trace(resource, "Colocating %s with %s", resource->id, with->id);
355 pcmk__new_colocation(set_id, NULL, local_score, resource,
356 with, role, role,
357 unpack_influence(coloc_id, resource,
358 influence_s), data_set);
359 }
360 with = resource;
361 }
362
363 } else if (local_score > 0) {
364 pe_resource_t *last = NULL;
365
366 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
367 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
368
369 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
370 if (last != NULL) {
371 pe_rsc_trace(resource, "Colocating %s with %s",
372 last->id, resource->id);
373 pcmk__new_colocation(set_id, NULL, local_score, last,
374 resource, role, role,
375 unpack_influence(coloc_id, last,
376 influence_s), data_set);
377 }
378
379 last = resource;
380 }
381
382 } else {
383 /* Anti-colocating with every prior resource is
384 * the only way to ensure the intuitive result
385 * (i.e. that no one in the set can run with anyone else in the set)
386 */
387
388 for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
389 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
390
391 xmlNode *xml_rsc_with = NULL;
392 bool influence = true;
393
394 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
395 influence = unpack_influence(coloc_id, resource, influence_s);
396
397 for (xml_rsc_with = first_named_child(set, XML_TAG_RESOURCE_REF);
398 xml_rsc_with != NULL;
399 xml_rsc_with = crm_next_same_xml(xml_rsc_with)) {
400
401 if (pcmk__str_eq(resource->id, ID(xml_rsc_with),
403 break;
404 }
405 EXPAND_CONSTRAINT_IDREF(set_id, with, ID(xml_rsc_with));
406 pe_rsc_trace(resource, "Anti-Colocating %s with %s", resource->id,
407 with->id);
408 pcmk__new_colocation(set_id, NULL, local_score,
409 resource, with, role, role,
410 influence, data_set);
411 }
412 }
413 }
414}
415
416static void
417colocate_rsc_sets(const char *id, xmlNode *set1, xmlNode *set2, int score,
418 const char *influence_s, pe_working_set_t *data_set)
419{
420 xmlNode *xml_rsc = NULL;
421 pe_resource_t *rsc_1 = NULL;
422 pe_resource_t *rsc_2 = NULL;
423
424 const char *role_1 = crm_element_value(set1, "role");
425 const char *role_2 = crm_element_value(set2, "role");
426
427 int rc = pcmk_rc_ok;
428 bool sequential = false;
429
430 if (score == 0) {
431 crm_trace("Ignoring colocation '%s' between sets because score is 0",
432 id);
433 return;
434 }
435
436 rc = pcmk__xe_get_bool_attr(set1, "sequential", &sequential);
437 if (rc != pcmk_rc_ok || sequential) {
438 // Get the first one
440 if (xml_rsc != NULL) {
441 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
442 }
443 }
444
445 rc = pcmk__xe_get_bool_attr(set2, "sequential", &sequential);
446 if (rc != pcmk_rc_ok || sequential) {
447 // Get the last one
448 const char *rid = NULL;
449
450 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
451 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
452
453 rid = ID(xml_rsc);
454 }
455 EXPAND_CONSTRAINT_IDREF(id, rsc_2, rid);
456 }
457
458 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
459 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1, role_2,
460 unpack_influence(id, rsc_1, influence_s),
461 data_set);
462
463 } else if (rsc_1 != NULL) {
464 bool influence = unpack_influence(id, rsc_1, influence_s);
465
466 for (xml_rsc = first_named_child(set2, XML_TAG_RESOURCE_REF);
467 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
468
469 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
470 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
471 role_2, influence, data_set);
472 }
473
474 } else if (rsc_2 != NULL) {
475 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
476 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
477
478 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
479 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2, role_1,
480 role_2,
481 unpack_influence(id, rsc_1, influence_s),
482 data_set);
483 }
484
485 } else {
486 for (xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
487 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
488
489 xmlNode *xml_rsc_2 = NULL;
490 bool influence = true;
491
492 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
493 influence = unpack_influence(id, rsc_1, influence_s);
494
495 for (xml_rsc_2 = first_named_child(set2, XML_TAG_RESOURCE_REF);
496 xml_rsc_2 != NULL;
497 xml_rsc_2 = crm_next_same_xml(xml_rsc_2)) {
498
499 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
500 pcmk__new_colocation(id, NULL, score, rsc_1, rsc_2,
501 role_1, role_2, influence,
502 data_set);
503 }
504 }
505 }
506}
507
508static void
509unpack_simple_colocation(xmlNode *xml_obj, const char *id,
510 const char *influence_s, pe_working_set_t *data_set)
511{
512 int score_i = 0;
513
514 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
515 const char *dependent_id = crm_element_value(xml_obj,
517 const char *primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
518 const char *dependent_role = crm_element_value(xml_obj,
520 const char *primary_role = crm_element_value(xml_obj,
522 const char *attr = crm_element_value(xml_obj, XML_COLOC_ATTR_NODE_ATTR);
523
524 // @COMPAT: Deprecated since 2.1.5
525 const char *dependent_instance = crm_element_value(xml_obj,
527 // @COMPAT: Deprecated since 2.1.5
528 const char *primary_instance = crm_element_value(xml_obj,
530
532 dependent_id);
534 primary_id);
535
536 if (dependent_instance != NULL) {
538 "Support for " XML_COLOC_ATTR_SOURCE_INSTANCE " is "
539 "deprecated and will be removed in a future release.");
540 }
541
542 if (primary_instance != NULL) {
544 "Support for " XML_COLOC_ATTR_TARGET_INSTANCE " is "
545 "deprecated and will be removed in a future release.");
546 }
547
548 if (dependent == NULL) {
549 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
550 "does not exist", id, dependent_id);
551 return;
552
553 } else if (primary == NULL) {
554 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
555 "does not exist", id, primary_id);
556 return;
557
558 } else if ((dependent_instance != NULL) && !pe_rsc_is_clone(dependent)) {
559 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
560 "is not a clone but instance '%s' was requested",
561 id, dependent_id, dependent_instance);
562 return;
563
564 } else if ((primary_instance != NULL) && !pe_rsc_is_clone(primary)) {
565 pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
566 "is not a clone but instance '%s' was requested",
567 id, primary_id, primary_instance);
568 return;
569 }
570
571 if (dependent_instance != NULL) {
572 dependent = find_clone_instance(dependent, dependent_instance, data_set);
573 if (dependent == NULL) {
574 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
575 "does not have an instance '%s'",
576 id, dependent_id, dependent_instance);
577 return;
578 }
579 }
580
581 if (primary_instance != NULL) {
582 primary = find_clone_instance(primary, primary_instance, data_set);
583 if (primary == NULL) {
584 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
585 "does not have an instance '%s'",
586 "'%s'", id, primary_id, primary_instance);
587 return;
588 }
589 }
590
592 pcmk__config_warn("The colocation constraint '"
594 "' attribute has been removed");
595 }
596
597 if (score) {
598 score_i = char2score(score);
599 }
600
601 pcmk__new_colocation(id, attr, score_i, dependent, primary,
602 dependent_role, primary_role,
603 unpack_influence(id, dependent, influence_s), data_set);
604}
605
606// \return Standard Pacemaker return code
607static int
608unpack_colocation_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
610{
611 const char *id = NULL;
612 const char *dependent_id = NULL;
613 const char *primary_id = NULL;
614 const char *dependent_role = NULL;
615 const char *primary_role = NULL;
616
617 pe_resource_t *dependent = NULL;
618 pe_resource_t *primary = NULL;
619
620 pe_tag_t *dependent_tag = NULL;
621 pe_tag_t *primary_tag = NULL;
622
623 xmlNode *dependent_set = NULL;
624 xmlNode *primary_set = NULL;
625 bool any_sets = false;
626
627 *expanded_xml = NULL;
628
629 CRM_CHECK(xml_obj != NULL, return EINVAL);
630
631 id = ID(xml_obj);
632 if (id == NULL) {
633 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
634 crm_element_name(xml_obj));
636 }
637
638 // Check whether there are any resource sets with template or tag references
639 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, data_set);
640 if (*expanded_xml != NULL) {
641 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
642 return pcmk_rc_ok;
643 }
644
645 dependent_id = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE);
646 primary_id = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET);
647 if ((dependent_id == NULL) || (primary_id == NULL)) {
648 return pcmk_rc_ok;
649 }
650
651 if (!pcmk__valid_resource_or_tag(data_set, dependent_id, &dependent,
652 &dependent_tag)) {
653 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
654 "valid resource or tag", id, dependent_id);
656 }
657
658 if (!pcmk__valid_resource_or_tag(data_set, primary_id, &primary,
659 &primary_tag)) {
660 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
661 "valid resource or tag", id, primary_id);
663 }
664
665 if ((dependent != NULL) && (primary != NULL)) {
666 /* Neither side references any template/tag. */
667 return pcmk_rc_ok;
668 }
669
670 if ((dependent_tag != NULL) && (primary_tag != NULL)) {
671 // A colocation constraint between two templates/tags makes no sense
672 pcmk__config_err("Ignoring constraint '%s' because two templates or "
673 "tags cannot be colocated", id);
675 }
676
677 dependent_role = crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE);
678 primary_role = crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE);
679
680 *expanded_xml = copy_xml(xml_obj);
681
682 // Convert template/tag reference in "rsc" into resource_set under constraint
683 if (!pcmk__tag_to_set(*expanded_xml, &dependent_set, XML_COLOC_ATTR_SOURCE,
684 true, data_set)) {
685 free_xml(*expanded_xml);
686 *expanded_xml = NULL;
688 }
689
690 if (dependent_set != NULL) {
691 if (dependent_role != NULL) {
692 // Move "rsc-role" into converted resource_set as "role"
693 crm_xml_add(dependent_set, "role", dependent_role);
695 }
696 any_sets = true;
697 }
698
699 // Convert template/tag reference in "with-rsc" into resource_set under constraint
700 if (!pcmk__tag_to_set(*expanded_xml, &primary_set, XML_COLOC_ATTR_TARGET,
701 true, data_set)) {
702 free_xml(*expanded_xml);
703 *expanded_xml = NULL;
705 }
706
707 if (primary_set != NULL) {
708 if (primary_role != NULL) {
709 // Move "with-rsc-role" into converted resource_set as "role"
710 crm_xml_add(primary_set, "role", primary_role);
712 }
713 any_sets = true;
714 }
715
716 if (any_sets) {
717 crm_log_xml_trace(*expanded_xml, "Expanded rsc_colocation");
718 } else {
719 free_xml(*expanded_xml);
720 *expanded_xml = NULL;
721 }
722
723 return pcmk_rc_ok;
724}
725
733void
735{
736 int score_i = 0;
737 xmlNode *set = NULL;
738 xmlNode *last = NULL;
739
740 xmlNode *orig_xml = NULL;
741 xmlNode *expanded_xml = NULL;
742
743 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
744 const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
745 const char *influence_s = crm_element_value(xml_obj,
747
748 if (score) {
749 score_i = char2score(score);
750 }
751
752 if (unpack_colocation_tags(xml_obj, &expanded_xml,
753 data_set) != pcmk_rc_ok) {
754 return;
755 }
756 if (expanded_xml) {
757 orig_xml = xml_obj;
758 xml_obj = expanded_xml;
759 }
760
761 for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
762 set = crm_next_same_xml(set)) {
763
764 set = expand_idref(set, data_set->input);
765 if (set == NULL) { // Configuration error, message already logged
766 if (expanded_xml != NULL) {
767 free_xml(expanded_xml);
768 }
769 return;
770 }
771
772 unpack_colocation_set(set, score_i, id, influence_s, data_set);
773
774 if (last != NULL) {
775 colocate_rsc_sets(id, last, set, score_i, influence_s, data_set);
776 }
777 last = set;
778 }
779
780 if (expanded_xml) {
781 free_xml(expanded_xml);
782 xml_obj = orig_xml;
783 }
784
785 if (last == NULL) {
786 unpack_simple_colocation(xml_obj, id, influence_s, data_set);
787 }
788}
789
798static void
799mark_action_blocked(pe_resource_t *rsc, const char *task,
800 const pe_resource_t *reason)
801{
802 char *reason_text = crm_strdup_printf("colocation with %s", reason->id);
803
804 for (GList *gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
805 pe_action_t *action = (pe_action_t *) gIter->data;
806
808 && pcmk__str_eq(action->task, task, pcmk__str_casei)) {
809
811 pe_action_set_reason(action, reason_text, false);
814 }
815 }
816
817 // If parent resource can't perform an action, neither can any children
818 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
819 mark_action_blocked((pe_resource_t *) (iter->data), task, reason);
820 }
821 free(reason_text);
822}
823
835void
838{
839 GList *gIter = NULL;
840 pe_resource_t *rsc = NULL;
841 bool is_start = false;
842
844 return; // Only unrunnable actions block dependents
845 }
846
847 is_start = pcmk__str_eq(action->task, RSC_START, pcmk__str_none);
848 if (!is_start && !pcmk__str_eq(action->task, RSC_PROMOTE, pcmk__str_none)) {
849 return; // Only unrunnable starts and promotes block dependents
850 }
851
852 CRM_ASSERT(action->rsc != NULL); // Start and promote are resource actions
853
854 /* If this resource is part of a collective resource, dependents are blocked
855 * only if all instances of the collective are unrunnable, so check the
856 * collective resource.
857 */
858 rsc = uber_parent(action->rsc);
859 if (rsc->parent != NULL) {
860 rsc = rsc->parent; // Bundle
861 }
862
863 if (rsc->rsc_cons_lhs == NULL) {
864 return;
865 }
866
867 // Colocation fails only if entire primary can't reach desired role
868 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
869 pe_resource_t *child = (pe_resource_t *) gIter->data;
870 pe_action_t *child_action = find_first_action(child->actions, NULL,
871 action->task, NULL);
872
873 if ((child_action == NULL)
874 || pcmk_is_set(child_action->flags, pe_action_runnable)) {
875 crm_trace("Not blocking %s colocation dependents because "
876 "at least %s has runnable %s",
877 rsc->id, child->id, action->task);
878 return; // At least one child can reach desired role
879 }
880 }
881
882 crm_trace("Blocking %s colocation dependents due to unrunnable %s %s",
883 rsc->id, action->rsc->id, action->task);
884
885 // Check each colocation where this resource is primary
886 for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
887 pcmk__colocation_t *colocation = (pcmk__colocation_t *) gIter->data;
888
889 if (colocation->score < INFINITY) {
890 continue; // Only mandatory colocations block dependent
891 }
892
893 /* If the primary can't start, the dependent can't reach its colocated
894 * role, regardless of what the primary or dependent colocation role is.
895 *
896 * If the primary can't be promoted, the dependent can't reach its
897 * colocated role if the primary's colocation role is promoted.
898 */
899 if (!is_start && (colocation->primary_role != RSC_ROLE_PROMOTED)) {
900 continue;
901 }
902
903 // Block the dependent from reaching its colocated role
904 if (colocation->dependent_role == RSC_ROLE_PROMOTED) {
905 mark_action_blocked(colocation->dependent, RSC_PROMOTE,
906 action->rsc);
907 } else {
908 mark_action_blocked(colocation->dependent, RSC_START, action->rsc);
909 }
910 }
911}
912
933 const pe_resource_t *primary,
934 const pcmk__colocation_t *colocation, bool preview)
935{
936 if (!preview && pcmk_is_set(primary->flags, pe_rsc_provisional)) {
937 // Primary resource has not been allocated yet, so we can't do anything
939 }
940
941 if ((colocation->dependent_role >= RSC_ROLE_UNPROMOTED)
942 && (dependent->parent != NULL)
944 && !pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
945
946 /* This is a colocation by role, and the dependent is a promotable clone
947 * that has already been allocated, so the colocation should now affect
948 * the role.
949 */
951 }
952
953 if (!preview && !pcmk_is_set(dependent->flags, pe_rsc_provisional)) {
954 /* The dependent resource has already been through allocation, so the
955 * constraint no longer has any effect. Log an error if a mandatory
956 * colocation constraint has been violated.
957 */
958
959 const pe_node_t *primary_node = primary->allocated_to;
960
961 if (dependent->allocated_to == NULL) {
962 crm_trace("Skipping colocation '%s': %s will not run anywhere",
963 colocation->id, dependent->id);
964
965 } else if (colocation->score >= INFINITY) {
966 // Dependent resource must colocate with primary resource
967
968 if ((primary_node == NULL) ||
969 (primary_node->details != dependent->allocated_to->details)) {
970 crm_err("%s must be colocated with %s but is not (%s vs. %s)",
971 dependent->id, primary->id,
972 pe__node_name(dependent->allocated_to),
973 pe__node_name(primary_node));
974 }
975
976 } else if (colocation->score <= -CRM_SCORE_INFINITY) {
977 // Dependent resource must anti-colocate with primary resource
978
979 if ((primary_node != NULL) &&
980 (dependent->allocated_to->details == primary_node->details)) {
981 crm_err("%s and %s must be anti-colocated but are allocated "
982 "to the same node (%s)",
983 dependent->id, primary->id, pe__node_name(primary_node));
984 }
985 }
987 }
988
989 if ((colocation->score > 0)
990 && (colocation->dependent_role != RSC_ROLE_UNKNOWN)
991 && (colocation->dependent_role != dependent->next_role)) {
992
993 crm_trace("Skipping colocation '%s': dependent limited to %s role "
994 "but %s next role is %s",
995 colocation->id, role2text(colocation->dependent_role),
996 dependent->id, role2text(dependent->next_role));
998 }
999
1000 if ((colocation->score > 0)
1001 && (colocation->primary_role != RSC_ROLE_UNKNOWN)
1002 && (colocation->primary_role != primary->next_role)) {
1003
1004 crm_trace("Skipping colocation '%s': primary limited to %s role "
1005 "but %s next role is %s",
1006 colocation->id, role2text(colocation->primary_role),
1007 primary->id, role2text(primary->next_role));
1009 }
1010
1011 if ((colocation->score < 0)
1012 && (colocation->dependent_role != RSC_ROLE_UNKNOWN)
1013 && (colocation->dependent_role == dependent->next_role)) {
1014 crm_trace("Skipping anti-colocation '%s': dependent role %s matches",
1015 colocation->id, role2text(colocation->dependent_role));
1017 }
1018
1019 if ((colocation->score < 0)
1020 && (colocation->primary_role != RSC_ROLE_UNKNOWN)
1021 && (colocation->primary_role == primary->next_role)) {
1022 crm_trace("Skipping anti-colocation '%s': primary role %s matches",
1023 colocation->id, role2text(colocation->primary_role));
1025 }
1026
1028}
1029
1041void
1043 const pe_resource_t *primary,
1044 const pcmk__colocation_t *colocation)
1045{
1046 const char *attribute = CRM_ATTR_ID;
1047 const char *value = NULL;
1048 GHashTable *work = NULL;
1049 GHashTableIter iter;
1050 pe_node_t *node = NULL;
1051
1052 if (colocation->node_attribute != NULL) {
1053 attribute = colocation->node_attribute;
1054 }
1055
1056 if (primary->allocated_to != NULL) {
1057 value = pe_node_attribute_raw(primary->allocated_to, attribute);
1058
1059 } else if (colocation->score < 0) {
1060 // Nothing to do (anti-colocation with something that is not running)
1061 return;
1062 }
1063
1064 work = pcmk__copy_node_table(dependent->allowed_nodes);
1065
1066 g_hash_table_iter_init(&iter, work);
1067 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1068 if (primary->allocated_to == NULL) {
1069 pe_rsc_trace(dependent, "%s: %s@%s -= %d (%s inactive)",
1070 colocation->id, dependent->id, pe__node_name(node),
1071 colocation->score, primary->id);
1072 node->weight = pcmk__add_scores(-colocation->score, node->weight);
1073
1074 } else if (pcmk__str_eq(pe_node_attribute_raw(node, attribute), value,
1075 pcmk__str_casei)) {
1076 if (colocation->score < CRM_SCORE_INFINITY) {
1077 pe_rsc_trace(dependent, "%s: %s@%s += %d",
1078 colocation->id, dependent->id,
1079 pe__node_name(node), colocation->score);
1080 node->weight = pcmk__add_scores(colocation->score,
1081 node->weight);
1082 }
1083
1084 } else if (colocation->score >= CRM_SCORE_INFINITY) {
1085 pe_rsc_trace(dependent, "%s: %s@%s -= %d (%s mismatch)",
1086 colocation->id, dependent->id, pe__node_name(node),
1087 colocation->score, attribute);
1088 node->weight = pcmk__add_scores(-colocation->score, node->weight);
1089 }
1090 }
1091
1092 if ((colocation->score <= -INFINITY) || (colocation->score >= INFINITY)
1093 || pcmk__any_node_available(work)) {
1094
1095 g_hash_table_destroy(dependent->allowed_nodes);
1096 dependent->allowed_nodes = work;
1097 work = NULL;
1098
1099 } else {
1100 pe_rsc_info(dependent,
1101 "%s: Rolling back scores from %s (no available nodes)",
1102 dependent->id, primary->id);
1103 }
1104
1105 if (work != NULL) {
1106 g_hash_table_destroy(work);
1107 }
1108}
1109
1121void
1123 const pe_resource_t *primary,
1124 const pcmk__colocation_t *colocation)
1125{
1126 const char *dependent_value = NULL;
1127 const char *primary_value = NULL;
1128 const char *attribute = CRM_ATTR_ID;
1129 int score_multiplier = 1;
1130
1131 if ((primary->allocated_to == NULL) || (dependent->allocated_to == NULL)) {
1132 return;
1133 }
1134
1135 if (colocation->node_attribute != NULL) {
1136 attribute = colocation->node_attribute;
1137 }
1138
1139 dependent_value = pe_node_attribute_raw(dependent->allocated_to, attribute);
1140 primary_value = pe_node_attribute_raw(primary->allocated_to, attribute);
1141
1142 if (!pcmk__str_eq(dependent_value, primary_value, pcmk__str_casei)) {
1143 if ((colocation->score == INFINITY)
1144 && (colocation->dependent_role == RSC_ROLE_PROMOTED)) {
1145 dependent->priority = -INFINITY;
1146 }
1147 return;
1148 }
1149
1150 if ((colocation->primary_role != RSC_ROLE_UNKNOWN)
1151 && (colocation->primary_role != primary->next_role)) {
1152 return;
1153 }
1154
1155 if (colocation->dependent_role == RSC_ROLE_UNPROMOTED) {
1156 score_multiplier = -1;
1157 }
1158
1159 dependent->priority = pcmk__add_scores(score_multiplier * colocation->score,
1160 dependent->priority);
1161}
1162
1171static int
1172best_node_score_matching_attr(const pe_resource_t *rsc, const char *attr,
1173 const char *value)
1174{
1175 GHashTableIter iter;
1176 pe_node_t *node = NULL;
1177 int best_score = -INFINITY;
1178 const char *best_node = NULL;
1179
1180 // Find best allowed node with matching attribute
1181 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1182 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1183
1184 if ((node->weight > best_score) && pcmk__node_available(node, false, false)
1185 && pcmk__str_eq(value, pe_node_attribute_raw(node, attr), pcmk__str_casei)) {
1186
1187 best_score = node->weight;
1188 best_node = node->details->uname;
1189 }
1190 }
1191
1192 if (!pcmk__str_eq(attr, CRM_ATTR_UNAME, pcmk__str_casei)) {
1193 if (best_node == NULL) {
1194 crm_info("No allowed node for %s matches node attribute %s=%s",
1195 rsc->id, attr, value);
1196 } else {
1197 crm_info("Allowed node %s for %s had best score (%d) "
1198 "of those matching node attribute %s=%s",
1199 best_node, rsc->id, best_score, attr, value);
1200 }
1201 }
1202 return best_score;
1203}
1204
1219static void
1220add_node_scores_matching_attr(GHashTable *nodes, const pe_resource_t *rsc,
1221 const char *attr, float factor,
1222 bool only_positive)
1223{
1224 GHashTableIter iter;
1225 pe_node_t *node = NULL;
1226
1227 if (attr == NULL) {
1228 attr = CRM_ATTR_UNAME;
1229 }
1230
1231 // Iterate through each node
1232 g_hash_table_iter_init(&iter, nodes);
1233 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1234 float weight_f = 0;
1235 int weight = 0;
1236 int score = 0;
1237 int new_score = 0;
1238
1239 score = best_node_score_matching_attr(rsc, attr,
1240 pe_node_attribute_raw(node, attr));
1241
1242 if ((factor < 0) && (score < 0)) {
1243 /* Negative preference for a node with a negative score
1244 * should not become a positive preference.
1245 *
1246 * @TODO Consider filtering only if weight is -INFINITY
1247 */
1248 crm_trace("%s: Filtering %d + %f * %d (double negative disallowed)",
1249 pe__node_name(node), node->weight, factor, score);
1250 continue;
1251 }
1252
1253 if (node->weight == INFINITY_HACK) {
1254 crm_trace("%s: Filtering %d + %f * %d (node was marked unusable)",
1255 pe__node_name(node), node->weight, factor, score);
1256 continue;
1257 }
1258
1259 weight_f = factor * score;
1260
1261 // Round the number; see http://c-faq.com/fp/round.html
1262 weight = (int) ((weight_f < 0)? (weight_f - 0.5) : (weight_f + 0.5));
1263
1264 /* Small factors can obliterate the small scores that are often actually
1265 * used in configurations. If the score and factor are nonzero, ensure
1266 * that the result is nonzero as well.
1267 */
1268 if ((weight == 0) && (score != 0)) {
1269 if (factor > 0.0) {
1270 weight = 1;
1271 } else if (factor < 0.0) {
1272 weight = -1;
1273 }
1274 }
1275
1276 new_score = pcmk__add_scores(weight, node->weight);
1277
1278 if (only_positive && (new_score < 0) && (node->weight > 0)) {
1279 crm_trace("%s: Filtering %d + %f * %d = %d "
1280 "(negative disallowed, marking node unusable)",
1281 pe__node_name(node), node->weight, factor, score,
1282 new_score);
1283 node->weight = INFINITY_HACK;
1284 continue;
1285 }
1286
1287 if (only_positive && (new_score < 0) && (node->weight == 0)) {
1288 crm_trace("%s: Filtering %d + %f * %d = %d (negative disallowed)",
1289 pe__node_name(node), node->weight, factor, score,
1290 new_score);
1291 continue;
1292 }
1293
1294 crm_trace("%s: %d + %f * %d = %d", pe__node_name(node),
1295 node->weight, factor, score, new_score);
1296 node->weight = new_score;
1297 }
1298}
1299
1316static GHashTable *
1317init_group_colocated_nodes(const pe_resource_t *rsc, const char *log_id,
1318 GHashTable **nodes, const char *attr, float factor,
1319 uint32_t flags)
1320{
1321 GHashTable *work = NULL;
1322 pe_resource_t *member = NULL;
1323
1324 // Ignore empty groups (only possible with schema validation disabled)
1325 if (rsc->children == NULL) {
1326 return NULL;
1327 }
1328
1329 if (*nodes == NULL) {
1330 // Only cmp_resources() passes a NULL nodes table
1331 member = pe__last_group_member(rsc);
1332 } else {
1333 /* The first member of the group will recursively incorporate any
1334 * constraints involving other members (including the group internal
1335 * colocation).
1336 *
1337 * @TODO The indirect colocations from the dependent group's other
1338 * members will be incorporated at full strength rather than by
1339 * factor, so the group's combined stickiness will be treated as
1340 * (factor + (#members - 1)) * stickiness. It is questionable what
1341 * the right approach should be.
1342 */
1343 member = rsc->children->data;
1344 }
1345
1346 pe_rsc_trace(rsc, "%s: Merging scores from group %s using member %s "
1347 "(at %.6f)", log_id, rsc->id, member->id, factor);
1348 work = pcmk__copy_node_table(*nodes);
1349 pcmk__add_colocated_node_scores(member, log_id, &work, attr, factor, flags);
1350 return work;
1351}
1352
1369static GHashTable *
1370init_nongroup_colocated_nodes(const pe_resource_t *rsc, const char *log_id,
1371 GHashTable **nodes, const char *attr,
1372 float factor, uint32_t flags)
1373{
1374 GHashTable *work = NULL;
1375
1376 if (*nodes == NULL) {
1377 /* Only cmp_resources() passes a NULL nodes table, which indicates we
1378 * should initialize it with the resource's allowed node scores.
1379 */
1381
1382 } else {
1383 pe_rsc_trace(rsc, "%s: Merging scores from %s (at %.6f)",
1384 log_id, rsc->id, factor);
1385 work = pcmk__copy_node_table(*nodes);
1386 add_node_scores_matching_attr(work, rsc, attr, factor,
1389 }
1390 return work;
1391}
1392
1410void
1412 GHashTable **nodes, const char *attr,
1413 float factor, uint32_t flags)
1414{
1415 GHashTable *work = NULL;
1416
1417 CRM_CHECK((rsc != NULL) && (nodes != NULL), return);
1418
1419 if (log_id == NULL) {
1420 log_id = rsc->id;
1421 }
1422
1423 // Avoid infinite recursion
1424 if (pcmk_is_set(rsc->flags, pe_rsc_merging)) {
1425 pe_rsc_info(rsc, "%s: Breaking dependency loop at %s",
1426 log_id, rsc->id);
1427 return;
1428 }
1430
1431 if (rsc->variant == pe_group) {
1432 work = init_group_colocated_nodes(rsc, log_id, nodes, attr, factor,
1433 flags);
1434 } else {
1435 work = init_nongroup_colocated_nodes(rsc, log_id, nodes, attr, factor,
1436 flags);
1437 }
1438 if (work == NULL) {
1440 return;
1441 }
1442
1443 if (pcmk__any_node_available(work)) {
1444 GList *gIter = NULL;
1445 float multiplier = (factor < 0.0)? -1.0 : 1.0;
1446
1448 gIter = rsc->rsc_cons;
1449 pe_rsc_trace(rsc,
1450 "Checking additional %d optional '%s with' constraints",
1451 g_list_length(gIter), rsc->id);
1452
1453 } else if (rsc->variant == pe_group) {
1454 pe_resource_t *last_rsc = pe__last_group_member(rsc);
1455
1456 gIter = last_rsc->rsc_cons_lhs;
1457 pe_rsc_trace(rsc, "Checking additional %d optional 'with group %s' "
1458 "constraints using last member %s",
1459 g_list_length(gIter), rsc->id, last_rsc->id);
1460
1461 } else {
1462 gIter = rsc->rsc_cons_lhs;
1463 pe_rsc_trace(rsc,
1464 "Checking additional %d optional 'with %s' constraints",
1465 g_list_length(gIter), rsc->id);
1466 }
1467
1468 for (; gIter != NULL; gIter = gIter->next) {
1469 pe_resource_t *other = NULL;
1470 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
1471
1473 other = constraint->primary;
1474 } else if (!pcmk__colocation_has_influence(constraint, NULL)) {
1475 continue;
1476 } else {
1477 other = constraint->dependent;
1478 }
1479
1480 pe_rsc_trace(rsc, "Optionally merging score of '%s' constraint (%s with %s)",
1481 constraint->id, constraint->dependent->id,
1482 constraint->primary->id);
1483 factor = multiplier * constraint->score / (float) INFINITY;
1484 pcmk__add_colocated_node_scores(other, log_id, &work,
1485 constraint->node_attribute, factor,
1487 pe__show_node_weights(true, NULL, log_id, work, rsc->cluster);
1488 }
1489
1491 pe_rsc_info(rsc, "%s: Rolling back optional scores from %s",
1492 log_id, rsc->id);
1493 g_hash_table_destroy(work);
1495 return;
1496 }
1497
1498
1500 pe_node_t *node = NULL;
1501 GHashTableIter iter;
1502
1503 g_hash_table_iter_init(&iter, work);
1504 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1505 if (node->weight == INFINITY_HACK) {
1506 node->weight = 1;
1507 }
1508 }
1509 }
1510
1511 if (*nodes != NULL) {
1512 g_hash_table_destroy(*nodes);
1513 }
1514 *nodes = work;
1515
1517}
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition: nvpair.c:948
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition: nvpair.c:975
uint64_t flags
Definition: remote.c:3
Utility functions.
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:113
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:454
@ 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:483
#define RSC_ROLE_UNKNOWN_S
Definition: common.h:110
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:912
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 xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, pe_working_set_t *data_set)
@ 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 bool pcmk__valid_resource_or_tag(pe_working_set_t *data_set, const char *id, pe_resource_t **rsc, pe_tag_t **tag)
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, 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:362
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_log_xml_trace(xml, text)
Definition: logging.h:373
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
#define XML_COLOC_ATTR_SOURCE_ROLE
Definition: msg_xml.h:361
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:216
#define ID(x)
Definition: msg_xml.h:468
#define XML_COLOC_ATTR_NODE_ATTR
Definition: msg_xml.h:364
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:336
#define XML_CONS_TAG_RSC_SET
Definition: msg_xml.h:355
#define XML_COLOC_ATTR_TARGET_ROLE
Definition: msg_xml.h:363
#define XML_COLOC_ATTR_TARGET_INSTANCE
Definition: msg_xml.h:371
#define XML_ATTR_ID
Definition: msg_xml.h:134
#define XML_COLOC_ATTR_SOURCE_INSTANCE
Definition: msg_xml.h:368
#define XML_COLOC_ATTR_INFLUENCE
Definition: msg_xml.h:365
#define XML_CONS_ATTR_SYMMETRICAL
Definition: msg_xml.h:356
#define XML_COLOC_ATTR_TARGET
Definition: msg_xml.h:362
#define XML_COLOC_ATTR_SOURCE
Definition: msg_xml.h:360
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:517
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:323
const char * action
Definition: pcmk_fence.c:30
void pcmk__add_with_this(pe_resource_t *rsc, pcmk__colocation_t *colocation)
void pcmk__block_colocation_dependents(pe_action_t *action, pe_working_set_t *data_set)
#define INFINITY_HACK
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__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)
void pcmk__add_this_with(pe_resource_t *rsc, pcmk__colocation_t *colocation)
@ pe_order_anti_colocation
Definition: pe_types.h:514
#define pe_rsc_provisional
Definition: pe_types.h:266
@ pe_action_runnable
Definition: pe_types.h:300
#define pe_rsc_merging
Definition: pe_types.h:268
@ pe_group
Definition: pe_types.h:39
@ pe_clone
Definition: pe_types.h:40
#define pe_rsc_promotable
Definition: pe_types.h:264
#define pe_rsc_critical
Definition: pe_types.h:274
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:394
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: internal.h:172
const char * pe_node_attribute_raw(const pe_node_t *node, const char *name)
Definition: common.c:562
pe_resource_t * pe__last_group_member(const pe_resource_t *group)
Definition: group.c:37
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1296
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
@ pe_wo_coloc_inst
Definition: internal.h:165
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:45
pe_resource_t * find_clone_instance(pe_resource_t *rsc, const char *sub_id, pe_working_set_t *data_set)
Definition: clone.c:167
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1447
#define CRM_ASSERT(expr)
Definition: results.h:42
@ pcmk_rc_ok
Definition: results.h:148
@ pcmk_rc_unpack_error
Definition: results.h:112
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
int weight
Definition: pe_types.h:249
struct pe_node_shared_s * details
Definition: pe_types.h:252
GList * actions
Definition: pe_types.h:366
enum pe_obj_types variant
Definition: pe_types.h:338
GList * rsc_cons
Definition: pe_types.h:364
GList * rsc_cons_lhs
Definition: pe_types.h:363
GList * children
Definition: pe_types.h:384
pe_working_set_t * cluster
Definition: pe_types.h:335
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
pe_node_t * allocated_to
Definition: pe_types.h:370
unsigned long long flags
Definition: pe_types.h:355
pe_resource_t * parent
Definition: pe_types.h:336
enum rsc_role_e next_role
Definition: pe_types.h:378
GList * colocation_constraints
Definition: pe_types.h:168
xmlNode * input
Definition: pe_types.h:144
GList * resources
Definition: pe_types.h:165
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:3002
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956
void free_xml(xmlNode *child)
Definition: xml.c:885
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:891
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:2145