pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
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"
22 #include "libpacemaker_private.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 
35 static gint
36 cmp_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 
85 static gint
86 cmp_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 
142 void
143 pcmk__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 
167 void
168 pcmk__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 
193 void
194 pcmk__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 
218 void
219 pcmk__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 
244 static void
245 anti_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 
302 void
303 pcmk__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 
376 static bool
377 unpack_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 
394 static void
395 unpack_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),
480  pcmk__str_casei)) {
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 
494 static void
495 colocate_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
517  xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
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 
586 static void
587 unpack_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
685 static int
686 unpack_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));
713  return pcmk_rc_unpack_error;
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);
733  return pcmk_rc_unpack_error;
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);
740  return pcmk_rc_unpack_error;
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);
752  return pcmk_rc_unpack_error;
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;
765  return pcmk_rc_unpack_error;
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;
782  return pcmk_rc_unpack_error;
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 
811 void
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 
876 static void
877 mark_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 
913 void
916 {
917  GList *gIter = NULL;
918  GList *colocations = NULL;
919  pe_resource_t *rsc = NULL;
920  bool is_start = false;
921 
922  if (pcmk_is_set(action->flags, pe_action_runnable)) {
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  */
1027  return pcmk__coloc_affects_role;
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 
1118 void
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),
1151  pcmk_readable_score(node->weight),
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),
1169  pcmk_readable_score(node->weight),
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 
1217 void
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 
1273 static int
1274 best_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 
1321 static void
1322 add_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 
1419 void
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  */
1444  work = pcmk__copy_node_table(rsc->allowed_nodes);
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 
1535 void
1536 pcmk__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;
1543  uint32_t flags = pcmk__coloc_select_active;
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 
1569 GList *
1571 {
1572  GList *list = NULL;
1573 
1574  rsc->cmds->with_this_colocations(rsc, rsc, &list);
1575  return list;
1576 }
1577 
1588 GList *
1590 {
1591  GList *list = NULL;
1592 
1593  rsc->cmds->this_with_colocations(rsc, rsc, &list);
1594  return list;
1595 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
A dumping ground.
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:99
GList * rsc_cons
Definition: pe_types.h:389
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:385
pcmk__coloc_affects
void pcmk__unpack_colocation(xmlNode *xml_obj, pe_working_set_t *data_set)
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:86
#define XML_COLOC_ATTR_TARGET_INSTANCE
Definition: msg_xml.h:383
G_GNUC_INTERNAL bool pcmk__any_node_available(GHashTable *nodes)
#define pcmk__config_warn(fmt...)
#define RSC_ROLE_STARTED_S
Definition: common.h:112
void pcmk__add_with_this_list(GList **list, GList *addition)
GList * children
Definition: pe_types.h:409
resource_alloc_functions_t * cmds
Definition: pe_types.h:359
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:351
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2521
enum rsc_role_e next_role
Definition: pe_types.h:403
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:1298
int char2score(const char *score)
Get the integer value of a score string.
Definition: scores.c:36
#define pcmk__config_err(fmt...)
void(* with_this_colocations)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
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
#define CRMD_ACTION_PROMOTE
Definition: crm.h:180
pe_resource_t * dependent
#define pe_rsc_critical
Definition: pe_types.h:290
GList * rsc_cons_lhs
Definition: pe_types.h:388
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition: nvpair.c:954
void pcmk__add_with_this(GList **list, const pcmk__colocation_t *colocation)
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pe_working_set_t *data_set)
#define RSC_START
Definition: crm.h:199
#define XML_COLOC_ATTR_TARGET_ROLE
Definition: msg_xml.h:375
pe_node_t * allocated_to
Definition: pe_types.h:395
#define CRM_SCORE_INFINITY
Definition: crm.h:85
#define XML_CONS_TAG_RSC_SET
Definition: msg_xml.h:367
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)
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:77
GList * resources
Definition: pe_types.h:181
#define CRMD_ACTION_START
Definition: crm.h:174
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:819
#define pe_rsc_provisional
Definition: pe_types.h:282
const char * role2text(enum rsc_role_e role)
Definition: common.c:450
GList * pcmk__with_this_colocations(const pe_resource_t *rsc)
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)
#define CRMD_ACTION_STOP
Definition: crm.h:177
#define pe_rsc_merging
Definition: pe_types.h:284
GList * pcmk__this_with_colocations(const pe_resource_t *rsc)
#define CRMD_ACTION_DEMOTE
Definition: crm.h:182
#define XML_COLOC_ATTR_TARGET
Definition: msg_xml.h:374
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1449
void pcmk__add_colocated_node_scores(pe_resource_t *rsc, const char *log_id, GHashTable **nodes, const char *attr, float factor, uint32_t flags)
G_GNUC_INTERNAL bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:922
Utility functions.
#define XML_ATTR_ID
Definition: msg_xml.h:147
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
const char * pe_node_attribute_raw(const pe_node_t *node, const char *name)
Definition: common.c:558
void pcmk__apply_coloc_to_priority(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation)
pe_resource_t * primary
#define pe_warn_once(pe_wo_bit, fmt...)
Definition: internal.h:177
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:98
#define CRM_ATTR_UNAME
Definition: crm.h:113
#define crm_trace(fmt, args...)
Definition: logging.h:383
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
void pcmk__apply_coloc_to_weights(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation)
struct pe_node_shared_s * details
Definition: pe_types.h:268
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:2593
void pcmk__block_colocation_dependents(pe_action_t *action, pe_working_set_t *data_set)
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition: nvpair.c:927
unsigned long long flags
Definition: pe_types.h:373
#define pe_rsc_promotable
Definition: pe_types.h:280
pe_working_set_t * data_set
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)
GList * actions
Definition: pe_types.h:391
#define XML_COLOC_ATTR_SOURCE_INSTANCE
Definition: msg_xml.h:380
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:229
pe_resource_t * find_clone_instance(const pe_resource_t *rsc, const char *sub_id)
Definition: clone.c:226
void free_xml(xmlNode *child)
Definition: xml.c:813
enum rsc_role_e text2role(const char *role)
Definition: common.c:479
enum pe_obj_types variant
Definition: pe_types.h:356
xmlNode * input
Definition: pe_types.h:160
void(* this_with_colocations)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
G_GNUC_INTERNAL pe_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
uint32_t id
Definition: cpg.c:45
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
#define XML_COLOC_ATTR_SOURCE_ROLE
Definition: msg_xml.h:373
#define XML_COLOC_ATTR_NODE_ATTR
Definition: msg_xml.h:376
void pcmk__add_this_with(GList **list, const pcmk__colocation_t *colocation)
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:427
void pcmk__add_this_with_list(GList **list, GList *addition)
G_GNUC_INTERNAL void pcmk__update_action_for_orderings(pe_action_t *action, pe_working_set_t *data_set)
Cluster status and scheduling.
#define XML_COLOC_ATTR_INFLUENCE
Definition: msg_xml.h:377
G_GNUC_INTERNAL GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define crm_err(fmt, args...)
Definition: logging.h:377
#define CRM_ASSERT(expr)
Definition: results.h:42
#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name)
#define RSC_PROMOTE
Definition: crm.h:205
GList * colocation_constraints
Definition: pe_types.h:184
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:1735
#define INFINITY_HACK
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:83
enum pcmk__coloc_affects pcmk__colocation_affects(const pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool preview)
pe_working_set_t * cluster
Definition: pe_types.h:353
const char * node_attribute
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:116
#define RSC_ROLE_UNKNOWN_S
Definition: common.h:110
#define crm_log_xml_trace(xml, text)
Definition: logging.h:391
void pcmk__add_dependent_scores(gpointer data, gpointer user_data)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:50
#define ID(x)
Definition: msg_xml.h:480
#define CRM_ATTR_ID
Definition: crm.h:114
#define XML_CONS_ATTR_SYMMETRICAL
Definition: msg_xml.h:368
#define crm_info(fmt, args...)
Definition: logging.h:380
#define XML_COLOC_ATTR_SOURCE
Definition: msg_xml.h:372
uint64_t flags
Definition: remote.c:215
void(* add_colocated_node_scores)(pe_resource_t *rsc, const char *log_id, GHashTable **nodes, const char *attr, float factor, uint32_t flags)
pe_resource_t * parent
Definition: pe_types.h:354
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:48
char * id
Definition: pe_types.h:347
GHashTable * allowed_nodes
Definition: pe_types.h:400
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2547