pacemaker  2.1.7-0f7f88312f
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 <crm/pengine/rules.h>
18 #include <pacemaker-internal.h>
19 
20 #include "libpacemaker_private.h"
21 
22 static int
23 get_node_score(const char *rule, const char *score, bool raw,
24  pcmk_node_t *node, pcmk_resource_t *rsc)
25 {
26  int score_f = 0;
27 
28  if (score == NULL) {
29  pe_err("Rule %s: no score specified. Assuming 0.", rule);
30 
31  } else if (raw) {
32  score_f = char2score(score);
33 
34  } else {
35  const char *attr_score = NULL;
36 
37  attr_score = pe__node_attribute_calculated(node, score, rsc,
39  false);
40 
41  if (attr_score == NULL) {
42  crm_debug("Rule %s: %s did not have a value for %s",
43  rule, pe__node_name(node), score);
44  score_f = -INFINITY;
45 
46  } else {
47  crm_debug("Rule %s: %s had value %s for %s",
48  rule, pe__node_name(node), attr_score, score);
49  score_f = char2score(attr_score);
50  }
51  }
52  return score_f;
53 }
54 
55 static pe__location_t *
56 generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml,
57  const char *discovery, crm_time_t *next_change,
58  pe_re_match_data_t *re_match_data)
59 {
60  const char *rule_id = NULL;
61  const char *score = NULL;
62  const char *boolean = NULL;
63  const char *role = NULL;
64 
65  GList *iter = NULL;
66  GList *nodes = NULL;
67 
68  bool do_and = true;
69  bool accept = true;
70  bool raw_score = true;
71  bool score_allocated = false;
72 
73  pe__location_t *location_rule = NULL;
74 
75  rule_xml = expand_idref(rule_xml, rsc->cluster->input);
76  if (rule_xml == NULL) {
77  return NULL;
78  }
79 
80  rule_id = crm_element_value(rule_xml, XML_ATTR_ID);
81  boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP);
82  role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE);
83 
84  crm_trace("Processing rule: %s", rule_id);
85 
86  if ((role != NULL) && (text2role(role) == pcmk_role_unknown)) {
87  pe_err("Bad role specified for %s: %s", rule_id, role);
88  return NULL;
89  }
90 
91  score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE);
92  if (score == NULL) {
94  if (score != NULL) {
95  raw_score = false;
96  }
97  }
98  if (pcmk__str_eq(boolean, "or", pcmk__str_casei)) {
99  do_and = false;
100  }
101 
102  location_rule = pcmk__new_location(rule_id, rsc, 0, discovery, NULL);
103 
104  if (location_rule == NULL) {
105  return NULL;
106  }
107 
108  if ((re_match_data != NULL) && (re_match_data->nregs > 0)
109  && (re_match_data->pmatch[0].rm_so != -1) && !raw_score) {
110 
111  char *result = pe_expand_re_matches(score, re_match_data);
112 
113  if (result != NULL) {
114  score = result;
115  score_allocated = true;
116  }
117  }
118 
119  if (role != NULL) {
120  crm_trace("Setting role filter: %s", role);
121  location_rule->role_filter = text2role(role);
122  if (location_rule->role_filter == pcmk_role_unpromoted) {
123  /* Any promotable clone cannot be promoted without being in the
124  * unpromoted role first. Ergo, any constraint for the unpromoted
125  * role applies to every role.
126  */
127  location_rule->role_filter = pcmk_role_unknown;
128  }
129  }
130  if (do_and) {
131  nodes = pcmk__copy_node_list(rsc->cluster->nodes, true);
132  for (iter = nodes; iter != NULL; iter = iter->next) {
133  pcmk_node_t *node = iter->data;
134 
135  node->weight = get_node_score(rule_id, score, raw_score, node, rsc);
136  }
137  }
138 
139  for (iter = rsc->cluster->nodes; iter != NULL; iter = iter->next) {
140  int score_f = 0;
141  pcmk_node_t *node = iter->data;
142  pe_match_data_t match_data = {
143  .re = re_match_data,
144  .params = pe_rsc_params(rsc, node, rsc->cluster),
145  .meta = rsc->meta,
146  };
147 
148  accept = pe_test_rule(rule_xml, node->details->attrs, pcmk_role_unknown,
149  rsc->cluster->now, next_change, &match_data);
150 
151  crm_trace("Rule %s %s on %s", ID(rule_xml), accept? "passed" : "failed",
152  pe__node_name(node));
153 
154  score_f = get_node_score(rule_id, score, raw_score, node, rsc);
155 
156  if (accept) {
157  pcmk_node_t *local = pe_find_node_id(nodes, node->details->id);
158 
159  if ((local == NULL) && do_and) {
160  continue;
161 
162  } else if (local == NULL) {
163  local = pe__copy_node(node);
164  nodes = g_list_append(nodes, local);
165  }
166 
167  if (!do_and) {
168  local->weight = pcmk__add_scores(local->weight, score_f);
169  }
170  crm_trace("%s has score %s after %s", pe__node_name(node),
171  pcmk_readable_score(local->weight), rule_id);
172 
173  } else if (do_and && !accept) {
174  // Remove it
175  pcmk_node_t *delete = pe_find_node_id(nodes, node->details->id);
176 
177  if (delete != NULL) {
178  nodes = g_list_remove(nodes, delete);
179  crm_trace("%s did not match", pe__node_name(node));
180  }
181  free(delete);
182  }
183  }
184 
185  if (score_allocated) {
186  free((char *)score);
187  }
188 
189  location_rule->node_list_rh = nodes;
190  if (location_rule->node_list_rh == NULL) {
191  crm_trace("No matching nodes for rule %s", rule_id);
192  return NULL;
193  }
194 
195  crm_trace("%s: %d nodes matched",
196  rule_id, g_list_length(location_rule->node_list_rh));
197  return location_rule;
198 }
199 
200 static void
201 unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, const char *role,
202  const char *score, 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,
210 
211  if (rsc == NULL) {
212  pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
213  "does not exist", id, rsc_id);
214  return;
215  }
216 
217  if (score == NULL) {
218  score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
219  }
220 
221  if ((node != NULL) && (score != NULL)) {
222  int score_i = char2score(score);
223  pcmk_node_t *match = pe_find_node(rsc->cluster->nodes, node);
224 
225  if (!match) {
226  return;
227  }
228  location = pcmk__new_location(id, rsc, score_i, discovery, match);
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  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  "location rule evaluation");
259  }
260  crm_time_free(next_change);
261  return;
262  }
263 
264  if (role == NULL) {
265  role = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
266  }
267 
268  if ((location != NULL) && (role != NULL)) {
269  if (text2role(role) == pcmk_role_unknown) {
270  pe_err("Invalid constraint %s: Bad role %s", id, role);
271  return;
272 
273  } else {
274  enum rsc_role_e r = text2role(role);
275  switch (r) {
276  case pcmk_role_unknown:
277  case pcmk_role_started:
279  /* Applies to all */
280  location->role_filter = pcmk_role_unknown;
281  break;
282  default:
283  location->role_filter = r;
284  break;
285  }
286  }
287  }
288 }
289 
290 static void
291 unpack_simple_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
292 {
293  const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
294  const char *value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
295 
296  if (value) {
297  pcmk_resource_t *rsc;
298 
300  unpack_rsc_location(xml_obj, rsc, NULL, NULL, NULL);
301  }
302 
304  if (value) {
305  regex_t *r_patt = calloc(1, sizeof(regex_t));
306  bool invert = false;
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 (GList *iter = scheduler->resources; iter != NULL;
322  iter = iter->next) {
323 
324  pcmk_resource_t *r = iter->data;
325  int nregs = 0;
326  regmatch_t *pmatch = NULL;
327  int status;
328 
329  if (r_patt->re_nsub > 0) {
330  nregs = r_patt->re_nsub + 1;
331  } else {
332  nregs = 1;
333  }
334  pmatch = calloc(nregs, sizeof(regmatch_t));
335 
336  status = regexec(r_patt, r->id, nregs, pmatch, 0);
337 
338  if (!invert && (status == 0)) {
339  pe_re_match_data_t re_match_data = {
340  .string = r->id,
341  .nregs = nregs,
342  .pmatch = pmatch
343  };
344 
345  crm_debug("'%s' matched '%s' for %s", r->id, value, id);
346  unpack_rsc_location(xml_obj, r, NULL, NULL, &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, 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  pcmk_resource_t *rsc = NULL;
374  pcmk_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  xml_obj->name);
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, scheduler);
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(scheduler, 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 any template or tag reference into constraint resource_set
415  if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, XML_LOC_ATTR_SOURCE,
416  false, scheduler)) {
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,
443 {
444  xmlNode *xml_rsc = NULL;
445  pcmk_resource_t *resource = NULL;
446  const char *set_id;
447  const char *role;
448  const char *local_score;
449 
450  CRM_CHECK(set != NULL, return EINVAL);
451 
452  set_id = ID(set);
453  if (set_id == NULL) {
454  pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_SET " without "
455  XML_ATTR_ID " in constraint '%s'",
456  pcmk__s(ID(location), "(missing ID)"));
457  return pcmk_rc_unpack_error;
458  }
459 
460  role = crm_element_value(set, "role");
461  local_score = crm_element_value(set, XML_RULE_ATTR_SCORE);
462 
463  for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
464  xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
465 
467  ID(xml_rsc));
468  if (resource == NULL) {
469  pcmk__config_err("%s: No resource found for %s",
470  set_id, ID(xml_rsc));
471  return pcmk_rc_unpack_error;
472  }
473 
474  unpack_rsc_location(location, resource, role, local_score, 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, scheduler) != 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, scheduler->input);
503  if ((set == NULL) // Configuration error, message already logged
504  || (unpack_location_set(xml_obj, set, scheduler) != 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, scheduler);
520  }
521 }
522 
538 pcmk__new_location(const char *id, pcmk_resource_t *rsc,
539  int node_score, const char *discover_mode, pcmk_node_t *node)
540 {
541  pe__location_t *new_con = NULL;
542 
543  if (id == NULL) {
544  pe_err("Invalid constraint: no ID specified");
545  return NULL;
546 
547  } else if (rsc == NULL) {
548  pe_err("Invalid constraint %s: no resource specified", id);
549  return NULL;
550 
551  } else if (node == NULL) {
552  CRM_CHECK(node_score == 0, return NULL);
553  }
554 
555  new_con = calloc(1, sizeof(pe__location_t));
556  if (new_con != NULL) {
557  new_con->id = strdup(id);
558  new_con->rsc_lh = rsc;
559  new_con->node_list_rh = NULL;
560  new_con->role_filter = pcmk_role_unknown;
561 
562  if (pcmk__str_eq(discover_mode, "always",
564  new_con->discover_mode = pcmk_probe_always;
565 
566  } else if (pcmk__str_eq(discover_mode, "never", pcmk__str_casei)) {
567  new_con->discover_mode = pcmk_probe_never;
568 
569  } else if (pcmk__str_eq(discover_mode, "exclusive", pcmk__str_casei)) {
571  rsc->exclusive_discover = TRUE;
572 
573  } else {
574  pe_err("Invalid " XML_LOCATION_ATTR_DISCOVERY " value %s "
575  "in location constraint", discover_mode);
576  }
577 
578  if (node != NULL) {
579  pcmk_node_t *copy = pe__copy_node(node);
580 
581  copy->weight = node_score;
582  new_con->node_list_rh = g_list_prepend(NULL, copy);
583  }
584 
585  rsc->cluster->placement_constraints = g_list_prepend(
586  rsc->cluster->placement_constraints, new_con);
587  rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
588  }
589 
590  return new_con;
591 }
592 
599 void
601 {
602  for (GList *iter = scheduler->placement_constraints;
603  iter != NULL; iter = iter->next) {
604  pe__location_t *location = iter->data;
605 
606  location->rsc_lh->cmds->apply_location(location->rsc_lh, location);
607  }
608 }
609 
620 void
622 {
623  bool need_role = false;
624 
625  CRM_ASSERT((rsc != NULL) && (location != NULL));
626 
627  // If a role was specified, ensure constraint is applicable
628  need_role = (location->role_filter > pcmk_role_unknown);
629  if (need_role && (location->role_filter != rsc->next_role)) {
630  pe_rsc_trace(rsc,
631  "Not applying %s to %s because role will be %s not %s",
632  location->id, rsc->id, role2text(rsc->next_role),
633  role2text(location->role_filter));
634  return;
635  }
636 
637  if (location->node_list_rh == NULL) {
638  pe_rsc_trace(rsc, "Not applying %s to %s because no nodes match",
639  location->id, rsc->id);
640  return;
641  }
642 
643  pe_rsc_trace(rsc, "Applying %s%s%s to %s", location->id,
644  (need_role? " for role " : ""),
645  (need_role? role2text(location->role_filter) : ""), rsc->id);
646 
647  for (GList *iter = location->node_list_rh;
648  iter != NULL; iter = iter->next) {
649 
650  pcmk_node_t *node = iter->data;
651  pcmk_node_t *allowed_node = g_hash_table_lookup(rsc->allowed_nodes,
652  node->details->id);
653 
654  if (allowed_node == NULL) {
655  pe_rsc_trace(rsc, "* = %d on %s",
656  node->weight, pe__node_name(node));
657  allowed_node = pe__copy_node(node);
658  g_hash_table_insert(rsc->allowed_nodes,
659  (gpointer) allowed_node->details->id,
660  allowed_node);
661  } else {
662  pe_rsc_trace(rsc, "* + %d on %s",
663  node->weight, pe__node_name(node));
664  allowed_node->weight = pcmk__add_scores(allowed_node->weight,
665  node->weight);
666  }
667 
668  if (allowed_node->rsc_discover_mode < location->discover_mode) {
669  if (location->discover_mode == pcmk_probe_exclusive) {
670  rsc->exclusive_discover = TRUE;
671  }
672  /* exclusive > never > always... always is default */
673  allowed_node->rsc_discover_mode = location->discover_mode;
674  }
675  }
676 }
pcmk_assignment_methods_t * cmds
Resource assignment methods.
Definition: resources.h:417
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:238
enum rsc_role_e role_filter
Definition: internal.h:161
A dumping ground.
pcmk_node_t * pe__copy_node(const pcmk_node_t *this_node)
Definition: utils.c:89
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition: resources.h:412
GHashTable * attrs
Node attributes.
Definition: nodes.h:115
#define INFINITY
Definition: crm.h:98
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:142
void pcmk__unpack_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:86
G_GNUC_INTERNAL bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, const pcmk_scheduler_t *scheduler)
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#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
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:341
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2484
enum rsc_role_e next_role
Resource&#39;s scheduled next role.
Definition: resources.h:469
gboolean exclusive_discover
Whether exclusive probing is enabled.
Definition: resources.h:433
int char2score(const char *score)
Get the integer value of a score string.
Definition: scores.c:36
#define pcmk__config_err(fmt...)
GHashTable * meta
Resource&#39;s meta-attributes.
Definition: resources.h:471
#define XML_LOCATION_ATTR_DISCOVERY
Definition: msg_xml.h:360
pe_re_match_data_t * re
Definition: common.h:63
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
void pcmk__apply_locations(pcmk_scheduler_t *scheduler)
Always probe resource on node.
Definition: nodes.h:50
#define XML_LOC_ATTR_SOURCE
Definition: msg_xml.h:375
Implementation of pcmk_scheduler_t.
Definition: scheduler.h:172
pcmk_resource_t * rsc_lh
Definition: internal.h:160
#define XML_CONS_TAG_RSC_SET
Definition: msg_xml.h:357
GList * resources
Resources in cluster.
Definition: scheduler.h:196
GList * nodes
Nodes in cluster.
Definition: scheduler.h:195
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:789
const char * role2text(enum rsc_role_e role)
Definition: common.c:458
gboolean local
Definition: cpg.c:47
int weight
Node score for a given resource.
Definition: nodes.h:131
enum pe_discover_e discover_mode
Definition: internal.h:162
Implementation of pcmk_resource_t.
Definition: resources.h:399
#define crm_debug(fmt, args...)
Definition: logging.h:386
G_GNUC_INTERNAL pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
void(* apply_location)(pcmk_resource_t *rsc, pe__location_t *location)
#define XML_ATTR_ID
Definition: msg_xml.h:156
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:447
pcmk_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
#define XML_LOC_ATTR_SOURCE_PATTERN
Definition: msg_xml.h:376
const char * pe__node_attribute_calculated(const pcmk_node_t *node, const char *name, const pcmk_resource_t *rsc, enum pcmk__rsc_node node_type, bool force_host)
Definition: common.c:546
#define crm_trace(fmt, args...)
Definition: logging.h:387
pcmk_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
struct pe_node_shared_s * details
Basic node information.
Definition: nodes.h:134
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:2555
Unpromoted.
Definition: roles.h:31
void pcmk__apply_location(pcmk_resource_t *rsc, pe__location_t *location)
rsc_role_e
Definition: roles.h:27
Never probe resource on node.
Definition: nodes.h:51
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:234
G_GNUC_INTERNAL bool pcmk__valid_resource_or_tag(const pcmk_scheduler_t *scheduler, const char *id, pcmk_resource_t **rsc, pcmk_tag_t **tag)
void free_xml(xmlNode *child)
Definition: xml.c:783
Implementation of pcmk_node_t.
Definition: nodes.h:130
enum rsc_role_e text2role(const char *role)
Definition: common.c:487
xmlNode * input
CIB XML.
Definition: scheduler.h:175
#define XML_CIB_TAG_NODE
Definition: msg_xml.h:223
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition: iso8601.c:359
void pe__update_recheck_time(time_t recheck, pcmk_scheduler_t *scheduler, const char *reason)
Definition: utils.c:682
int rsc_discover_mode
Probe mode (enum pe_discover_e)
Definition: nodes.h:137
const char * id
Node ID at the cluster layer.
Definition: nodes.h:67
#define XML_RULE_ATTR_BOOLEAN_OP
Definition: msg_xml.h:344
pe__location_t * pcmk__new_location(const char *id, pcmk_resource_t *rsc, int node_score, const char *discover_mode, pcmk_node_t *node)
Cluster status and scheduling.
pcmk__action_result_t result
Definition: pcmk_fence.c:35
GList * pcmk__copy_node_list(const GList *list, bool reset)
pcmk_scheduler_t * scheduler
#define CRM_ASSERT(expr)
Definition: results.h:42
regmatch_t * pmatch
Definition: common.h:59
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:1696
Started.
Definition: roles.h:30
Configuration tag object.
Definition: tags.h:26
GList * rsc_location
Definition: resources.h:446
GList * placement_constraints
Location constraints.
Definition: scheduler.h:197
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:116
#define crm_log_xml_trace(xml, text)
Definition: logging.h:395
#define XML_RULE_ATTR_SCORE_ATTRIBUTE
Definition: msg_xml.h:342
Resource role is unknown.
Definition: roles.h:28
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:37
GHashTable * pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get a table of resource parameters.
Definition: complex.c:446
#define ID(x)
Definition: msg_xml.h:474
#define pe_err(fmt...)
Definition: internal.h:39
#define XML_TAG_RULE
Definition: msg_xml.h:340
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
crm_time_t * now
Current time for evaluation purposes.
Definition: scheduler.h:176
char * string
Definition: common.h:57
char * id
Resource ID in configuration.
Definition: resources.h:400
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition: resources.h:466
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2510
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:563
#define XML_RULE_ATTR_ROLE
Definition: msg_xml.h:343
Where resource is running.
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150