pacemaker  2.1.5-b7adf64e51
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"
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 
140 void
142 {
143  rsc->rsc_cons = g_list_insert_sorted(rsc->rsc_cons, colocation,
144  cmp_primary_priority);
145 }
146 
154 void
156 {
157  rsc->rsc_cons_lhs = g_list_insert_sorted(rsc->rsc_cons_lhs, colocation,
158  cmp_dependent_priority);
159 }
160 
165 static void
166 anti_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 
224 void
225 pcmk__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 
298 static bool
299 unpack_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 
316 static void
317 unpack_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),
402  pcmk__str_casei)) {
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 
416 static void
417 colocate_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
439  xml_rsc = first_named_child(set1, XML_TAG_RESOURCE_REF);
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 
508 static void
509 unpack_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
607 static int
608 unpack_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));
635  return pcmk_rc_unpack_error;
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);
655  return pcmk_rc_unpack_error;
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);
662  return pcmk_rc_unpack_error;
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);
674  return pcmk_rc_unpack_error;
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;
687  return pcmk_rc_unpack_error;
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;
704  return pcmk_rc_unpack_error;
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 
733 void
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 
798 static void
799 mark_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 
835 void
838 {
839  GList *gIter = NULL;
840  pe_resource_t *rsc = NULL;
841  bool is_start = false;
842 
843  if (pcmk_is_set(action->flags, pe_action_runnable)) {
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)
943  && pcmk_is_set(dependent->parent->flags, pe_rsc_promotable)
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 
1041 void
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 
1121 void
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 
1171 static int
1172 best_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 
1219 static void
1220 add_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 
1316 static GHashTable *
1317 init_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 
1369 static GHashTable *
1370 init_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  */
1380  work = pcmk__copy_node_table(rsc->allowed_nodes);
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 
1410 void
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 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
A dumping ground.
#define INFINITY
Definition: crm.h:99
GList * rsc_cons
Definition: pe_types.h:364
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:394
pcmk__coloc_affects
void pcmk__unpack_colocation(xmlNode *xml_obj, pe_working_set_t *data_set)
#define XML_COLOC_ATTR_TARGET_INSTANCE
Definition: msg_xml.h:371
G_GNUC_INTERNAL bool pcmk__any_node_available(GHashTable *nodes)
#define pcmk__config_warn(fmt...)
#define RSC_ROLE_STARTED_S
Definition: common.h:112
GList * children
Definition: pe_types.h:384
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:336
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
enum rsc_role_e next_role
Definition: pe_types.h:378
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
int char2score(const char *score)
Get the integer value of a score string.
Definition: scores.c:36
#define pcmk__config_err(fmt...)
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
#define CRMD_ACTION_PROMOTE
Definition: crm.h:180
pe_resource_t * dependent
void pcmk__add_this_with(pe_resource_t *rsc, pcmk__colocation_t *colocation)
#define pe_rsc_critical
Definition: pe_types.h:274
GList * rsc_cons_lhs
Definition: pe_types.h:363
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition: nvpair.c:975
#define RSC_START
Definition: crm.h:199
#define XML_COLOC_ATTR_TARGET_ROLE
Definition: msg_xml.h:363
pe_node_t * allocated_to
Definition: pe_types.h:370
#define CRM_SCORE_INFINITY
Definition: crm.h:85
#define XML_CONS_TAG_RSC_SET
Definition: msg_xml.h:355
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
GList * resources
Definition: pe_types.h:165
#define CRMD_ACTION_START
Definition: crm.h:174
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, pe_working_set_t *data_set)
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:891
#define pe_rsc_provisional
Definition: pe_types.h:266
const char * role2text(enum rsc_role_e role)
Definition: common.c:454
#define CRMD_ACTION_STOP
Definition: crm.h:177
#define pe_rsc_merging
Definition: pe_types.h:268
#define CRMD_ACTION_DEMOTE
Definition: crm.h:182
#define XML_COLOC_ATTR_TARGET
Definition: msg_xml.h:362
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1447
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:912
Utility functions.
#define XML_ATTR_ID
Definition: msg_xml.h:134
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
const char * pe_node_attribute_raw(const pe_node_t *node, const char *name)
Definition: common.c:562
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:172
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
#define CRM_ATTR_UNAME
Definition: crm.h:113
#define crm_trace(fmt, args...)
Definition: logging.h:365
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:252
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:3002
void pcmk__block_colocation_dependents(pe_action_t *action, pe_working_set_t *data_set)
pe_resource_t * find_clone_instance(pe_resource_t *rsc, const char *sub_id, pe_working_set_t *data_set)
Definition: clone.c:167
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
Definition: nvpair.c:948
unsigned long long flags
Definition: pe_types.h:355
#define pe_rsc_promotable
Definition: pe_types.h:264
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:366
#define XML_COLOC_ATTR_SOURCE_INSTANCE
Definition: msg_xml.h:368
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:216
void free_xml(xmlNode *child)
Definition: xml.c:885
enum rsc_role_e text2role(const char *role)
Definition: common.c:483
enum pe_obj_types variant
Definition: pe_types.h:338
xmlNode * input
Definition: pe_types.h:144
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:361
#define XML_COLOC_ATTR_NODE_ATTR
Definition: msg_xml.h:364
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:427
pe_resource_t * pe__last_group_member(const pe_resource_t *group)
Definition: group.c:37
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:365
G_GNUC_INTERNAL GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define crm_err(fmt, args...)
Definition: logging.h:359
#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:168
void pcmk__add_with_this(pe_resource_t *rsc, pcmk__colocation_t *colocation)
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:2145
#define INFINITY_HACK
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
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:335
const char * node_attribute
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:113
#define RSC_ROLE_UNKNOWN_S
Definition: common.h:110
#define crm_log_xml_trace(xml, text)
Definition: logging.h:373
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define ID(x)
Definition: msg_xml.h:468
#define CRM_ATTR_ID
Definition: crm.h:114
#define XML_CONS_ATTR_SYMMETRICAL
Definition: msg_xml.h:356
#define crm_info(fmt, args...)
Definition: logging.h:362
#define XML_COLOC_ATTR_SOURCE
Definition: msg_xml.h:360
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)
uint64_t flags
Definition: remote.c:215
pe_resource_t * parent
Definition: pe_types.h:336
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:45
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)
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956