pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
pcmk_sched_location.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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>
17 #include <crm/pengine/status.h>
18 #include <crm/pengine/rules.h>
19 #include <pacemaker-internal.h>
20 
21 #include "libpacemaker_private.h"
22 
23 static int
24 get_node_score(const char *rule, const char *score, bool raw,
25  pcmk_node_t *node, pcmk_resource_t *rsc)
26 {
27  int score_f = 0;
28 
29  if (score == NULL) {
30  pcmk__config_warn("Rule %s: no score specified (assuming 0)", rule);
31 
32  } else if (raw) {
33  score_f = char2score(score);
34 
35  } else {
36  const char *target = NULL;
37  const char *attr_score = NULL;
38 
39  target = g_hash_table_lookup(rsc->meta,
41 
42  attr_score = pcmk__node_attr(node, score, target,
44  if (attr_score == NULL) {
45  crm_debug("Rule %s: %s did not have a value for %s",
46  rule, pcmk__node_name(node), score);
47  score_f = -PCMK_SCORE_INFINITY;
48 
49  } else {
50  crm_debug("Rule %s: %s had value %s for %s",
51  rule, pcmk__node_name(node), attr_score, score);
52  score_f = char2score(attr_score);
53  }
54  }
55  return score_f;
56 }
57 
67 static bool
68 parse_location_role(const char *role_spec, enum rsc_role_e *role)
69 {
70  if (role_spec == NULL) {
71  *role = pcmk_role_unknown;
72  return true;
73  }
74 
75  *role = pcmk_parse_role(role_spec);
76  switch (*role) {
77  case pcmk_role_unknown:
78  return false;
79 
80  case pcmk_role_started:
82  /* Any promotable clone instance cannot be promoted without being in
83  * the unpromoted role first. Therefore, any constraint for the
84  * started or unpromoted role applies to every role.
85  */
86  *role = pcmk_role_unknown;
87  break;
88 
89  default:
90  break;
91  }
92  return true;
93 }
94 
110 static bool
111 generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml,
112  const char *discovery, crm_time_t *next_change,
113  pcmk_rule_input_t *rule_input)
114 {
115  const char *rule_id = NULL;
116  const char *score = NULL;
117  const char *boolean = NULL;
118  const char *role_spec = NULL;
119 
120  GList *iter = NULL;
121 
122  bool raw_score = true;
123  bool score_allocated = false;
124 
125  pcmk__location_t *location_rule = NULL;
126  enum rsc_role_e role = pcmk_role_unknown;
127  enum pcmk__combine combine = pcmk__combine_unknown;
128 
129  rule_xml = expand_idref(rule_xml, rsc->cluster->input);
130  if (rule_xml == NULL) {
131  return false; // Error already logged
132  }
133 
134  rule_id = crm_element_value(rule_xml, PCMK_XA_ID);
135  if (rule_id == NULL) {
136  pcmk__config_err("Ignoring " PCMK_XE_RULE " without " PCMK_XA_ID
137  " in location constraint");
138  return false;
139  }
140 
141  boolean = crm_element_value(rule_xml, PCMK_XA_BOOLEAN_OP);
142  role_spec = crm_element_value(rule_xml, PCMK_XA_ROLE);
143 
144  if (parse_location_role(role_spec, &role)) {
145  crm_trace("Setting rule %s role filter to %s", rule_id, role_spec);
146  } else {
147  pcmk__config_err("Ignoring rule %s: Invalid " PCMK_XA_ROLE " '%s'",
148  rule_id, role_spec);
149  return false;
150  }
151 
152  crm_trace("Processing location constraint rule %s", rule_id);
153 
154  score = crm_element_value(rule_xml, PCMK_XA_SCORE);
155  if (score == NULL) {
156  score = crm_element_value(rule_xml, PCMK_XA_SCORE_ATTRIBUTE);
157  if (score != NULL) {
158  raw_score = false;
159  }
160  }
161 
162  combine = pcmk__parse_combine(boolean);
163  switch (combine) {
164  case pcmk__combine_and:
165  case pcmk__combine_or:
166  break;
167 
168  default:
169  /* @COMPAT When we can break behavioral backward compatibility,
170  * return false
171  */
172  pcmk__config_warn("Location constraint rule %s has invalid "
173  PCMK_XA_BOOLEAN_OP " value '%s', using default "
174  "'" PCMK_VALUE_AND "'",
175  rule_id, boolean);
176  break;
177  }
178 
179  location_rule = pcmk__new_location(rule_id, rsc, 0, discovery, NULL);
180  CRM_CHECK(location_rule != NULL, return NULL);
181 
182  location_rule->role_filter = role;
183 
184  if ((rule_input->rsc_id != NULL) && (rule_input->rsc_id_nmatches > 0)
185  && !raw_score) {
186 
187  char *result = pcmk__replace_submatches(score, rule_input->rsc_id,
188  rule_input->rsc_id_submatches,
189  rule_input->rsc_id_nmatches);
190 
191  if (result != NULL) {
192  score = result;
193  score_allocated = true;
194  }
195  }
196 
197  for (iter = rsc->cluster->nodes; iter != NULL; iter = iter->next) {
198  pcmk_node_t *node = iter->data;
199 
200  rule_input->node_attrs = node->details->attrs;
201  rule_input->rsc_params = pe_rsc_params(rsc, node, rsc->cluster);
202 
203  if (pcmk_evaluate_rule(rule_xml, rule_input,
204  next_change) == pcmk_rc_ok) {
206 
207  location_rule->nodes = g_list_prepend(location_rule->nodes, local);
208  local->weight = get_node_score(rule_id, score, raw_score, node,
209  rsc);
210  crm_trace("%s has score %s after %s", pcmk__node_name(node),
211  pcmk_readable_score(local->weight), rule_id);
212  }
213  }
214 
215  if (score_allocated) {
216  free((char *)score);
217  }
218 
219  if (location_rule->nodes == NULL) {
220  crm_trace("No matching nodes for location constraint rule %s", rule_id);
221  } else {
222  crm_trace("Location constraint rule %s matched %d nodes",
223  rule_id, g_list_length(location_rule->nodes));
224  }
225  return true;
226 }
227 
228 static void
229 unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc,
230  const char *role_spec, const char *score,
231  char *rsc_id_match, int rsc_id_nmatches,
232  regmatch_t *rsc_id_submatches)
233 {
234  const char *rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
235  const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
236  const char *node = crm_element_value(xml_obj, PCMK_XE_NODE);
237  const char *discovery = crm_element_value(xml_obj,
239 
240  if (rsc == NULL) {
241  pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
242  "does not exist", id, rsc_id);
243  return;
244  }
245 
246  if (score == NULL) {
247  score = crm_element_value(xml_obj, PCMK_XA_SCORE);
248  }
249 
250  if ((node != NULL) && (score != NULL)) {
251  int score_i = char2score(score);
252  pcmk_node_t *match = pcmk_find_node(rsc->cluster, node);
253  enum rsc_role_e role = pcmk_role_unknown;
254  pcmk__location_t *location = NULL;
255 
256  if (match == NULL) {
257  crm_info("Ignoring location constraint %s "
258  "because '%s' is not a known node",
259  pcmk__s(id, "without ID"), node);
260  return;
261  }
262 
263  if (role_spec == NULL) {
264  role_spec = crm_element_value(xml_obj, PCMK_XA_ROLE);
265  }
266  if (parse_location_role(role_spec, &role)) {
267  crm_trace("Setting location constraint %s role filter: %s",
268  id, role_spec);
269  } else {
270  /* @COMPAT The previous behavior of creating the constraint ignoring
271  * the role is retained for now, but we should ignore the entire
272  * constraint when we can break backward compatibility.
273  */
274  pcmk__config_err("Ignoring role in constraint %s: "
275  "Invalid value '%s'", id, role_spec);
276  }
277 
278  location = pcmk__new_location(id, rsc, score_i, discovery, match);
279  if (location == NULL) {
280  return; // Error already logged
281  }
282  location->role_filter = role;
283 
284  } else {
285  bool empty = true;
286  crm_time_t *next_change = crm_time_new_undefined();
287  pcmk_rule_input_t rule_input = {
288  .now = rsc->cluster->now,
289  .rsc_meta = rsc->meta,
290  .rsc_id = rsc_id_match,
291  .rsc_id_submatches = rsc_id_submatches,
292  .rsc_id_nmatches = rsc_id_nmatches,
293  };
294 
295  /* This loop is logically parallel to pcmk__evaluate_rules(), except
296  * instead of checking whether any rule is active, we set up location
297  * constraints for each active rule.
298  *
299  * @COMPAT When we can break backward compatibility, limit location
300  * constraints to a single rule, for consistency with other contexts.
301  * Since a rule may contain other rules, this does not prohibit any
302  * existing use cases.
303  */
304  for (xmlNode *rule_xml = pcmk__xe_first_child(xml_obj, PCMK_XE_RULE,
305  NULL, NULL);
306  rule_xml != NULL; rule_xml = pcmk__xe_next_same(rule_xml)) {
307 
308  if (generate_location_rule(rsc, rule_xml, discovery, next_change,
309  &rule_input)) {
310  if (empty) {
311  empty = false;
312  continue;
313  }
315  "Support for multiple " PCMK_XE_RULE
316  " elements in a location constraint is "
317  "deprecated and will be removed in a future "
318  "release (use a single new rule combining the "
319  "previous rules with " PCMK_XA_BOOLEAN_OP
320  " set to '" PCMK_VALUE_OR "' instead)");
321  }
322  }
323 
324  if (empty) {
325  pcmk__config_err("Ignoring constraint '%s' because it contains "
326  "no valid rules", id);
327  }
328 
329  /* If there is a point in the future when the evaluation of a rule will
330  * change, make sure the scheduler is re-run by that time.
331  */
332  if (crm_time_is_defined(next_change)) {
333  time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change);
334 
336  "location rule evaluation");
337  }
338  crm_time_free(next_change);
339  }
340 }
341 
342 static void
343 unpack_simple_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
344 {
345  const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
346  const char *value = crm_element_value(xml_obj, PCMK_XA_RSC);
347 
348  if (value) {
349  pcmk_resource_t *rsc;
350 
352  unpack_rsc_location(xml_obj, rsc, NULL, NULL, NULL, 0, NULL);
353  }
354 
355  value = crm_element_value(xml_obj, PCMK_XA_RSC_PATTERN);
356  if (value) {
357  regex_t regex;
358  bool invert = false;
359 
360  if (value[0] == '!') {
361  value++;
362  invert = true;
363  }
364 
365  if (regcomp(&regex, value, REG_EXTENDED) != 0) {
366  pcmk__config_err("Ignoring constraint '%s' because "
368  " has invalid value '%s'", id, value);
369  return;
370  }
371 
372  for (GList *iter = scheduler->resources; iter != NULL;
373  iter = iter->next) {
374 
375  pcmk_resource_t *r = iter->data;
376  int nregs = 0;
377  regmatch_t *pmatch = NULL;
378  int status;
379 
380  if (regex.re_nsub > 0) {
381  nregs = regex.re_nsub + 1;
382  } else {
383  nregs = 1;
384  }
385  pmatch = pcmk__assert_alloc(nregs, sizeof(regmatch_t));
386 
387  status = regexec(&regex, r->id, nregs, pmatch, 0);
388 
389  if (!invert && (status == 0)) {
390  crm_debug("'%s' matched '%s' for %s", r->id, value, id);
391  unpack_rsc_location(xml_obj, r, NULL, NULL, r->id, nregs,
392  pmatch);
393 
394  } else if (invert && (status != 0)) {
395  crm_debug("'%s' is an inverted match of '%s' for %s",
396  r->id, value, id);
397  unpack_rsc_location(xml_obj, r, NULL, NULL, NULL, 0, NULL);
398 
399  } else {
400  crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
401  }
402 
403  free(pmatch);
404  }
405 
406  regfree(&regex);
407  }
408 }
409 
410 // \return Standard Pacemaker return code
411 static int
412 unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
414 {
415  const char *id = NULL;
416  const char *rsc_id = NULL;
417  const char *state = NULL;
418  pcmk_resource_t *rsc = NULL;
419  pcmk_tag_t *tag = NULL;
420  xmlNode *rsc_set = NULL;
421 
422  *expanded_xml = NULL;
423 
424  CRM_CHECK(xml_obj != NULL, return EINVAL);
425 
426  id = pcmk__xe_id(xml_obj);
427  if (id == NULL) {
428  pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
429  xml_obj->name);
430  return pcmk_rc_unpack_error;
431  }
432 
433  // Check whether there are any resource sets with template or tag references
434  *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
435  if (*expanded_xml != NULL) {
436  crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION);
437  return pcmk_rc_ok;
438  }
439 
440  rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
441  if (rsc_id == NULL) {
442  return pcmk_rc_ok;
443  }
444 
445  if (!pcmk__valid_resource_or_tag(scheduler, rsc_id, &rsc, &tag)) {
446  pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
447  "valid resource or tag", id, rsc_id);
448  return pcmk_rc_unpack_error;
449 
450  } else if (rsc != NULL) {
451  // No template is referenced
452  return pcmk_rc_ok;
453  }
454 
455  state = crm_element_value(xml_obj, PCMK_XA_ROLE);
456 
457  *expanded_xml = pcmk__xml_copy(NULL, xml_obj);
458 
459  /* Convert any template or tag reference into constraint
460  * PCMK_XE_RESOURCE_SET
461  */
462  if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, PCMK_XA_RSC,
463  false, scheduler)) {
464  free_xml(*expanded_xml);
465  *expanded_xml = NULL;
466  return pcmk_rc_unpack_error;
467  }
468 
469  if (rsc_set != NULL) {
470  if (state != NULL) {
471  /* Move PCMK_XA_RSC_ROLE into converted PCMK_XE_RESOURCE_SET as
472  * PCMK_XA_ROLE attribute
473  */
474  crm_xml_add(rsc_set, PCMK_XA_ROLE, state);
475  pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_ROLE);
476  }
477  crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION);
478 
479  } else {
480  // No sets
481  free_xml(*expanded_xml);
482  *expanded_xml = NULL;
483  }
484 
485  return pcmk_rc_ok;
486 }
487 
488 // \return Standard Pacemaker return code
489 static int
490 unpack_location_set(xmlNode *location, xmlNode *set,
492 {
493  xmlNode *xml_rsc = NULL;
494  pcmk_resource_t *resource = NULL;
495  const char *set_id;
496  const char *role;
497  const char *local_score;
498 
499  CRM_CHECK(set != NULL, return EINVAL);
500 
501  set_id = pcmk__xe_id(set);
502  if (set_id == NULL) {
503  pcmk__config_err("Ignoring " PCMK_XE_RESOURCE_SET " without "
504  PCMK_XA_ID " in constraint '%s'",
505  pcmk__s(pcmk__xe_id(location), "(missing ID)"));
506  return pcmk_rc_unpack_error;
507  }
508 
509  role = crm_element_value(set, PCMK_XA_ROLE);
510  local_score = crm_element_value(set, PCMK_XA_SCORE);
511 
512  for (xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF, NULL, NULL);
513  xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
514 
516  pcmk__xe_id(xml_rsc));
517  if (resource == NULL) {
518  pcmk__config_err("%s: No resource found for %s",
519  set_id, pcmk__xe_id(xml_rsc));
520  return pcmk_rc_unpack_error;
521  }
522 
523  unpack_rsc_location(location, resource, role, local_score, NULL, 0,
524  NULL);
525  }
526 
527  return pcmk_rc_ok;
528 }
529 
530 void
532 {
533  xmlNode *set = NULL;
534  bool any_sets = false;
535 
536  xmlNode *orig_xml = NULL;
537  xmlNode *expanded_xml = NULL;
538 
539  if (unpack_location_tags(xml_obj, &expanded_xml, scheduler) != pcmk_rc_ok) {
540  return;
541  }
542 
543  if (expanded_xml) {
544  orig_xml = xml_obj;
545  xml_obj = expanded_xml;
546  }
547 
548  for (set = pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, NULL, NULL);
549  set != NULL; set = pcmk__xe_next_same(set)) {
550 
551  any_sets = true;
552  set = expand_idref(set, scheduler->input);
553  if ((set == NULL) // Configuration error, message already logged
554  || (unpack_location_set(xml_obj, set, scheduler) != pcmk_rc_ok)) {
555 
556  if (expanded_xml) {
557  free_xml(expanded_xml);
558  }
559  return;
560  }
561  }
562 
563  if (expanded_xml) {
564  free_xml(expanded_xml);
565  xml_obj = orig_xml;
566  }
567 
568  if (!any_sets) {
569  unpack_simple_location(xml_obj, scheduler);
570  }
571 }
572 
588 pcmk__new_location(const char *id, pcmk_resource_t *rsc,
589  int node_score, const char *discover_mode, pcmk_node_t *node)
590 {
591  pcmk__location_t *new_con = NULL;
592 
593  CRM_CHECK((node != NULL) || (node_score == 0), return NULL);
594 
595  if (id == NULL) {
596  pcmk__config_err("Invalid constraint: no ID specified");
597  return NULL;
598  }
599 
600  if (rsc == NULL) {
601  pcmk__config_err("Invalid constraint %s: no resource specified", id);
602  return NULL;
603  }
604 
605  new_con = pcmk__assert_alloc(1, sizeof(pcmk__location_t));
606  new_con->id = pcmk__str_copy(id);
607  new_con->rsc = rsc;
608  new_con->nodes = NULL;
609  new_con->role_filter = pcmk_role_unknown;
610 
611  if (pcmk__str_eq(discover_mode, PCMK_VALUE_ALWAYS,
613  new_con->discover_mode = pcmk_probe_always;
614 
615  } else if (pcmk__str_eq(discover_mode, PCMK_VALUE_NEVER,
616  pcmk__str_casei)) {
617  new_con->discover_mode = pcmk_probe_never;
618 
619  } else if (pcmk__str_eq(discover_mode, PCMK_VALUE_EXCLUSIVE,
620  pcmk__str_casei)) {
622  rsc->exclusive_discover = TRUE;
623 
624  } else {
625  pcmk__config_err("Invalid " PCMK_XA_RESOURCE_DISCOVERY " value %s "
626  "in location constraint", discover_mode);
627  }
628 
629  if (node != NULL) {
630  pcmk_node_t *copy = pe__copy_node(node);
631 
632  copy->weight = node_score;
633  new_con->nodes = g_list_prepend(NULL, copy);
634  }
635 
636  rsc->cluster->placement_constraints = g_list_prepend(
637  rsc->cluster->placement_constraints, new_con);
638  rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
639 
640  return new_con;
641 }
642 
649 void
651 {
652  for (GList *iter = scheduler->placement_constraints;
653  iter != NULL; iter = iter->next) {
654  pcmk__location_t *location = iter->data;
655 
656  location->rsc->cmds->apply_location(location->rsc, location);
657  }
658 }
659 
670 void
672 {
673  bool need_role = false;
674 
675  pcmk__assert((rsc != NULL) && (location != NULL));
676 
677  // If a role was specified, ensure constraint is applicable
678  need_role = (location->role_filter > pcmk_role_unknown);
679  if (need_role && (location->role_filter != rsc->next_role)) {
680  pcmk__rsc_trace(rsc,
681  "Not applying %s to %s because role will be %s not %s",
682  location->id, rsc->id, pcmk_role_text(rsc->next_role),
683  pcmk_role_text(location->role_filter));
684  return;
685  }
686 
687  if (location->nodes == NULL) {
688  pcmk__rsc_trace(rsc, "Not applying %s to %s because no nodes match",
689  location->id, rsc->id);
690  return;
691  }
692 
693  for (GList *iter = location->nodes; iter != NULL; iter = iter->next) {
694  pcmk_node_t *node = iter->data;
695  pcmk_node_t *allowed_node = g_hash_table_lookup(rsc->allowed_nodes,
696  node->details->id);
697 
698  pcmk__rsc_trace(rsc, "Applying %s%s%s to %s score on %s: %c %s",
699  location->id,
700  (need_role? " for role " : ""),
701  (need_role? pcmk_role_text(location->role_filter) : ""),
702  rsc->id, pcmk__node_name(node),
703  ((allowed_node == NULL)? '=' : '+'),
704  pcmk_readable_score(node->weight));
705 
706  if (allowed_node == NULL) {
707  allowed_node = pe__copy_node(node);
708  g_hash_table_insert(rsc->allowed_nodes,
709  (gpointer) allowed_node->details->id,
710  allowed_node);
711  } else {
712  allowed_node->weight = pcmk__add_scores(allowed_node->weight,
713  node->weight);
714  }
715 
716  if (allowed_node->rsc_discover_mode < location->discover_mode) {
717  if (location->discover_mode == pcmk_probe_exclusive) {
718  rsc->exclusive_discover = TRUE;
719  }
720  /* exclusive > never > always... always is default */
721  allowed_node->rsc_discover_mode = location->discover_mode;
722  }
723  }
724 }
pcmk_assignment_methods_t * cmds
Definition: resources.h:413
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:129
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
pcmk_node_t * pcmk_find_node(const pcmk_scheduler_t *scheduler, const char *node_name)
Find a node by name in scheduler data.
Definition: scheduler.c:103
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:974
A dumping ground.
pcmk_node_t * pe__copy_node(const pcmk_node_t *this_node)
Definition: utils.c:89
pcmk_scheduler_t * cluster
Definition: resources.h:408
GHashTable * attrs
Definition: nodes.h:143
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition: roles.c:23
const crm_time_t * now
Current time for rule evaluation purposes.
Definition: rules.h:59
enum pcmk__combine pcmk__parse_combine(const char *combine)
Definition: rules.c:903
Data used to evaluate a rule (any NULL items are ignored)
Definition: rules.h:57
GHashTable * rsc_params
Definition: rules.h:86
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:137
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
pcmk__location_t * pcmk__new_location(const char *id, pcmk_resource_t *rsc, int node_score, const char *discover_mode, pcmk_node_t *node)
#define pcmk__config_warn(fmt...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define PCMK_META_CONTAINER_ATTRIBUTE_TARGET
Definition: options.h:85
#define PCMK_VALUE_OR
Definition: options.h:187
#define PCMK_XA_RESOURCE_DISCOVERY
Definition: xml_names.h:384
#define PCMK_XE_RESOURCE_REF
Definition: xml_names.h:177
enum rsc_role_e next_role
Definition: resources.h:465
gboolean exclusive_discover
Definition: resources.h:432
#define pcmk__config_err(fmt...)
GHashTable * meta
Definition: resources.h:467
#define PCMK_VALUE_AND
Definition: options.h:133
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:313
#define PCMK_XA_RSC
Definition: xml_names.h:388
int rsc_id_nmatches
Number of entries in rsc_id_submatches.
Definition: rules.h:102
#define PCMK_XA_SCORE_ATTRIBUTE
Definition: xml_names.h:397
void pcmk__apply_locations(pcmk_scheduler_t *scheduler)
#define PCMK_VALUE_NEVER
Definition: options.h:177
enum rsc_role_e pcmk_parse_role(const char *role)
Parse a resource role from a string role specification.
Definition: roles.c:59
GList * resources
Definition: scheduler.h:231
pcmk__combine
gboolean local
Definition: cpg.c:50
int weight
Definition: nodes.h:163
char * pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches)
Definition: rules.c:686
#define PCMK_VALUE_ALWAYS
Definition: options.h:132
#define crm_debug(fmt, args...)
Definition: logging.h:402
#define PCMK_XE_RSC_LOCATION
Definition: xml_names.h:188
G_GNUC_INTERNAL pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:458
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:481
int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
Evaluate a single rule, including all its conditions.
Definition: rules.c:1386
int char2score(const char *score)
Get the integer value of a score string.
Definition: scores.c:115
#define crm_trace(fmt, args...)
Definition: logging.h:404
struct pe_node_shared_s * details
Definition: nodes.h:168
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:2170
Unpromoted.
Definition: roles.h:38
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
Definition: xml.c:702
rsc_role_e
Definition: roles.h:34
void(* apply_location)(pcmk_resource_t *rsc, pcmk__location_t *location)
#define PCMK_XA_ID
Definition: xml_names.h:301
pcmk_resource_t * rsc
#define PCMK_XA_SCORE
Definition: xml_names.h:396
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:958
void pcmk__apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:167
xmlNode * input
Definition: scheduler.h:196
#define pcmk__str_copy(str)
#define pcmk__warn_once(wo_flag, fmt...)
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition: iso8601.c:374
#define PCMK_XE_RULE
Definition: xml_names.h:191
void pe__update_recheck_time(time_t recheck, pcmk_scheduler_t *scheduler, const char *reason)
Definition: utils.c:694
int rsc_discover_mode
Definition: nodes.h:171
const char * id
Definition: nodes.h:73
#define pcmk__assert(expr)
const char * target
Definition: pcmk_fence.c:29
#define PCMK_XE_NODE
Definition: xml_names.h:136
Cluster status and scheduling.
pcmk__action_result_t result
Definition: pcmk_fence.c:35
#define PCMK_VALUE_EXCLUSIVE
Definition: options.h:150
pcmk_scheduler_t * scheduler
const regmatch_t * rsc_id_submatches
Resource pattern submatches (as set by regexec()) for rsc_id.
Definition: rules.h:99
#define PCMK_XE_RESOURCE_SET
Definition: xml_names.h:178
const char * pcmk__node_attr(const pcmk_node_t *node, const char *name, const char *target, enum pcmk__rsc_node node_type)
Definition: attrs.c:118
Started.
Definition: roles.h:37
Definition: tags.h:29
GList * rsc_location
Definition: resources.h:443
enum rsc_role_e role_filter
#define PCMK_XA_RSC_PATTERN
Definition: xml_names.h:389
GHashTable * node_attrs
Operation interval that rule applies to.
Definition: rules.h:77
#define PCMK_XA_BOOLEAN_OP
Definition: xml_names.h:240
GList * placement_constraints
Definition: scheduler.h:232
#define crm_log_xml_trace(xml, text)
Definition: logging.h:412
Resource role is unknown.
Definition: roles.h:35
enum pe_discover_e discover_mode
Location constraint object.
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:484
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:297
const char * rsc_id
Resource ID to compare against a location constraint&#39;s resource pattern.
Definition: rules.h:96
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition: xml.c:2130
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
#define PCMK_XA_ROLE
Definition: xml_names.h:387
crm_time_t * now
Definition: scheduler.h:198
#define crm_info(fmt, args...)
Definition: logging.h:399
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition: scores.h:24
GHashTable * allowed_nodes
Definition: resources.h:462
Where resource is running.
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150