pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
pcmk_sched_location.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 "libpacemaker_private.h"
20 
21 static int
22 get_node_score(const char *rule, const char *score, bool raw,
23  pe_node_t *node, pe_resource_t *rsc)
24 {
25  int score_f = 0;
26 
27  if (score == NULL) {
28  pe_err("Rule %s: no score specified. Assuming 0.", rule);
29 
30  } else if (raw) {
31  score_f = char2score(score);
32 
33  } else {
34  const char *attr_score = pe_node_attribute_calculated(node, score, rsc);
35 
36  if (attr_score == NULL) {
37  crm_debug("Rule %s: %s did not have a value for %s",
38  rule, pe__node_name(node), score);
39  score_f = -INFINITY;
40 
41  } else {
42  crm_debug("Rule %s: %s had value %s for %s",
43  rule, pe__node_name(node), attr_score, score);
44  score_f = char2score(attr_score);
45  }
46  }
47  return score_f;
48 }
49 
50 static pe__location_t *
51 generate_location_rule(pe_resource_t *rsc, xmlNode *rule_xml,
52  const char *discovery, crm_time_t *next_change,
54  pe_re_match_data_t *re_match_data)
55 {
56  const char *rule_id = NULL;
57  const char *score = NULL;
58  const char *boolean = NULL;
59  const char *role = NULL;
60 
61  GList *gIter = NULL;
62  GList *match_L = NULL;
63 
64  bool do_and = true;
65  bool accept = true;
66  bool raw_score = true;
67  bool score_allocated = false;
68 
69  pe__location_t *location_rule = NULL;
70 
71  rule_xml = expand_idref(rule_xml, data_set->input);
72  if (rule_xml == NULL) {
73  return NULL;
74  }
75 
76  rule_id = crm_element_value(rule_xml, XML_ATTR_ID);
77  boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP);
78  role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE);
79 
80  crm_trace("Processing rule: %s", rule_id);
81 
82  if ((role != NULL) && (text2role(role) == RSC_ROLE_UNKNOWN)) {
83  pe_err("Bad role specified for %s: %s", rule_id, role);
84  return NULL;
85  }
86 
87  score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE);
88  if (score == NULL) {
90  if (score != NULL) {
91  raw_score = false;
92  }
93  }
94  if (pcmk__str_eq(boolean, "or", pcmk__str_casei)) {
95  do_and = false;
96  }
97 
98  location_rule = pcmk__new_location(rule_id, rsc, 0, discovery, NULL,
99  data_set);
100 
101  if (location_rule == NULL) {
102  return NULL;
103  }
104 
105  if ((re_match_data != NULL) && (re_match_data->nregs > 0)
106  && (re_match_data->pmatch[0].rm_so != -1) && !raw_score) {
107 
108  char *result = pe_expand_re_matches(score, re_match_data);
109 
110  if (result != NULL) {
111  score = result;
112  score_allocated = true;
113  }
114  }
115 
116  if (role != NULL) {
117  crm_trace("Setting role filter: %s", role);
118  location_rule->role_filter = text2role(role);
119  if (location_rule->role_filter == RSC_ROLE_UNPROMOTED) {
120  /* Any promotable clone cannot be promoted without being in the
121  * unpromoted role first. Ergo, any constraint for the unpromoted
122  * role applies to every role.
123  */
124  location_rule->role_filter = RSC_ROLE_UNKNOWN;
125  }
126  }
127  if (do_and) {
128  GList *gIter = NULL;
129 
130  match_L = pcmk__copy_node_list(data_set->nodes, true);
131  for (gIter = match_L; gIter != NULL; gIter = gIter->next) {
132  pe_node_t *node = (pe_node_t *) gIter->data;
133 
134  node->weight = get_node_score(rule_id, score, raw_score, node, rsc);
135  }
136  }
137 
138  for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
139  int score_f = 0;
140  pe_node_t *node = (pe_node_t *) gIter->data;
141  pe_match_data_t match_data = {
142  .re = re_match_data,
143  .params = pe_rsc_params(rsc, node, data_set),
144  .meta = rsc->meta,
145  };
146 
147  accept = pe_test_rule(rule_xml, node->details->attrs, RSC_ROLE_UNKNOWN,
148  data_set->now, next_change, &match_data);
149 
150  crm_trace("Rule %s %s on %s", ID(rule_xml), accept? "passed" : "failed",
151  pe__node_name(node));
152 
153  score_f = get_node_score(rule_id, score, raw_score, node, rsc);
154 
155  if (accept) {
156  pe_node_t *local = pe_find_node_id(match_L, node->details->id);
157 
158  if ((local == NULL) && do_and) {
159  continue;
160 
161  } else if (local == NULL) {
162  local = pe__copy_node(node);
163  match_L = g_list_append(match_L, local);
164  }
165 
166  if (!do_and) {
167  local->weight = pcmk__add_scores(local->weight, score_f);
168  }
169  crm_trace("%s has score %s after %s", pe__node_name(node),
170  pcmk_readable_score(local->weight), rule_id);
171 
172  } else if (do_and && !accept) {
173  // Remove it
174  pe_node_t *delete = pe_find_node_id(match_L, node->details->id);
175 
176  if (delete != NULL) {
177  match_L = g_list_remove(match_L, delete);
178  crm_trace("%s did not match", pe__node_name(node));
179  }
180  free(delete);
181  }
182  }
183 
184  if (score_allocated) {
185  free((char *)score);
186  }
187 
188  location_rule->node_list_rh = match_L;
189  if (location_rule->node_list_rh == NULL) {
190  crm_trace("No matching nodes for rule %s", rule_id);
191  return NULL;
192  }
193 
194  crm_trace("%s: %d nodes matched",
195  rule_id, g_list_length(location_rule->node_list_rh));
196  return location_rule;
197 }
198 
199 static void
200 unpack_rsc_location(xmlNode *xml_obj, pe_resource_t *rsc, const char *role,
201  const char *score, pe_working_set_t *data_set,
202  pe_re_match_data_t *re_match_data)
203 {
204  pe__location_t *location = NULL;
205  const char *rsc_id = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
206  const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
207  const char *node = crm_element_value(xml_obj, XML_CIB_TAG_NODE);
208  const char *discovery = crm_element_value(xml_obj, XML_LOCATION_ATTR_DISCOVERY);
209 
210  if (rsc == NULL) {
211  pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
212  "does not exist", id, rsc_id);
213  return;
214  }
215 
216  if (score == NULL) {
217  score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
218  }
219 
220  if ((node != NULL) && (score != NULL)) {
221  int score_i = char2score(score);
222  pe_node_t *match = pe_find_node(data_set->nodes, node);
223 
224  if (!match) {
225  return;
226  }
227  location = pcmk__new_location(id, rsc, score_i, discovery, match,
228  data_set);
229 
230  } else {
231  bool empty = true;
232  crm_time_t *next_change = crm_time_new_undefined();
233 
234  /* This loop is logically parallel to pe_evaluate_rules(), except
235  * instead of checking whether any rule is active, we set up location
236  * constraints for each active rule.
237  */
238  for (xmlNode *rule_xml = first_named_child(xml_obj, XML_TAG_RULE);
239  rule_xml != NULL; rule_xml = crm_next_same_xml(rule_xml)) {
240  empty = false;
241  crm_trace("Unpacking %s/%s", id, ID(rule_xml));
242  generate_location_rule(rsc, rule_xml, discovery, next_change,
243  data_set, re_match_data);
244  }
245 
246  if (empty) {
247  pcmk__config_err("Ignoring constraint '%s' because it contains "
248  "no rules", id);
249  }
250 
251  /* If there is a point in the future when the evaluation of a rule will
252  * change, make sure the scheduler is re-run by that time.
253  */
254  if (crm_time_is_defined(next_change)) {
255  time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change);
256 
258  }
259  crm_time_free(next_change);
260  return;
261  }
262 
263  if (role == NULL) {
264  role = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
265  }
266 
267  if ((location != NULL) && (role != NULL)) {
268  if (text2role(role) == RSC_ROLE_UNKNOWN) {
269  pe_err("Invalid constraint %s: Bad role %s", id, role);
270  return;
271 
272  } else {
273  enum rsc_role_e r = text2role(role);
274  switch(r) {
275  case RSC_ROLE_UNKNOWN:
276  case RSC_ROLE_STARTED:
277  case RSC_ROLE_UNPROMOTED:
278  /* Applies to all */
279  location->role_filter = RSC_ROLE_UNKNOWN;
280  break;
281  default:
282  location->role_filter = r;
283  break;
284  }
285  }
286  }
287 }
288 
289 static void
290 unpack_simple_location(xmlNode *xml_obj, pe_working_set_t *data_set)
291 {
292  const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
293  const char *value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
294 
295  if (value) {
296  pe_resource_t *rsc;
297 
299  unpack_rsc_location(xml_obj, rsc, NULL, NULL, data_set, NULL);
300  }
301 
303  if (value) {
304  regex_t *r_patt = calloc(1, sizeof(regex_t));
305  bool invert = false;
306  GList *rIter = NULL;
307 
308  if (value[0] == '!') {
309  value++;
310  invert = true;
311  }
312 
313  if (regcomp(r_patt, value, REG_EXTENDED) != 0) {
314  pcmk__config_err("Ignoring constraint '%s' because "
316  " has invalid value '%s'", id, value);
317  free(r_patt);
318  return;
319  }
320 
321  for (rIter = data_set->resources; rIter; rIter = rIter->next) {
322  pe_resource_t *r = rIter->data;
323  int nregs = 0;
324  regmatch_t *pmatch = NULL;
325  int status;
326 
327  if(r_patt->re_nsub > 0) {
328  nregs = r_patt->re_nsub + 1;
329  } else {
330  nregs = 1;
331  }
332  pmatch = calloc(nregs, sizeof(regmatch_t));
333 
334  status = regexec(r_patt, r->id, nregs, pmatch, 0);
335 
336  if (!invert && (status == 0)) {
337  pe_re_match_data_t re_match_data = {
338  .string = r->id,
339  .nregs = nregs,
340  .pmatch = pmatch
341  };
342 
343  crm_debug("'%s' matched '%s' for %s", r->id, value, id);
344  unpack_rsc_location(xml_obj, r, NULL, NULL, data_set,
345  &re_match_data);
346 
347  } else if (invert && (status != 0)) {
348  crm_debug("'%s' is an inverted match of '%s' for %s",
349  r->id, value, id);
350  unpack_rsc_location(xml_obj, r, NULL, NULL, data_set, NULL);
351 
352  } else {
353  crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
354  }
355 
356  free(pmatch);
357  }
358 
359  regfree(r_patt);
360  free(r_patt);
361  }
362 }
363 
364 // \return Standard Pacemaker return code
365 static int
366 unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
368 {
369  const char *id = NULL;
370  const char *rsc_id = NULL;
371  const char *state = NULL;
372  pe_resource_t *rsc = NULL;
373  pe_tag_t *tag = NULL;
374  xmlNode *rsc_set = NULL;
375 
376  *expanded_xml = NULL;
377 
378  CRM_CHECK(xml_obj != NULL, return EINVAL);
379 
380  id = ID(xml_obj);
381  if (id == NULL) {
382  pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
383  crm_element_name(xml_obj));
384  return pcmk_rc_unpack_error;
385  }
386 
387  // Check whether there are any resource sets with template or tag references
388  *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, data_set);
389  if (*expanded_xml != NULL) {
390  crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
391  return pcmk_rc_ok;
392  }
393 
394  rsc_id = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
395  if (rsc_id == NULL) {
396  return pcmk_rc_ok;
397  }
398 
399  if (!pcmk__valid_resource_or_tag(data_set, rsc_id, &rsc, &tag)) {
400  pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
401  "valid resource or tag", id, rsc_id);
402  return pcmk_rc_unpack_error;
403 
404  } else if (rsc != NULL) {
405  // No template is referenced
406  return pcmk_rc_ok;
407  }
408 
409  state = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
410 
411  *expanded_xml = copy_xml(xml_obj);
412 
413  // Convert template/tag reference in "rsc" into resource_set under constraint
414  if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, XML_LOC_ATTR_SOURCE,
415  false, data_set)) {
416  free_xml(*expanded_xml);
417  *expanded_xml = NULL;
418  return pcmk_rc_unpack_error;
419  }
420 
421  if (rsc_set != NULL) {
422  if (state != NULL) {
423  // Move "rsc-role" into converted resource_set as "role" attribute
424  crm_xml_add(rsc_set, "role", state);
425  xml_remove_prop(*expanded_xml, XML_RULE_ATTR_ROLE);
426  }
427  crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
428 
429  } else {
430  // No sets
431  free_xml(*expanded_xml);
432  *expanded_xml = NULL;
433  }
434 
435  return pcmk_rc_ok;
436 }
437 
438 // \return Standard Pacemaker return code
439 static int
440 unpack_location_set(xmlNode *location, xmlNode *set, pe_working_set_t *data_set)
441 {
442  xmlNode *xml_rsc = NULL;
443  pe_resource_t *resource = NULL;
444  const char *set_id;
445  const char *role;
446  const char *local_score;
447 
448  CRM_CHECK(set != NULL, return EINVAL);
449 
450  set_id = ID(set);
451  if (set_id == NULL) {
452  pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_SET " without "
453  XML_ATTR_ID " in constraint '%s'",
454  pcmk__s(ID(location), "(missing ID)"));
455  return pcmk_rc_unpack_error;
456  }
457 
458  role = crm_element_value(set, "role");
459  local_score = crm_element_value(set, XML_RULE_ATTR_SCORE);
460 
461  for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
462  xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
463 
465  ID(xml_rsc));
466  if (resource == NULL) {
467  pcmk__config_err("%s: No resource found for %s",
468  set_id, ID(xml_rsc));
469  return pcmk_rc_unpack_error;
470  }
471 
472  unpack_rsc_location(location, resource, role, local_score, data_set,
473  NULL);
474  }
475 
476  return pcmk_rc_ok;
477 }
478 
479 void
481 {
482  xmlNode *set = NULL;
483  bool any_sets = false;
484 
485  xmlNode *orig_xml = NULL;
486  xmlNode *expanded_xml = NULL;
487 
488  if (unpack_location_tags(xml_obj, &expanded_xml, data_set) != pcmk_rc_ok) {
489  return;
490  }
491 
492  if (expanded_xml) {
493  orig_xml = xml_obj;
494  xml_obj = expanded_xml;
495  }
496 
497  for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
498  set = crm_next_same_xml(set)) {
499 
500  any_sets = true;
501  set = expand_idref(set, data_set->input);
502  if ((set == NULL) // Configuration error, message already logged
503  || (unpack_location_set(xml_obj, set, data_set) != pcmk_rc_ok)) {
504 
505  if (expanded_xml) {
506  free_xml(expanded_xml);
507  }
508  return;
509  }
510  }
511 
512  if (expanded_xml) {
513  free_xml(expanded_xml);
514  xml_obj = orig_xml;
515  }
516 
517  if (!any_sets) {
518  unpack_simple_location(xml_obj, data_set);
519  }
520 }
521 
538 pcmk__new_location(const char *id, pe_resource_t *rsc,
539  int node_weight, const char *discover_mode,
541 {
542  pe__location_t *new_con = NULL;
543 
544  if (id == NULL) {
545  pe_err("Invalid constraint: no ID specified");
546  return NULL;
547 
548  } else if (rsc == NULL) {
549  pe_err("Invalid constraint %s: no resource specified", id);
550  return NULL;
551 
552  } else if (node == NULL) {
553  CRM_CHECK(node_weight == 0, return NULL);
554  }
555 
556  new_con = calloc(1, sizeof(pe__location_t));
557  if (new_con != NULL) {
558  new_con->id = strdup(id);
559  new_con->rsc_lh = rsc;
560  new_con->node_list_rh = NULL;
561  new_con->role_filter = RSC_ROLE_UNKNOWN;
562 
563  if (pcmk__str_eq(discover_mode, "always",
566 
567  } else if (pcmk__str_eq(discover_mode, "never", pcmk__str_casei)) {
568  new_con->discover_mode = pe_discover_never;
569 
570  } else if (pcmk__str_eq(discover_mode, "exclusive", pcmk__str_casei)) {
572  rsc->exclusive_discover = TRUE;
573 
574  } else {
575  pe_err("Invalid " XML_LOCATION_ATTR_DISCOVERY " value %s "
576  "in location constraint", discover_mode);
577  }
578 
579  if (node != NULL) {
580  pe_node_t *copy = pe__copy_node(node);
581 
582  copy->weight = node_weight;
583  new_con->node_list_rh = g_list_prepend(NULL, copy);
584  }
585 
587  new_con);
588  rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
589  }
590 
591  return new_con;
592 }
593 
600 void
602 {
603  for (GList *iter = data_set->placement_constraints;
604  iter != NULL; iter = iter->next) {
605  pe__location_t *location = iter->data;
606 
607  location->rsc_lh->cmds->apply_location(location->rsc_lh, location);
608  }
609 }
610 
621 void
623 {
624  bool need_role = false;
625 
626  CRM_CHECK((rsc != NULL) && (location != NULL), return);
627 
628  // If a role was specified, ensure constraint is applicable
629  need_role = (location->role_filter > RSC_ROLE_UNKNOWN);
630  if (need_role && (location->role_filter != rsc->next_role)) {
631  pe_rsc_trace(rsc,
632  "Not applying %s to %s because role will be %s not %s",
633  location->id, rsc->id, role2text(rsc->next_role),
634  role2text(location->role_filter));
635  return;
636  }
637 
638  if (location->node_list_rh == NULL) {
639  pe_rsc_trace(rsc, "Not applying %s to %s because no nodes match",
640  location->id, rsc->id);
641  return;
642  }
643 
644  pe_rsc_trace(rsc, "Applying %s%s%s to %s", location->id,
645  (need_role? " for role " : ""),
646  (need_role? role2text(location->role_filter) : ""), rsc->id);
647 
648  for (GList *gIter = location->node_list_rh; gIter != NULL;
649  gIter = gIter->next) {
650 
651  pe_node_t *node = (pe_node_t *) gIter->data;
652  pe_node_t *weighted_node = NULL;
653 
654  weighted_node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes,
655  node->details->id);
656  if (weighted_node == NULL) {
657  pe_rsc_trace(rsc, "* = %d on %s",
658  node->weight, pe__node_name(node));
659  weighted_node = pe__copy_node(node);
660  g_hash_table_insert(rsc->allowed_nodes,
661  (gpointer) weighted_node->details->id,
662  weighted_node);
663  } else {
664  pe_rsc_trace(rsc, "* + %d on %s",
665  node->weight, pe__node_name(node));
666  weighted_node->weight = pcmk__add_scores(weighted_node->weight,
667  node->weight);
668  }
669 
670  if (weighted_node->rsc_discover_mode < location->discover_mode) {
671  if (location->discover_mode == pe_discover_exclusive) {
672  rsc->exclusive_discover = TRUE;
673  }
674  /* exclusive > never > always... always is default */
675  weighted_node->rsc_discover_mode = location->discover_mode;
676  }
677  }
678 }
GList * pcmk__copy_node_list(const GList *list, bool reset)
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:126
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
enum rsc_role_e role_filter
Definition: internal.h:194
A dumping ground.
GHashTable * attrs
Definition: pe_types.h:257
const char * pe_node_attribute_calculated(const pe_node_t *node, const char *name, const pe_resource_t *rsc)
Definition: common.c:518
#define INFINITY
Definition: crm.h:99
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:142
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:86
struct crm_time_s crm_time_t
Definition: iso8601.h:32
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition: utils.c:715
#define pcmk__config_warn(fmt...)
gboolean pe_test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, crm_time_t *next_change, pe_match_data_t *match_data)
Definition: rules.c:55
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
gboolean exclusive_discover
Definition: pe_types.h:377
int char2score(const char *score)
Get the integer value of a score string.
Definition: scores.c:36
#define pcmk__config_err(fmt...)
void pcmk__unpack_location(xmlNode *xml_obj, pe_working_set_t *data_set)
GHashTable * meta
Definition: pe_types.h:405
#define XML_LOCATION_ATTR_DISCOVERY
Definition: msg_xml.h:370
pe_re_match_data_t * re
Definition: common.h:176
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
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pe_working_set_t *data_set)
pe_resource_t * rsc_lh
Definition: internal.h:193
#define XML_LOC_ATTR_SOURCE
Definition: msg_xml.h:385
#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)
GList * resources
Definition: pe_types.h:181
GList * nodes
Definition: pe_types.h:180
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:819
const char * role2text(enum rsc_role_e role)
Definition: common.c:450
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)
gboolean local
Definition: cpg.c:47
int weight
Definition: pe_types.h:265
enum pe_discover_e discover_mode
Definition: internal.h:195
#define crm_debug(fmt, args...)
Definition: logging.h:382
#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
#define XML_LOC_ATTR_SOURCE_PATTERN
Definition: msg_xml.h:386
#define crm_trace(fmt, args...)
Definition: logging.h:383
struct pe_node_shared_s * details
Definition: pe_types.h:268
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:2593
pe_working_set_t * data_set
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:229
void free_xml(xmlNode *child)
Definition: xml.c:813
enum rsc_role_e text2role(const char *role)
Definition: common.c:479
xmlNode * input
Definition: pe_types.h:160
#define XML_CIB_TAG_NODE
Definition: msg_xml.h:218
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition: iso8601.c:359
G_GNUC_INTERNAL pe_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
const char * id
Definition: pe_types.h:231
#define XML_RULE_ATTR_BOOLEAN_OP
Definition: msg_xml.h:354
pe__location_t * pcmk__new_location(const char *id, pe_resource_t *rsc, int node_weight, const char *discover_mode, pe_node_t *node, pe_working_set_t *data_set)
pe_node_t * pe_find_node_id(const GList *node_list, const char *id)
Find a node by ID in a list of nodes.
Definition: status.c:448
Cluster status and scheduling.
pcmk__action_result_t result
Definition: pcmk_fence.c:35
regmatch_t * pmatch
Definition: common.h:172
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:1735
GHashTable * pe_rsc_params(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:436
GList * rsc_location
Definition: pe_types.h:390
pe_node_t * pe_find_node(const GList *node_list, const char *node_name)
Find a node by name in a list of nodes.
Definition: status.c:473
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
GList * placement_constraints
Definition: pe_types.h:182
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:116
void pcmk__apply_locations(pe_working_set_t *data_set)
#define crm_log_xml_trace(xml, text)
Definition: logging.h:391
#define XML_RULE_ATTR_SCORE_ATTRIBUTE
Definition: msg_xml.h:352
void(* apply_location)(pe_resource_t *rsc, pe__location_t *location)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:50
#define ID(x)
Definition: msg_xml.h:480
#define pe_err(fmt...)
Definition: internal.h:52
void pcmk__apply_location(pe_resource_t *rsc, pe__location_t *location)
#define XML_TAG_RULE
Definition: msg_xml.h:350
crm_time_t * now
Definition: pe_types.h:161
char * string
Definition: common.h:170
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
char * pe_expand_re_matches(const char *string, const pe_re_match_data_t *match_data)
Expand any regular expression submatches (%0-%9) in a string.
Definition: rules.c:560
#define XML_RULE_ATTR_ROLE
Definition: msg_xml.h:353
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150