pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
pcmk_sched_location.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 "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 now has weight %d",
170  pe__node_name(node), local->weight);
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)) {
314  pcmk__config_err("Ignoring constraint '%s' because "
316  " has invalid value '%s'", id, value);
317  regfree(r_patt);
318  free(r_patt);
319  return;
320  }
321 
322  for (rIter = data_set->resources; rIter; rIter = rIter->next) {
323  pe_resource_t *r = rIter->data;
324  int nregs = 0;
325  regmatch_t *pmatch = NULL;
326  int status;
327 
328  if(r_patt->re_nsub > 0) {
329  nregs = r_patt->re_nsub + 1;
330  } else {
331  nregs = 1;
332  }
333  pmatch = calloc(nregs, sizeof(regmatch_t));
334 
335  status = regexec(r_patt, r->id, nregs, pmatch, 0);
336 
337  if (!invert && (status == 0)) {
338  pe_re_match_data_t re_match_data = {
339  .string = r->id,
340  .nregs = nregs,
341  .pmatch = pmatch
342  };
343 
344  crm_debug("'%s' matched '%s' for %s", r->id, value, id);
345  unpack_rsc_location(xml_obj, r, NULL, NULL, data_set,
346  &re_match_data);
347 
348  } else if (invert && (status != 0)) {
349  crm_debug("'%s' is an inverted match of '%s' for %s",
350  r->id, value, id);
351  unpack_rsc_location(xml_obj, r, NULL, NULL, data_set, NULL);
352 
353  } else {
354  crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
355  }
356 
357  free(pmatch);
358  }
359 
360  regfree(r_patt);
361  free(r_patt);
362  }
363 }
364 
365 // \return Standard Pacemaker return code
366 static int
367 unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
369 {
370  const char *id = NULL;
371  const char *rsc_id = NULL;
372  const char *state = NULL;
373  pe_resource_t *rsc = NULL;
374  pe_tag_t *tag = NULL;
375  xmlNode *rsc_set = NULL;
376 
377  *expanded_xml = NULL;
378 
379  CRM_CHECK(xml_obj != NULL, return EINVAL);
380 
381  id = ID(xml_obj);
382  if (id == NULL) {
383  pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
384  crm_element_name(xml_obj));
385  return pcmk_rc_unpack_error;
386  }
387 
388  // Check whether there are any resource sets with template or tag references
389  *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, data_set);
390  if (*expanded_xml != NULL) {
391  crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
392  return pcmk_rc_ok;
393  }
394 
395  rsc_id = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
396  if (rsc_id == NULL) {
397  return pcmk_rc_ok;
398  }
399 
400  if (!pcmk__valid_resource_or_tag(data_set, rsc_id, &rsc, &tag)) {
401  pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
402  "valid resource or tag", id, rsc_id);
403  return pcmk_rc_unpack_error;
404 
405  } else if (rsc != NULL) {
406  // No template is referenced
407  return pcmk_rc_ok;
408  }
409 
410  state = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
411 
412  *expanded_xml = copy_xml(xml_obj);
413 
414  // Convert template/tag reference in "rsc" into resource_set under constraint
415  if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, XML_LOC_ATTR_SOURCE,
416  false, data_set)) {
417  free_xml(*expanded_xml);
418  *expanded_xml = NULL;
419  return pcmk_rc_unpack_error;
420  }
421 
422  if (rsc_set != NULL) {
423  if (state != NULL) {
424  // Move "rsc-role" into converted resource_set as "role" attribute
425  crm_xml_add(rsc_set, "role", state);
426  xml_remove_prop(*expanded_xml, XML_RULE_ATTR_ROLE);
427  }
428  crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
429 
430  } else {
431  // No sets
432  free_xml(*expanded_xml);
433  *expanded_xml = NULL;
434  }
435 
436  return pcmk_rc_ok;
437 }
438 
439 // \return Standard Pacemaker return code
440 static int
441 unpack_location_set(xmlNode *location, xmlNode *set, pe_working_set_t *data_set)
442 {
443  xmlNode *xml_rsc = NULL;
444  pe_resource_t *resource = NULL;
445  const char *set_id;
446  const char *role;
447  const char *local_score;
448 
449  CRM_CHECK(set != NULL, return EINVAL);
450 
451  set_id = ID(set);
452  if (set_id == NULL) {
453  pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_SET " without "
454  XML_ATTR_ID " in constraint '%s'",
455  pcmk__s(ID(location), "(missing ID)"));
456  return pcmk_rc_unpack_error;
457  }
458 
459  role = crm_element_value(set, "role");
460  local_score = crm_element_value(set, XML_RULE_ATTR_SCORE);
461 
462  for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
463  xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
464 
466  ID(xml_rsc));
467  if (resource == NULL) {
468  pcmk__config_err("%s: No resource found for %s",
469  set_id, ID(xml_rsc));
470  return pcmk_rc_unpack_error;
471  }
472 
473  unpack_rsc_location(location, resource, role, local_score, data_set,
474  NULL);
475  }
476 
477  return pcmk_rc_ok;
478 }
479 
480 void
482 {
483  xmlNode *set = NULL;
484  bool any_sets = false;
485 
486  xmlNode *orig_xml = NULL;
487  xmlNode *expanded_xml = NULL;
488 
489  if (unpack_location_tags(xml_obj, &expanded_xml, data_set) != pcmk_rc_ok) {
490  return;
491  }
492 
493  if (expanded_xml) {
494  orig_xml = xml_obj;
495  xml_obj = expanded_xml;
496  }
497 
498  for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
499  set = crm_next_same_xml(set)) {
500 
501  any_sets = true;
502  set = expand_idref(set, data_set->input);
503  if ((set == NULL) // Configuration error, message already logged
504  || (unpack_location_set(xml_obj, set, data_set) != pcmk_rc_ok)) {
505 
506  if (expanded_xml) {
507  free_xml(expanded_xml);
508  }
509  return;
510  }
511  }
512 
513  if (expanded_xml) {
514  free_xml(expanded_xml);
515  xml_obj = orig_xml;
516  }
517 
518  if (!any_sets) {
519  unpack_simple_location(xml_obj, data_set);
520  }
521 }
522 
539 pcmk__new_location(const char *id, pe_resource_t *rsc,
540  int node_weight, const char *discover_mode,
542 {
543  pe__location_t *new_con = NULL;
544 
545  if (id == NULL) {
546  pe_err("Invalid constraint: no ID specified");
547  return NULL;
548 
549  } else if (rsc == NULL) {
550  pe_err("Invalid constraint %s: no resource specified", id);
551  return NULL;
552 
553  } else if (node == NULL) {
554  CRM_CHECK(node_weight == 0, return NULL);
555  }
556 
557  new_con = calloc(1, sizeof(pe__location_t));
558  if (new_con != NULL) {
559  new_con->id = strdup(id);
560  new_con->rsc_lh = rsc;
561  new_con->node_list_rh = NULL;
562  new_con->role_filter = RSC_ROLE_UNKNOWN;
563 
564  if (pcmk__str_eq(discover_mode, "always",
567 
568  } else if (pcmk__str_eq(discover_mode, "never", pcmk__str_casei)) {
569  new_con->discover_mode = pe_discover_never;
570 
571  } else if (pcmk__str_eq(discover_mode, "exclusive", pcmk__str_casei)) {
573  rsc->exclusive_discover = TRUE;
574 
575  } else {
576  pe_err("Invalid " XML_LOCATION_ATTR_DISCOVERY " value %s "
577  "in location constraint", discover_mode);
578  }
579 
580  if (node != NULL) {
581  pe_node_t *copy = pe__copy_node(node);
582 
583  copy->weight = node_weight;
584  new_con->node_list_rh = g_list_prepend(NULL, copy);
585  }
586 
588  new_con);
589  rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
590  }
591 
592  return new_con;
593 }
594 
601 void
603 {
604  for (GList *iter = data_set->placement_constraints;
605  iter != NULL; iter = iter->next) {
606  pe__location_t *location = iter->data;
607 
608  location->rsc_lh->cmds->apply_location(location->rsc_lh, location);
609  }
610 }
611 
622 void
624 {
625  bool need_role = false;
626 
627  CRM_CHECK((rsc != NULL) && (location != NULL), return);
628 
629  // If a role was specified, ensure constraint is applicable
630  need_role = (location->role_filter > RSC_ROLE_UNKNOWN);
631  if (need_role && (location->role_filter != rsc->next_role)) {
632  pe_rsc_trace(rsc,
633  "Not applying %s to %s because role will be %s not %s",
634  location->id, rsc->id, role2text(rsc->next_role),
635  role2text(location->role_filter));
636  return;
637  }
638 
639  if (location->node_list_rh == NULL) {
640  pe_rsc_trace(rsc, "Not applying %s to %s because no nodes match",
641  location->id, rsc->id);
642  return;
643  }
644 
645  pe_rsc_trace(rsc, "Applying %s%s%s to %s", location->id,
646  (need_role? " for role " : ""),
647  (need_role? role2text(location->role_filter) : ""), rsc->id);
648 
649  for (GList *gIter = location->node_list_rh; gIter != NULL;
650  gIter = gIter->next) {
651 
652  pe_node_t *node = (pe_node_t *) gIter->data;
653  pe_node_t *weighted_node = NULL;
654 
655  weighted_node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes,
656  node->details->id);
657  if (weighted_node == NULL) {
658  pe_rsc_trace(rsc, "* = %d on %s",
659  node->weight, pe__node_name(node));
660  weighted_node = pe__copy_node(node);
661  g_hash_table_insert(rsc->allowed_nodes,
662  (gpointer) weighted_node->details->id,
663  weighted_node);
664  } else {
665  pe_rsc_trace(rsc, "* + %d on %s",
666  node->weight, pe__node_name(node));
667  weighted_node->weight = pcmk__add_scores(weighted_node->weight,
668  node->weight);
669  }
670 
671  if (weighted_node->rsc_discover_mode < location->discover_mode) {
672  if (location->discover_mode == pe_discover_exclusive) {
673  rsc->exclusive_discover = TRUE;
674  }
675  /* exclusive > never > always... always is default */
676  weighted_node->rsc_discover_mode = location->discover_mode;
677  }
678  }
679 }
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:116
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
pe_node_t * pe_find_node(GList *node_list, const char *uname)
Definition: status.c:443
enum rsc_role_e role_filter
Definition: internal.h:189
A dumping ground.
GHashTable * attrs
Definition: pe_types.h:241
const char * pe_node_attribute_calculated(const pe_node_t *node, const char *name, const pe_resource_t *rsc)
Definition: common.c:522
#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:132
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:703
#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:341
#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
gboolean exclusive_discover
Definition: pe_types.h:359
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:380
#define XML_LOCATION_ATTR_DISCOVERY
Definition: msg_xml.h:358
pe_re_match_data_t * re
Definition: common.h:177
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
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
pe_resource_t * rsc_lh
Definition: internal.h:188
#define XML_LOC_ATTR_SOURCE
Definition: msg_xml.h:373
#define XML_CONS_TAG_RSC_SET
Definition: msg_xml.h:355
GList * resources
Definition: pe_types.h:165
GList * nodes
Definition: pe_types.h:164
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
const char * role2text(enum rsc_role_e role)
Definition: common.c:454
gboolean local
Definition: cpg.c:47
int weight
Definition: pe_types.h:249
enum pe_discover_e discover_mode
Definition: internal.h:190
#define crm_debug(fmt, args...)
Definition: logging.h:364
#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
#define XML_LOC_ATTR_SOURCE_PATTERN
Definition: msg_xml.h:374
#define crm_trace(fmt, args...)
Definition: logging.h:365
struct pe_node_shared_s * details
Definition: pe_types.h:252
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:3002
pe_working_set_t * data_set
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:216
char * pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
Definition: rules.c:557
void free_xml(xmlNode *child)
Definition: xml.c:885
enum rsc_role_e text2role(const char *role)
Definition: common.c:483
xmlNode * input
Definition: pe_types.h:144
#define XML_CIB_TAG_NODE
Definition: msg_xml.h:205
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition: iso8601.c:352
G_GNUC_INTERNAL pe_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
const char * id
Definition: pe_types.h:215
#define XML_RULE_ATTR_BOOLEAN_OP
Definition: msg_xml.h:339
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition: status.c:427
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)
Cluster status and scheduling.
pcmk__action_result_t result
Definition: pcmk_fence.c:35
regmatch_t * pmatch
Definition: common.h:173
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:2145
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:429
GList * rsc_location
Definition: pe_types.h:365
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
GList * placement_constraints
Definition: pe_types.h:166
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:113
void pcmk__apply_locations(pe_working_set_t *data_set)
#define crm_log_xml_trace(xml, text)
Definition: logging.h:373
#define XML_RULE_ATTR_SCORE_ATTRIBUTE
Definition: msg_xml.h:337
void(* apply_location)(pe_resource_t *rsc, pe__location_t *location)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define ID(x)
Definition: msg_xml.h:468
#define pe_err(fmt...)
Definition: internal.h:49
void pcmk__apply_location(pe_resource_t *rsc, pe__location_t *location)
#define XML_TAG_RULE
Definition: msg_xml.h:335
crm_time_t * now
Definition: pe_types.h:145
char * string
Definition: common.h:171
G_GNUC_INTERNAL bool pcmk__valid_resource_or_tag(pe_working_set_t *data_set, const char *id, pe_resource_t **rsc, pe_tag_t **tag)
G_GNUC_INTERNAL 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
#define XML_RULE_ATTR_ROLE
Definition: msg_xml.h:338
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140