pacemaker  3.0.0-d8340737c4
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 
32 static bool
33 parse_location_role(const char *role_spec, enum rsc_role_e *role)
34 {
35  if (role_spec == NULL) {
36  *role = pcmk_role_unknown;
37  return true;
38  }
39 
40  *role = pcmk_parse_role(role_spec);
41  switch (*role) {
42  case pcmk_role_unknown:
43  return false;
44 
45  case pcmk_role_started:
47  /* Any promotable clone instance cannot be promoted without being in
48  * the unpromoted role first. Therefore, any constraint for the
49  * started or unpromoted role applies to every role.
50  */
51  *role = pcmk_role_unknown;
52  break;
53 
54  default:
55  break;
56  }
57  return true;
58 }
59 
73 static const char *
74 score_attribute_name(const xmlNode *rule_xml, char **allocated,
75  const pcmk_rule_input_t *rule_input)
76 {
77  const char *name = NULL;
78 
80  if (name == NULL) {
81  return NULL;
82  }
83 
84  /* A score attribute name may use submatches extracted from a
85  * resource ID regular expression. For example, if score-attribute is
86  * "loc-\1", rsc-pattern is "ip-(.*)", and the resource ID is "ip-db", then
87  * the score attribute name is "loc-db".
88  */
89  if ((rule_input->rsc_id != NULL) && (rule_input->rsc_id_nmatches > 0)) {
90  *allocated = pcmk__replace_submatches(name, rule_input->rsc_id,
91  rule_input->rsc_id_submatches,
92  rule_input->rsc_id_nmatches);
93  if (*allocated != NULL) {
94  name = *allocated;
95  }
96  }
97  return name;
98 }
99 
109 static int
110 score_from_rule(const xmlNode *rule_xml, int *score)
111 {
112  int rc = pcmk_rc_ok;
113  const char *score_s = crm_element_value(rule_xml, PCMK_XA_SCORE);
114 
115  if (score_s == NULL) { // Not possible with schema validation enabled
116  pcmk__config_err("Ignoring location constraint rule %s because "
117  "neither " PCMK_XA_SCORE " nor "
118  PCMK_XA_SCORE_ATTRIBUTE " was specified",
119  pcmk__xe_id(rule_xml));
120  return pcmk_rc_unpack_error;
121  }
122 
123  rc = pcmk_parse_score(score_s, score, 0);
124  if (rc != pcmk_rc_ok) { // Not possible with schema validation enabled
125  pcmk__config_err("Ignoring location constraint rule %s because "
126  "'%s' is not a valid " PCMK_XA_SCORE ": %s",
127  pcmk__xe_id(rule_xml), score_s, pcmk_rc_str(rc));
128  return pcmk_rc_unpack_error;
129  }
130 
131  return pcmk_rc_ok;
132 }
133 
148 static int
149 score_from_attr(const char *constraint_id, const char *attr_name,
150  const pcmk_node_t *node, const pcmk_resource_t *rsc, int *score)
151 {
152  int rc = pcmk_rc_ok;
153  const char *target = NULL;
154  const char *score_s = NULL;
155 
156  target = g_hash_table_lookup(rsc->priv->meta,
158  score_s = pcmk__node_attr(node, attr_name, target, pcmk__rsc_node_current);
159  if (pcmk__str_empty(score_s)) {
160  crm_info("Ignoring location %s for %s on %s "
161  "because it has no node attribute %s",
162  constraint_id, rsc->id, pcmk__node_name(node), attr_name);
163  return ENXIO;
164  }
165 
166  rc = pcmk_parse_score(score_s, score, 0);
167  if (rc != pcmk_rc_ok) {
168  crm_warn("Ignoring location %s for node %s because node "
169  "attribute %s value '%s' is not a valid score: %s",
170  constraint_id, pcmk__node_name(node), attr_name,
171  score_s, pcmk_rc_str(rc));
172  return rc;
173  }
174  return pcmk_rc_ok;
175 }
176 
193 static bool
194 generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml,
195  const char *discovery, crm_time_t *next_change,
196  pcmk_rule_input_t *rule_input, const char *constraint_id)
197 {
198  const char *rule_id = NULL;
199  const char *score_attr = NULL;
200  const char *boolean = NULL;
201  const char *role_spec = NULL;
202 
203  GList *iter = NULL;
204  int score = 0;
205  char *local_score_attr = NULL;
206  pcmk__location_t *location_rule = NULL;
207  enum rsc_role_e role = pcmk_role_unknown;
208  enum pcmk__combine combine = pcmk__combine_unknown;
209 
210  rule_xml = pcmk__xe_resolve_idref(rule_xml, rsc->priv->scheduler->input);
211  if (rule_xml == NULL) {
212  return false; // Error already logged
213  }
214 
215  rule_id = crm_element_value(rule_xml, PCMK_XA_ID);
216  if (rule_id == NULL) {
217  pcmk__config_err("Ignoring location constraint '%s' because its rule "
218  "has no " PCMK_XA_ID,
219  constraint_id);
220  return false;
221  }
222 
223  boolean = crm_element_value(rule_xml, PCMK_XA_BOOLEAN_OP);
224  role_spec = crm_element_value(rule_xml, PCMK_XA_ROLE);
225 
226  if (parse_location_role(role_spec, &role)) {
227  crm_trace("Setting rule %s role filter to %s", rule_id, role_spec);
228  } else {
229  pcmk__config_err("Ignoring location constraint '%s' because rule '%s' "
230  "has invalid " PCMK_XA_ROLE " '%s'",
231  constraint_id, rule_id, role_spec);
232  return false;
233  }
234 
235  combine = pcmk__parse_combine(boolean);
236  switch (combine) {
237  case pcmk__combine_and:
238  case pcmk__combine_or:
239  break;
240 
241  default: // Not possible with schema validation enabled
242  pcmk__config_err("Ignoring location constraint '%s' because rule "
243  "'%s' has invalid " PCMK_XA_BOOLEAN_OP " '%s'",
244  constraint_id, rule_id, boolean);
245  return false;
246  }
247 
248  /* Users may configure the rule with either a score or the name of a
249  * node attribute whose value should be used as the constraint score for
250  * that node.
251  */
252  score_attr = score_attribute_name(rule_xml, &local_score_attr, rule_input);
253  if ((score_attr == NULL)
254  && (score_from_rule(rule_xml, &score) != pcmk_rc_ok)) {
255  return false;
256  }
257 
258  location_rule = pcmk__new_location(rule_id, rsc, 0, discovery, NULL);
259  CRM_CHECK(location_rule != NULL, return NULL);
260 
261  location_rule->role_filter = role;
262 
263  for (iter = rsc->priv->scheduler->nodes;
264  iter != NULL; iter = iter->next) {
265 
266  pcmk_node_t *node = iter->data;
267  pcmk_node_t *local = NULL;
268 
269  rule_input->node_attrs = node->priv->attrs;
270  rule_input->rsc_params = pe_rsc_params(rsc, node,
271  rsc->priv->scheduler);
272 
273  if (pcmk_evaluate_rule(rule_xml, rule_input,
274  next_change) != pcmk_rc_ok) {
275  continue;
276  }
277 
278  if ((score_attr != NULL)
279  && (score_from_attr(constraint_id, score_attr, node, rsc,
280  &score) != pcmk_rc_ok)) {
281  continue; // Message already logged
282  }
283 
284  local = pe__copy_node(node);
285  location_rule->nodes = g_list_prepend(location_rule->nodes, local);
286  local->assign->score = score;
287  pcmk__rsc_trace(rsc,
288  "Location %s score for %s on %s is %s via rule %s",
289  constraint_id, rsc->id, pcmk__node_name(node),
290  pcmk_readable_score(score), rule_id);
291  }
292 
293  free(local_score_attr);
294 
295  if (location_rule->nodes == NULL) {
296  crm_trace("No matching nodes for location constraint rule %s", rule_id);
297  } else {
298  crm_trace("Location constraint rule %s matched %d nodes",
299  rule_id, g_list_length(location_rule->nodes));
300  }
301  return true;
302 }
303 
304 static void
305 unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc,
306  const char *role_spec, const char *score,
307  char *rsc_id_match, int rsc_id_nmatches,
308  regmatch_t *rsc_id_submatches)
309 {
310  const char *rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
311  const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
312  const char *node = crm_element_value(xml_obj, PCMK_XA_NODE);
313  const char *discovery = crm_element_value(xml_obj,
315 
316  if (rsc == NULL) {
317  pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
318  "does not exist", id, rsc_id);
319  return;
320  }
321 
322  if (score == NULL) {
323  score = crm_element_value(xml_obj, PCMK_XA_SCORE);
324  }
325 
326  if ((node != NULL) && (score != NULL)) {
327  int score_i = 0;
328  int rc = pcmk_rc_ok;
329  pcmk_node_t *match = pcmk_find_node(rsc->priv->scheduler, node);
330  enum rsc_role_e role = pcmk_role_unknown;
331  pcmk__location_t *location = NULL;
332 
333  if (match == NULL) {
334  crm_info("Ignoring location constraint %s "
335  "because '%s' is not a known node",
336  pcmk__s(id, "without ID"), node);
337  return;
338  }
339 
340  rc = pcmk_parse_score(score, &score_i, 0);
341  if (rc != pcmk_rc_ok) { // Not possible with schema validation enabled
342  pcmk__config_err("Ignoring location constraint %s "
343  "because '%s' is not a valid score", id, score);
344  return;
345  }
346 
347  if (role_spec == NULL) {
348  role_spec = crm_element_value(xml_obj, PCMK_XA_ROLE);
349  }
350  if (parse_location_role(role_spec, &role)) {
351  crm_trace("Setting location constraint %s role filter: %s",
352  id, role_spec);
353  } else { // Not possible with schema validation enabled
354  pcmk__config_err("Ignoring location constraint %s "
355  "because '%s' is not a valid " PCMK_XA_ROLE,
356  id, role_spec);
357  return;
358  }
359 
360  location = pcmk__new_location(id, rsc, score_i, discovery, match);
361  if (location == NULL) {
362  return; // Error already logged
363  }
364  location->role_filter = role;
365 
366  } else {
367  crm_time_t *next_change = crm_time_new_undefined();
368  xmlNode *rule_xml = pcmk__xe_first_child(xml_obj, PCMK_XE_RULE, NULL,
369  NULL);
370  pcmk_rule_input_t rule_input = {
371  .now = rsc->priv->scheduler->priv->now,
372  .rsc_meta = rsc->priv->meta,
373  .rsc_id = rsc_id_match,
374  .rsc_id_submatches = rsc_id_submatches,
375  .rsc_id_nmatches = rsc_id_nmatches,
376  };
377 
378  generate_location_rule(rsc, rule_xml, discovery, next_change,
379  &rule_input, id);
380 
381  /* If there is a point in the future when the evaluation of a rule will
382  * change, make sure the scheduler is re-run by that time.
383  */
384  if (crm_time_is_defined(next_change)) {
385  time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change);
386 
388  "location rule evaluation");
389  }
390  crm_time_free(next_change);
391  }
392 }
393 
394 static void
395 unpack_simple_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
396 {
397  const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
398  const char *value = crm_element_value(xml_obj, PCMK_XA_RSC);
399 
400  if (value) {
401  pcmk_resource_t *rsc;
402 
404  unpack_rsc_location(xml_obj, rsc, NULL, NULL, NULL, 0, NULL);
405  }
406 
407  value = crm_element_value(xml_obj, PCMK_XA_RSC_PATTERN);
408  if (value) {
409  regex_t regex;
410  bool invert = false;
411 
412  if (value[0] == '!') {
413  value++;
414  invert = true;
415  }
416 
417  if (regcomp(&regex, value, REG_EXTENDED) != 0) {
418  pcmk__config_err("Ignoring constraint '%s' because "
420  " has invalid value '%s'", id, value);
421  return;
422  }
423 
424  for (GList *iter = scheduler->priv->resources;
425  iter != NULL; iter = iter->next) {
426 
427  pcmk_resource_t *r = iter->data;
428  int nregs = 0;
429  regmatch_t *pmatch = NULL;
430  int status;
431 
432  if (regex.re_nsub > 0) {
433  nregs = regex.re_nsub + 1;
434  } else {
435  nregs = 1;
436  }
437  pmatch = pcmk__assert_alloc(nregs, sizeof(regmatch_t));
438 
439  status = regexec(&regex, r->id, nregs, pmatch, 0);
440 
441  if (!invert && (status == 0)) {
442  crm_debug("'%s' matched '%s' for %s", r->id, value, id);
443  unpack_rsc_location(xml_obj, r, NULL, NULL, r->id, nregs,
444  pmatch);
445 
446  } else if (invert && (status != 0)) {
447  crm_debug("'%s' is an inverted match of '%s' for %s",
448  r->id, value, id);
449  unpack_rsc_location(xml_obj, r, NULL, NULL, NULL, 0, NULL);
450 
451  } else {
452  crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
453  }
454 
455  free(pmatch);
456  }
457 
458  regfree(&regex);
459  }
460 }
461 
462 // \return Standard Pacemaker return code
463 static int
464 unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
466 {
467  const char *id = NULL;
468  const char *rsc_id = NULL;
469  const char *state = NULL;
470  pcmk_resource_t *rsc = NULL;
471  pcmk__idref_t *tag = NULL;
472  xmlNode *rsc_set = NULL;
473 
474  *expanded_xml = NULL;
475 
476  CRM_CHECK(xml_obj != NULL, return EINVAL);
477 
478  id = pcmk__xe_id(xml_obj);
479  if (id == NULL) {
480  pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
481  xml_obj->name);
482  return pcmk_rc_unpack_error;
483  }
484 
485  // Check whether there are any resource sets with template or tag references
486  *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
487  if (*expanded_xml != NULL) {
488  crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION);
489  return pcmk_rc_ok;
490  }
491 
492  rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
493  if (rsc_id == NULL) {
494  return pcmk_rc_ok;
495  }
496 
497  if (!pcmk__valid_resource_or_tag(scheduler, rsc_id, &rsc, &tag)) {
498  pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
499  "valid resource or tag", id, rsc_id);
500  return pcmk_rc_unpack_error;
501 
502  } else if (rsc != NULL) {
503  // No template is referenced
504  return pcmk_rc_ok;
505  }
506 
507  state = crm_element_value(xml_obj, PCMK_XA_ROLE);
508 
509  *expanded_xml = pcmk__xml_copy(NULL, xml_obj);
510 
511  /* Convert any template or tag reference into constraint
512  * PCMK_XE_RESOURCE_SET
513  */
514  if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, PCMK_XA_RSC,
515  false, scheduler)) {
516  pcmk__xml_free(*expanded_xml);
517  *expanded_xml = NULL;
518  return pcmk_rc_unpack_error;
519  }
520 
521  if (rsc_set != NULL) {
522  if (state != NULL) {
523  /* Move PCMK_XA_RSC_ROLE into converted PCMK_XE_RESOURCE_SET as
524  * PCMK_XA_ROLE attribute
525  */
526  crm_xml_add(rsc_set, PCMK_XA_ROLE, state);
527  pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_ROLE);
528  }
529  crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION);
530 
531  } else {
532  // No sets
533  pcmk__xml_free(*expanded_xml);
534  *expanded_xml = NULL;
535  }
536 
537  return pcmk_rc_ok;
538 }
539 
540 // \return Standard Pacemaker return code
541 static int
542 unpack_location_set(xmlNode *location, xmlNode *set,
544 {
545  xmlNode *xml_rsc = NULL;
546  pcmk_resource_t *resource = NULL;
547  const char *set_id;
548  const char *role;
549  const char *local_score;
550 
551  CRM_CHECK(set != NULL, return EINVAL);
552 
553  set_id = pcmk__xe_id(set);
554  if (set_id == NULL) {
555  pcmk__config_err("Ignoring " PCMK_XE_RESOURCE_SET " without "
556  PCMK_XA_ID " in constraint '%s'",
557  pcmk__s(pcmk__xe_id(location), "(missing ID)"));
558  return pcmk_rc_unpack_error;
559  }
560 
561  role = crm_element_value(set, PCMK_XA_ROLE);
562  local_score = crm_element_value(set, PCMK_XA_SCORE);
563 
564  for (xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF, NULL, NULL);
565  xml_rsc != NULL;
566  xml_rsc = pcmk__xe_next(xml_rsc, PCMK_XE_RESOURCE_REF)) {
567 
569  pcmk__xe_id(xml_rsc));
570  if (resource == NULL) {
571  pcmk__config_err("%s: No resource found for %s",
572  set_id, pcmk__xe_id(xml_rsc));
573  return pcmk_rc_unpack_error;
574  }
575 
576  unpack_rsc_location(location, resource, role, local_score, NULL, 0,
577  NULL);
578  }
579 
580  return pcmk_rc_ok;
581 }
582 
583 void
585 {
586  xmlNode *set = NULL;
587  bool any_sets = false;
588 
589  xmlNode *orig_xml = NULL;
590  xmlNode *expanded_xml = NULL;
591 
592  if (unpack_location_tags(xml_obj, &expanded_xml, scheduler) != pcmk_rc_ok) {
593  return;
594  }
595 
596  if (expanded_xml) {
597  orig_xml = xml_obj;
598  xml_obj = expanded_xml;
599  }
600 
601  for (set = pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, NULL, NULL);
602  set != NULL; set = pcmk__xe_next(set, PCMK_XE_RESOURCE_SET)) {
603 
604  any_sets = true;
606  if ((set == NULL) // Configuration error, message already logged
607  || (unpack_location_set(xml_obj, set, scheduler) != pcmk_rc_ok)) {
608 
609  if (expanded_xml) {
610  pcmk__xml_free(expanded_xml);
611  }
612  return;
613  }
614  }
615 
616  if (expanded_xml) {
617  pcmk__xml_free(expanded_xml);
618  xml_obj = orig_xml;
619  }
620 
621  if (!any_sets) {
622  unpack_simple_location(xml_obj, scheduler);
623  }
624 }
625 
641 pcmk__new_location(const char *id, pcmk_resource_t *rsc,
642  int node_score, const char *probe_mode, pcmk_node_t *node)
643 {
644  pcmk__location_t *new_con = NULL;
645 
646  CRM_CHECK((node != NULL) || (node_score == 0), return NULL);
647 
648  if (id == NULL) {
649  pcmk__config_err("Invalid constraint: no ID specified");
650  return NULL;
651  }
652 
653  if (rsc == NULL) {
654  pcmk__config_err("Invalid constraint %s: no resource specified", id);
655  return NULL;
656  }
657 
658  new_con = pcmk__assert_alloc(1, sizeof(pcmk__location_t));
659  new_con->id = pcmk__str_copy(id);
660  new_con->rsc = rsc;
661  new_con->nodes = NULL;
662  new_con->role_filter = pcmk_role_unknown;
663 
664  if (pcmk__str_eq(probe_mode, PCMK_VALUE_ALWAYS,
666  new_con->probe_mode = pcmk__probe_always;
667 
668  } else if (pcmk__str_eq(probe_mode, PCMK_VALUE_NEVER, pcmk__str_casei)) {
669  new_con->probe_mode = pcmk__probe_never;
670 
671  } else if (pcmk__str_eq(probe_mode, PCMK_VALUE_EXCLUSIVE,
672  pcmk__str_casei)) {
675 
676  } else {
677  pcmk__config_err("Invalid " PCMK_XA_RESOURCE_DISCOVERY " value %s "
678  "in location constraint", probe_mode);
679  }
680 
681  if (node != NULL) {
682  pcmk_node_t *copy = pe__copy_node(node);
683 
684  copy->assign->score = node_score;
685  new_con->nodes = g_list_prepend(NULL, copy);
686  }
687 
689  g_list_prepend(rsc->priv->scheduler->priv->location_constraints,
690  new_con);
691  rsc->priv->location_constraints =
692  g_list_prepend(rsc->priv->location_constraints, new_con);
693 
694  return new_con;
695 }
696 
703 void
705 {
706  for (GList *iter = scheduler->priv->location_constraints;
707  iter != NULL; iter = iter->next) {
708  pcmk__location_t *location = iter->data;
709 
710  location->rsc->priv->cmds->apply_location(location->rsc, location);
711  }
712 }
713 
724 void
726 {
727  bool need_role = false;
728 
729  pcmk__assert((rsc != NULL) && (location != NULL));
730 
731  // If a role was specified, ensure constraint is applicable
732  need_role = (location->role_filter > pcmk_role_unknown);
733  if (need_role && (location->role_filter != rsc->priv->next_role)) {
734  pcmk__rsc_trace(rsc,
735  "Not applying %s to %s because role will be %s not %s",
736  location->id, rsc->id,
738  pcmk_role_text(location->role_filter));
739  return;
740  }
741 
742  if (location->nodes == NULL) {
743  pcmk__rsc_trace(rsc, "Not applying %s to %s because no nodes match",
744  location->id, rsc->id);
745  return;
746  }
747 
748  for (GList *iter = location->nodes; iter != NULL; iter = iter->next) {
749  pcmk_node_t *node = iter->data;
750  pcmk_node_t *allowed_node = NULL;
751 
752  allowed_node = g_hash_table_lookup(rsc->priv->allowed_nodes,
753  node->priv->id);
754 
755  pcmk__rsc_trace(rsc, "Applying %s%s%s to %s score on %s: %c %s",
756  location->id,
757  (need_role? " for role " : ""),
758  (need_role? pcmk_role_text(location->role_filter) : ""),
759  rsc->id, pcmk__node_name(node),
760  ((allowed_node == NULL)? '=' : '+'),
762 
763  if (allowed_node == NULL) {
764  allowed_node = pe__copy_node(node);
765  g_hash_table_insert(rsc->priv->allowed_nodes,
766  (gpointer) allowed_node->priv->id,
767  allowed_node);
768  } else {
769  allowed_node->assign->score =
770  pcmk__add_scores(allowed_node->assign->score,
771  node->assign->score);
772  }
773 
774  if (allowed_node->assign->probe_mode < location->probe_mode) {
775  if (location->probe_mode == pcmk__probe_exclusive) {
777  }
778  /* exclusive > never > always... always is default */
779  allowed_node->assign->probe_mode = location->probe_mode;
780  }
781  }
782 }
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:213
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:100
enum pcmk__probe_mode probe_mode
xmlNode * pcmk__xe_resolve_idref(xmlNode *xml, xmlNode *search)
Definition: xml_idref.c:85
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
A dumping ground.
pcmk_node_t * pe__copy_node(const pcmk_node_t *this_node)
Definition: utils.c:91
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
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:830
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 * name
Definition: cib.c:26
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:102
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...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define PCMK_META_CONTAINER_ATTRIBUTE_TARGET
Definition: options.h:85
#define PCMK_XA_RESOURCE_DISCOVERY
Definition: xml_names.h:384
#define PCMK_XE_RESOURCE_REF
Definition: xml_names.h:177
enum pcmk__probe_mode probe_mode
#define pcmk__set_rsc_flags(resource, flags_to_set)
#define pcmk__config_err(fmt...)
pcmk__scheduler_private_t * priv
Definition: scheduler.h:99
#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__xe_remove_attr(xmlNode *element, const char *name)
Definition: xml_element.c:339
void pcmk__apply_locations(pcmk_scheduler_t *scheduler)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:609
#define PCMK_VALUE_NEVER
Definition: options.h:178
enum rsc_role_e pcmk_parse_role(const char *role)
Parse a resource role from a string role specification.
Definition: roles.c:51
#define PCMK_XA_NODE
Definition: xml_names.h:335
pcmk__location_t * pcmk__new_location(const char *id, pcmk_resource_t *rsc, int node_score, const char *probe_mode, pcmk_node_t *node)
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
pcmk__combine
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
pcmk__node_private_t * priv
Definition: nodes.h:85
gboolean local
Definition: cpg.c:50
char * pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches)
Definition: rules.c:613
#define crm_warn(fmt, args...)
Definition: logging.h:362
#define PCMK_VALUE_ALWAYS
Definition: options.h:132
#define crm_debug(fmt, args...)
Definition: logging.h:370
#define PCMK_XE_RSC_LOCATION
Definition: xml_names.h:188
pcmk_scheduler_t * scheduler
G_GNUC_INTERNAL pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
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:1303
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define crm_trace(fmt, args...)
Definition: logging.h:372
void(* apply_location)(pcmk_resource_t *rsc, pcmk__location_t *location)
pcmk__resource_private_t * priv
Definition: resources.h:61
Unpromoted.
Definition: roles.h:38
rsc_role_e
Definition: roles.h:34
#define PCMK_XA_ID
Definition: xml_names.h:301
pcmk_resource_t * rsc
#define PCMK_XA_SCORE
Definition: xml_names.h:396
void pcmk__apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:159
#define pcmk__str_copy(str)
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:675
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
Definition: xml_element.c:106
#define pcmk__assert(expr)
const char * target
Definition: pcmk_fence.c:31
Cluster status and scheduling.
GList * nodes
Definition: scheduler.h:97
#define PCMK_VALUE_EXCLUSIVE
Definition: options.h:151
pcmk_scheduler_t * scheduler
const regmatch_t * rsc_id_submatches
Resource pattern submatches (as set by regexec()) for rsc_id.
Definition: rules.h:99
G_GNUC_INTERNAL bool pcmk__valid_resource_or_tag(const pcmk_scheduler_t *scheduler, const char *id, pcmk_resource_t **rsc, pcmk__idref_t **tag)
#define PCMK_XE_RESOURCE_SET
Definition: xml_names.h:178
xmlNode * input
Definition: scheduler.h:81
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:114
Started.
Definition: roles.h:37
enum rsc_role_e role_filter
GHashTable * attrs
int pcmk_parse_score(const char *score_s, int *score, int default_score)
Parse an integer score from a string.
Definition: scores.c:34
#define PCMK_XA_RSC_PATTERN
Definition: xml_names.h:389
GHashTable * node_attrs
Definition: rules.h:77
#define PCMK_XA_BOOLEAN_OP
Definition: xml_names.h:240
#define crm_log_xml_trace(xml, text)
Definition: logging.h:380
Resource role is unknown.
Definition: roles.h:35
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:476
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
const char * rsc_id
Resource ID to compare against a location constraint&#39;s resource pattern.
Definition: rules.h:96
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
#define crm_info(fmt, args...)
Definition: logging.h:367
const pcmk__assignment_methods_t * cmds
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150
struct pcmk__node_assignment * assign
Definition: nodes.h:79