pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
rules.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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/msg_xml.h>
13 #include <crm/common/xml.h>
15 
16 #include <glib.h>
17 
18 #include <crm/pengine/rules.h>
20 #include <crm/pengine/internal.h>
21 
22 #include <sys/types.h>
23 #include <regex.h>
24 #include <ctype.h>
25 
26 CRM_TRACE_INIT_DATA(pe_rules);
27 
38 gboolean
39 pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now,
40  crm_time_t *next_change)
41 {
42  pe_rule_eval_data_t rule_data = {
43  .node_hash = node_hash,
44  .role = RSC_ROLE_UNKNOWN,
45  .now = now,
46  .match_data = NULL,
47  .rsc_data = NULL,
48  .op_data = NULL
49  };
50 
51  return pe_eval_rules(ruleset, &rule_data, next_change);
52 }
53 
54 gboolean
55 pe_test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
56  crm_time_t *now, crm_time_t *next_change,
57  pe_match_data_t *match_data)
58 {
59  pe_rule_eval_data_t rule_data = {
60  .node_hash = node_hash,
61  .role = role,
62  .now = now,
63  .match_data = match_data,
64  .rsc_data = NULL,
65  .op_data = NULL
66  };
67 
68  return pe_eval_expr(rule, &rule_data, next_change);
69 }
70 
87 gboolean
88 pe_test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role,
89  crm_time_t *now, crm_time_t *next_change,
90  pe_match_data_t *match_data)
91 {
92  pe_rule_eval_data_t rule_data = {
93  .node_hash = node_hash,
94  .role = role,
95  .now = now,
96  .match_data = match_data,
97  .rsc_data = NULL,
98  .op_data = NULL
99  };
100 
101  return pe_eval_subexpr(expr, &rule_data, next_change);
102 }
103 
104 enum expression_type
105 find_expression_type(xmlNode * expr)
106 {
107  const char *tag = NULL;
108  const char *attr = NULL;
109 
111  tag = crm_element_name(expr);
112 
113  if (pcmk__str_eq(tag, PCMK_XE_DATE_EXPRESSION, pcmk__str_none)) {
114  return time_expr;
115 
116  } else if (pcmk__str_eq(tag, PCMK_XE_RSC_EXPRESSION, pcmk__str_none)) {
117  return rsc_expr;
118 
119  } else if (pcmk__str_eq(tag, PCMK_XE_OP_EXPRESSION, pcmk__str_none)) {
120  return op_expr;
121 
122  } else if (pcmk__str_eq(tag, XML_TAG_RULE, pcmk__str_none)) {
123  return nested_rule;
124 
125  } else if (!pcmk__str_eq(tag, XML_TAG_EXPRESSION, pcmk__str_none)) {
126  return not_expr;
127 
128  } else if (pcmk__str_any_of(attr, CRM_ATTR_UNAME, CRM_ATTR_KIND, CRM_ATTR_ID, NULL)) {
129  return loc_expr;
130 
131  } else if (pcmk__str_eq(attr, CRM_ATTR_ROLE, pcmk__str_none)) {
132  return role_expr;
133  }
134 
135  return attr_expr;
136 }
137 
138 /* As per the nethack rules:
139  *
140  * moon period = 29.53058 days ~= 30, year = 365.2422 days
141  * days moon phase advances on first day of year compared to preceding year
142  * = 365.2422 - 12*29.53058 ~= 11
143  * years in Metonic cycle (time until same phases fall on the same days of
144  * the month) = 18.6 ~= 19
145  * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
146  * (29 as initial condition)
147  * current phase in days = first day phase + days elapsed in year
148  * 6 moons ~= 177 days
149  * 177 ~= 8 reported phases * 22
150  * + 11/22 for rounding
151  *
152  * 0-7, with 0: new, 4: full
153  */
154 
155 static int
156 phase_of_the_moon(crm_time_t * now)
157 {
158  uint32_t epact, diy, goldn;
159  uint32_t y;
160 
161  crm_time_get_ordinal(now, &y, &diy);
162 
163  goldn = (y % 19) + 1;
164  epact = (11 * goldn + 18) % 30;
165  if ((epact == 25 && goldn > 11) || epact == 24)
166  epact++;
167 
168  return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
169 }
170 
171 static int
172 check_one(xmlNode *cron_spec, const char *xml_field, uint32_t time_field) {
173  int rc = pcmk_rc_undetermined;
174  const char *value = crm_element_value(cron_spec, xml_field);
175  long long low, high;
176 
177  if (value == NULL) {
178  /* Return pe_date_result_undetermined if the field is missing. */
179  goto bail;
180  }
181 
182  if (pcmk__parse_ll_range(value, &low, &high) == pcmk_rc_unknown_format) {
183  goto bail;
184  } else if (low == high) {
185  /* A single number was given, not a range. */
186  if (time_field < low) {
188  } else if (time_field > high) {
189  rc = pcmk_rc_after_range;
190  } else {
192  }
193  } else if (low != -1 && high != -1) {
194  /* This is a range with both bounds. */
195  if (time_field < low) {
197  } else if (time_field > high) {
198  rc = pcmk_rc_after_range;
199  } else {
201  }
202  } else if (low == -1) {
203  /* This is a range with no starting value. */
204  rc = time_field <= high ? pcmk_rc_within_range : pcmk_rc_after_range;
205  } else if (high == -1) {
206  /* This is a range with no ending value. */
207  rc = time_field >= low ? pcmk_rc_within_range : pcmk_rc_before_range;
208  }
209 
210 bail:
211  if (rc == pcmk_rc_within_range) {
212  crm_debug("Condition '%s' in %s: passed", value, xml_field);
213  } else {
214  crm_debug("Condition '%s' in %s: failed", value, xml_field);
215  }
216 
217  return rc;
218 }
219 
220 static gboolean
221 check_passes(int rc) {
222  /* _within_range is obvious. _undetermined is a pass because
223  * this is the return value if a field is not given. In this
224  * case, we just want to ignore it and check other fields to
225  * see if they place some restriction on what can pass.
226  */
227  return rc == pcmk_rc_within_range || rc == pcmk_rc_undetermined;
228 }
229 
230 #define CHECK_ONE(spec, name, var) do { \
231  int subpart_rc = check_one(spec, name, var); \
232  if (check_passes(subpart_rc) == FALSE) { \
233  return subpart_rc; \
234  } \
235 } while (0)
236 
237 int
238 pe_cron_range_satisfied(crm_time_t * now, xmlNode * cron_spec)
239 {
240  uint32_t h, m, s, y, d, w;
241 
242  CRM_CHECK(now != NULL, return pcmk_rc_op_unsatisfied);
243 
244  crm_time_get_gregorian(now, &y, &m, &d);
245  CHECK_ONE(cron_spec, "years", y);
246  CHECK_ONE(cron_spec, "months", m);
247  CHECK_ONE(cron_spec, "monthdays", d);
248 
249  crm_time_get_timeofday(now, &h, &m, &s);
250  CHECK_ONE(cron_spec, "hours", h);
251  CHECK_ONE(cron_spec, "minutes", m);
252  CHECK_ONE(cron_spec, "seconds", s);
253 
254  crm_time_get_ordinal(now, &y, &d);
255  CHECK_ONE(cron_spec, "yeardays", d);
256 
257  crm_time_get_isoweek(now, &y, &w, &d);
258  CHECK_ONE(cron_spec, "weekyears", y);
259  CHECK_ONE(cron_spec, "weeks", w);
260  CHECK_ONE(cron_spec, "weekdays", d);
261 
262  CHECK_ONE(cron_spec, "moon", phase_of_the_moon(now));
263 
264  /* If we get here, either no fields were specified (which is success), or all
265  * the fields that were specified had their conditions met (which is also a
266  * success). Thus, the result is success.
267  */
268  return pcmk_rc_ok;
269 }
270 
271 static void
272 update_field(crm_time_t *t, xmlNode *xml, const char *attr,
273  void (*time_fn)(crm_time_t *, int))
274 {
275  long long value;
276 
277  if ((pcmk__scan_ll(crm_element_value(xml, attr), &value, 0LL) == pcmk_rc_ok)
278  && (value != 0LL) && (value >= INT_MIN) && (value <= INT_MAX)) {
279  time_fn(t, (int) value);
280  }
281 }
282 
283 crm_time_t *
284 pe_parse_xml_duration(crm_time_t * start, xmlNode * duration_spec)
285 {
286  crm_time_t *end = pcmk_copy_time(start);
287 
288  update_field(end, duration_spec, "years", crm_time_add_years);
289  update_field(end, duration_spec, "months", crm_time_add_months);
290  update_field(end, duration_spec, "weeks", crm_time_add_weeks);
291  update_field(end, duration_spec, "days", crm_time_add_days);
292  update_field(end, duration_spec, "hours", crm_time_add_hours);
293  update_field(end, duration_spec, "minutes", crm_time_add_minutes);
294  update_field(end, duration_spec, "seconds", crm_time_add_seconds);
295 
296  return end;
297 }
298 
299 // Set next_change to t if t is earlier
300 static void
301 crm_time_set_if_earlier(crm_time_t *next_change, crm_time_t *t)
302 {
303  if ((next_change != NULL) && (t != NULL)) {
304  if (!crm_time_is_defined(next_change)
305  || (crm_time_compare(t, next_change) < 0)) {
306  crm_time_set(next_change, t);
307  }
308  }
309 }
310 
311 // Information about a block of nvpair elements
312 typedef struct sorted_set_s {
313  int score; // This block's score for sorting
314  const char *name; // This block's ID
315  const char *special_name; // ID that should sort first
316  xmlNode *attr_set; // This block
317 } sorted_set_t;
318 
319 static gint
320 sort_pairs(gconstpointer a, gconstpointer b)
321 {
322  const sorted_set_t *pair_a = a;
323  const sorted_set_t *pair_b = b;
324 
325  if (a == NULL && b == NULL) {
326  return 0;
327  } else if (a == NULL) {
328  return 1;
329  } else if (b == NULL) {
330  return -1;
331  }
332 
333  if (pcmk__str_eq(pair_a->name, pair_a->special_name, pcmk__str_casei)) {
334  return -1;
335 
336  } else if (pcmk__str_eq(pair_b->name, pair_a->special_name, pcmk__str_casei)) {
337  return 1;
338  }
339 
340  if (pair_a->score < pair_b->score) {
341  return 1;
342  } else if (pair_a->score > pair_b->score) {
343  return -1;
344  }
345  return 0;
346 }
347 
348 static void
349 populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlNode * top)
350 {
351  const char *name = NULL;
352  const char *value = NULL;
353  const char *old_value = NULL;
354  xmlNode *list = nvpair_list;
355  xmlNode *an_attr = NULL;
356 
357  name = crm_element_name(list->children);
358  if (pcmk__str_eq(XML_TAG_ATTRS, name, pcmk__str_casei)) {
359  list = list->children;
360  }
361 
362  for (an_attr = pcmk__xe_first_child(list); an_attr != NULL;
363  an_attr = pcmk__xe_next(an_attr)) {
364 
365  if (pcmk__str_eq((const char *)an_attr->name, XML_CIB_TAG_NVPAIR, pcmk__str_none)) {
366  xmlNode *ref_nvpair = expand_idref(an_attr, top);
367 
369  if (name == NULL) {
371  }
372 
373  value = crm_element_value(an_attr, XML_NVPAIR_ATTR_VALUE);
374  if (value == NULL) {
375  value = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_VALUE);
376  }
377 
378  if (name == NULL || value == NULL) {
379  continue;
380  }
381 
382  old_value = g_hash_table_lookup(hash, name);
383 
384  if (pcmk__str_eq(value, "#default", pcmk__str_casei)) {
385  if (old_value) {
386  crm_trace("Letting %s default (removing explicit value \"%s\")",
387  name, value);
388  g_hash_table_remove(hash, name);
389  }
390  continue;
391 
392  } else if (old_value == NULL) {
393  crm_trace("Setting %s=\"%s\"", name, value);
394  g_hash_table_insert(hash, strdup(name), strdup(value));
395 
396  } else if (overwrite) {
397  crm_trace("Setting %s=\"%s\" (overwriting old value \"%s\")",
398  name, value, old_value);
399  g_hash_table_replace(hash, strdup(name), strdup(value));
400  }
401  }
402  }
403 }
404 
405 typedef struct unpack_data_s {
406  gboolean overwrite;
407  void *hash;
408  crm_time_t *next_change;
409  pe_rule_eval_data_t *rule_data;
410  xmlNode *top;
411 } unpack_data_t;
412 
413 static void
414 unpack_attr_set(gpointer data, gpointer user_data)
415 {
416  sorted_set_t *pair = data;
417  unpack_data_t *unpack_data = user_data;
418 
419  if (!pe_eval_rules(pair->attr_set, unpack_data->rule_data,
420  unpack_data->next_change)) {
421  return;
422  }
423 
424  crm_trace("Adding attributes from %s (score %d) %s overwrite",
425  pair->name, pair->score,
426  (unpack_data->overwrite? "with" : "without"));
427  populate_hash(pair->attr_set, unpack_data->hash, unpack_data->overwrite, unpack_data->top);
428 }
429 
441 static GList *
442 make_pairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
443  const char *always_first)
444 {
445  GList *unsorted = NULL;
446 
447  if (xml_obj == NULL) {
448  return NULL;
449  }
450  for (xmlNode *attr_set = pcmk__xe_first_child(xml_obj); attr_set != NULL;
451  attr_set = pcmk__xe_next(attr_set)) {
452 
453  if (pcmk__str_eq(set_name, (const char *) attr_set->name,
455  const char *score = NULL;
456  sorted_set_t *pair = NULL;
457  xmlNode *expanded_attr_set = expand_idref(attr_set, top);
458 
459  if (expanded_attr_set == NULL) {
460  // Schema (if not "none") prevents this
461  continue;
462  }
463 
464  pair = calloc(1, sizeof(sorted_set_t));
465  pair->name = ID(expanded_attr_set);
466  pair->special_name = always_first;
467  pair->attr_set = expanded_attr_set;
468 
469  score = crm_element_value(expanded_attr_set, XML_RULE_ATTR_SCORE);
470  pair->score = char2score(score);
471 
472  unsorted = g_list_prepend(unsorted, pair);
473  }
474  }
475  return g_list_sort(unsorted, sort_pairs);
476 }
477 
492 static void
493 unpack_nvpair_blocks(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
494  void *hash, const char *always_first, gboolean overwrite,
495  pe_rule_eval_data_t *rule_data, crm_time_t *next_change,
496  GFunc unpack_func)
497 {
498  GList *pairs = make_pairs(top, xml_obj, set_name, always_first);
499 
500  if (pairs) {
501  unpack_data_t data = {
502  .hash = hash,
503  .overwrite = overwrite,
504  .next_change = next_change,
505  .top = top,
506  .rule_data = rule_data
507  };
508 
509  g_list_foreach(pairs, unpack_func, &data);
510  g_list_free_full(pairs, free);
511  }
512 }
513 
514 void
515 pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
516  pe_rule_eval_data_t *rule_data, GHashTable *hash,
517  const char *always_first, gboolean overwrite,
518  crm_time_t *next_change)
519 {
520  unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first,
521  overwrite, rule_data, next_change, unpack_attr_set);
522 }
523 
537 void
538 pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name,
539  GHashTable *node_hash, GHashTable *hash,
540  const char *always_first, gboolean overwrite,
541  crm_time_t *now, crm_time_t *next_change)
542 {
543  pe_rule_eval_data_t rule_data = {
544  .node_hash = node_hash,
545  .role = RSC_ROLE_UNKNOWN,
546  .now = now,
547  .match_data = NULL,
548  .rsc_data = NULL,
549  .op_data = NULL
550  };
551 
552  pe_eval_nvpairs(top, xml_obj, set_name, &rule_data, hash,
553  always_first, overwrite, next_change);
554 }
555 
556 char *
557 pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
558 {
559  size_t len = 0;
560  int i;
561  const char *p, *last_match_index;
562  char *p_dst, *result = NULL;
563 
564  if (pcmk__str_empty(string) || !match_data) {
565  return NULL;
566  }
567 
568  p = last_match_index = string;
569 
570  while (*p) {
571  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
572  i = *(p + 1) - '0';
573  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
574  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
575  len += p - last_match_index + (match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so);
576  last_match_index = p + 2;
577  }
578  p++;
579  }
580  p++;
581  }
582  len += p - last_match_index + 1;
583 
584  /* FIXME: Excessive? */
585  if (len - 1 <= 0) {
586  return NULL;
587  }
588 
589  p_dst = result = calloc(1, len);
590  p = string;
591 
592  while (*p) {
593  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
594  i = *(p + 1) - '0';
595  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
596  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
597  /* rm_eo can be equal to rm_so, but then there is nothing to do */
598  int match_len = match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so;
599  memcpy(p_dst, match_data->string + match_data->pmatch[i].rm_so, match_len);
600  p_dst += match_len;
601  }
602  p++;
603  } else {
604  *(p_dst) = *(p);
605  p_dst++;
606  }
607  p++;
608  }
609 
610  return result;
611 }
612 
613 gboolean
614 pe_eval_rules(xmlNode *ruleset, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
615 {
616  // If there are no rules, pass by default
617  gboolean ruleset_default = TRUE;
618 
619  for (xmlNode *rule = first_named_child(ruleset, XML_TAG_RULE);
620  rule != NULL; rule = crm_next_same_xml(rule)) {
621 
622  ruleset_default = FALSE;
623  if (pe_eval_expr(rule, rule_data, next_change)) {
624  /* Only the deprecated "lifetime" element of location constraints
625  * may contain more than one rule at the top level -- the schema
626  * limits a block of nvpairs to a single top-level rule. So, this
627  * effectively means that a lifetime is active if any rule it
628  * contains is active.
629  */
630  return TRUE;
631  }
632  }
633 
634  return ruleset_default;
635 }
636 
637 gboolean
638 pe_eval_expr(xmlNode *rule, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
639 {
640  xmlNode *expr = NULL;
641  gboolean test = TRUE;
642  gboolean empty = TRUE;
643  gboolean passed = TRUE;
644  gboolean do_and = TRUE;
645  const char *value = NULL;
646 
647  rule = expand_idref(rule, NULL);
649  if (pcmk__str_eq(value, "or", pcmk__str_casei)) {
650  do_and = FALSE;
651  passed = FALSE;
652  }
653 
654  crm_trace("Testing rule %s", ID(rule));
655  for (expr = pcmk__xe_first_child(rule); expr != NULL;
656  expr = pcmk__xe_next(expr)) {
657 
658  test = pe_eval_subexpr(expr, rule_data, next_change);
659  empty = FALSE;
660 
661  if (test && do_and == FALSE) {
662  crm_trace("Expression %s/%s passed", ID(rule), ID(expr));
663  return TRUE;
664 
665  } else if (test == FALSE && do_and) {
666  crm_trace("Expression %s/%s failed", ID(rule), ID(expr));
667  return FALSE;
668  }
669  }
670 
671  if (empty) {
672  crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule));
673  }
674 
675  crm_trace("Rule %s %s", ID(rule), passed ? "passed" : "failed");
676  return passed;
677 }
678 
679 gboolean
680 pe_eval_subexpr(xmlNode *expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
681 {
682  gboolean accept = FALSE;
683  const char *uname = NULL;
684 
685  switch (find_expression_type(expr)) {
686  case nested_rule:
687  accept = pe_eval_expr(expr, rule_data, next_change);
688  break;
689  case attr_expr:
690  case loc_expr:
691  /* these expressions can never succeed if there is
692  * no node to compare with
693  */
694  if (rule_data->node_hash != NULL) {
695  accept = pe__eval_attr_expr(expr, rule_data);
696  }
697  break;
698 
699  case time_expr:
700  switch (pe__eval_date_expr(expr, rule_data, next_change)) {
702  case pcmk_rc_ok:
703  accept = TRUE;
704  break;
705 
706  default:
707  accept = FALSE;
708  break;
709  }
710  break;
711 
712  case role_expr:
713  accept = pe__eval_role_expr(expr, rule_data);
714  break;
715 
716  case rsc_expr:
717  accept = pe__eval_rsc_expr(expr, rule_data);
718  break;
719 
720  case op_expr:
721  accept = pe__eval_op_expr(expr, rule_data);
722  break;
723 
724  default:
725  CRM_CHECK(FALSE /* bad type */ , return FALSE);
726  accept = FALSE;
727  }
728  if (rule_data->node_hash) {
729  uname = g_hash_table_lookup(rule_data->node_hash, CRM_ATTR_UNAME);
730  }
731 
732  crm_trace("Expression %s %s on %s",
733  ID(expr), accept ? "passed" : "failed", uname ? uname : "all nodes");
734  return accept;
735 }
736 
752 static int
753 compare_attr_expr_vals(const char *l_val, const char *r_val, const char *type,
754  const char *op)
755 {
756  int cmp = 0;
757 
758  if (l_val != NULL && r_val != NULL) {
759  if (type == NULL) {
760  if (pcmk__strcase_any_of(op, "lt", "lte", "gt", "gte", NULL)) {
761  if (pcmk__char_in_any_str('.', l_val, r_val, NULL)) {
762  type = "number";
763  } else {
764  type = "integer";
765  }
766 
767  } else {
768  type = "string";
769  }
770  crm_trace("Defaulting to %s based comparison for '%s' op", type, op);
771  }
772 
773  if (pcmk__str_eq(type, "string", pcmk__str_casei)) {
774  cmp = strcasecmp(l_val, r_val);
775 
776  } else if (pcmk__str_eq(type, "integer", pcmk__str_casei)) {
777  long long l_val_num;
778  int rc1 = pcmk__scan_ll(l_val, &l_val_num, 0LL);
779 
780  long long r_val_num;
781  int rc2 = pcmk__scan_ll(r_val, &r_val_num, 0LL);
782 
783  if ((rc1 == pcmk_rc_ok) && (rc2 == pcmk_rc_ok)) {
784  if (l_val_num < r_val_num) {
785  cmp = -1;
786  } else if (l_val_num > r_val_num) {
787  cmp = 1;
788  } else {
789  cmp = 0;
790  }
791 
792  } else {
793  crm_debug("Integer parse error. Comparing %s and %s as strings",
794  l_val, r_val);
795  cmp = compare_attr_expr_vals(l_val, r_val, "string", op);
796  }
797 
798  } else if (pcmk__str_eq(type, "number", pcmk__str_casei)) {
799  double l_val_num;
800  double r_val_num;
801 
802  int rc1 = pcmk__scan_double(l_val, &l_val_num, NULL, NULL);
803  int rc2 = pcmk__scan_double(r_val, &r_val_num, NULL, NULL);
804 
805  if (rc1 == pcmk_rc_ok && rc2 == pcmk_rc_ok) {
806  if (l_val_num < r_val_num) {
807  cmp = -1;
808  } else if (l_val_num > r_val_num) {
809  cmp = 1;
810  } else {
811  cmp = 0;
812  }
813 
814  } else {
815  crm_debug("Floating-point parse error. Comparing %s and %s as "
816  "strings", l_val, r_val);
817  cmp = compare_attr_expr_vals(l_val, r_val, "string", op);
818  }
819 
820  } else if (pcmk__str_eq(type, "version", pcmk__str_casei)) {
821  cmp = compare_version(l_val, r_val);
822 
823  }
824 
825  } else if (l_val == NULL && r_val == NULL) {
826  cmp = 0;
827  } else if (r_val == NULL) {
828  cmp = 1;
829  } else { // l_val == NULL && r_val != NULL
830  cmp = -1;
831  }
832 
833  return cmp;
834 }
835 
850 static bool
851 accept_attr_expr(const char *l_val, const char *r_val, const char *type,
852  const char *op)
853 {
854  int cmp;
855 
856  if (pcmk__str_eq(op, "defined", pcmk__str_casei)) {
857  return (l_val != NULL);
858 
859  } else if (pcmk__str_eq(op, "not_defined", pcmk__str_casei)) {
860  return (l_val == NULL);
861 
862  }
863 
864  cmp = compare_attr_expr_vals(l_val, r_val, type, op);
865 
866  if (pcmk__str_eq(op, "eq", pcmk__str_casei)) {
867  return (cmp == 0);
868 
869  } else if (pcmk__str_eq(op, "ne", pcmk__str_casei)) {
870  return (cmp != 0);
871 
872  } else if (l_val == NULL || r_val == NULL) {
873  // The comparison is meaningless from this point on
874  return false;
875 
876  } else if (pcmk__str_eq(op, "lt", pcmk__str_casei)) {
877  return (cmp < 0);
878 
879  } else if (pcmk__str_eq(op, "lte", pcmk__str_casei)) {
880  return (cmp <= 0);
881 
882  } else if (pcmk__str_eq(op, "gt", pcmk__str_casei)) {
883  return (cmp > 0);
884 
885  } else if (pcmk__str_eq(op, "gte", pcmk__str_casei)) {
886  return (cmp >= 0);
887  }
888 
889  return false; // Should never reach this point
890 }
891 
900 static const char *
901 expand_value_source(const char *value, const char *value_source,
902  pe_match_data_t *match_data)
903 {
904  GHashTable *table = NULL;
905 
906  if (pcmk__str_empty(value)) {
907  return NULL; // value_source is irrelevant
908 
909  } else if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
910  table = match_data->params;
911 
912  } else if (pcmk__str_eq(value_source, "meta", pcmk__str_casei)) {
913  table = match_data->meta;
914 
915  } else { // literal
916  return value;
917  }
918 
919  if (table == NULL) {
920  return NULL;
921  }
922  return (const char *) g_hash_table_lookup(table, value);
923 }
924 
935 gboolean
936 pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
937 {
938  gboolean attr_allocated = FALSE;
939  const char *h_val = NULL;
940 
941  const char *op = NULL;
942  const char *type = NULL;
943  const char *attr = NULL;
944  const char *value = NULL;
945  const char *value_source = NULL;
946 
949  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
951  value_source = crm_element_value(expr, XML_EXPR_ATTR_VALUE_SOURCE);
952 
953  if (attr == NULL) {
954  pe_err("Expression %s invalid: " XML_EXPR_ATTR_ATTRIBUTE
955  " not specified", pcmk__s(ID(expr), "without ID"));
956  return FALSE;
957  } else if (op == NULL) {
958  pe_err("Expression %s invalid: " XML_EXPR_ATTR_OPERATION
959  " not specified", pcmk__s(ID(expr), "without ID"));
960  }
961 
962  if (rule_data->match_data != NULL) {
963  // Expand any regular expression submatches (%0-%9) in attribute name
964  if (rule_data->match_data->re != NULL) {
965  char *resolved_attr = pe_expand_re_matches(attr, rule_data->match_data->re);
966 
967  if (resolved_attr != NULL) {
968  attr = (const char *) resolved_attr;
969  attr_allocated = TRUE;
970  }
971  }
972 
973  // Get value appropriate to value-source
974  value = expand_value_source(value, value_source, rule_data->match_data);
975  }
976 
977  if (rule_data->node_hash != NULL) {
978  h_val = (const char *)g_hash_table_lookup(rule_data->node_hash, attr);
979  }
980 
981  if (attr_allocated) {
982  free((char *)attr);
983  attr = NULL;
984  }
985 
986  return accept_attr_expr(h_val, value, type, op);
987 }
988 
999 int
1000 pe__eval_date_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
1001 {
1002  crm_time_t *start = NULL;
1003  crm_time_t *end = NULL;
1004  const char *value = NULL;
1005  const char *op = crm_element_value(expr, "operation");
1006 
1007  xmlNode *duration_spec = NULL;
1008  xmlNode *date_spec = NULL;
1009 
1010  // "undetermined" will also be returned for parsing errors
1011  int rc = pcmk_rc_undetermined;
1012 
1013  crm_trace("Testing expression: %s", ID(expr));
1014 
1015  duration_spec = first_named_child(expr, "duration");
1016  date_spec = first_named_child(expr, "date_spec");
1017 
1018  value = crm_element_value(expr, "start");
1019  if (value != NULL) {
1020  start = crm_time_new(value);
1021  }
1022  value = crm_element_value(expr, "end");
1023  if (value != NULL) {
1024  end = crm_time_new(value);
1025  }
1026 
1027  if (start != NULL && end == NULL && duration_spec != NULL) {
1028  end = pe_parse_xml_duration(start, duration_spec);
1029  }
1030 
1031  if (pcmk__str_eq(op, "in_range", pcmk__str_null_matches | pcmk__str_casei)) {
1032  if ((start == NULL) && (end == NULL)) {
1033  // in_range requires at least one of start or end
1034  } else if ((start != NULL) && (crm_time_compare(rule_data->now, start) < 0)) {
1035  rc = pcmk_rc_before_range;
1036  crm_time_set_if_earlier(next_change, start);
1037  } else if ((end != NULL) && (crm_time_compare(rule_data->now, end) > 0)) {
1038  rc = pcmk_rc_after_range;
1039  } else {
1040  rc = pcmk_rc_within_range;
1041  if (end && next_change) {
1042  // Evaluation doesn't change until second after end
1043  crm_time_add_seconds(end, 1);
1044  crm_time_set_if_earlier(next_change, end);
1045  }
1046  }
1047 
1048  } else if (pcmk__str_eq(op, "date_spec", pcmk__str_casei)) {
1049  rc = pe_cron_range_satisfied(rule_data->now, date_spec);
1050  // @TODO set next_change appropriately
1051 
1052  } else if (pcmk__str_eq(op, "gt", pcmk__str_casei)) {
1053  if (start == NULL) {
1054  // gt requires start
1055  } else if (crm_time_compare(rule_data->now, start) > 0) {
1056  rc = pcmk_rc_within_range;
1057  } else {
1058  rc = pcmk_rc_before_range;
1059 
1060  // Evaluation doesn't change until second after start
1061  crm_time_add_seconds(start, 1);
1062  crm_time_set_if_earlier(next_change, start);
1063  }
1064 
1065  } else if (pcmk__str_eq(op, "lt", pcmk__str_casei)) {
1066  if (end == NULL) {
1067  // lt requires end
1068  } else if (crm_time_compare(rule_data->now, end) < 0) {
1069  rc = pcmk_rc_within_range;
1070  crm_time_set_if_earlier(next_change, end);
1071  } else {
1072  rc = pcmk_rc_after_range;
1073  }
1074  }
1075 
1076  crm_time_free(start);
1077  crm_time_free(end);
1078  return rc;
1079 }
1080 
1081 gboolean
1082 pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) {
1083  const char *name = crm_element_value(expr, XML_NVPAIR_ATTR_NAME);
1084  const char *interval_s = crm_element_value(expr, XML_LRM_ATTR_INTERVAL);
1085  guint interval;
1086 
1087  crm_trace("Testing op_defaults expression: %s", ID(expr));
1088 
1089  if (rule_data->op_data == NULL) {
1090  crm_trace("No operations data provided");
1091  return FALSE;
1092  }
1093 
1094  interval = crm_parse_interval_spec(interval_s);
1095  if (interval == 0 && errno != 0) {
1096  crm_trace("Could not parse interval: %s", interval_s);
1097  return FALSE;
1098  }
1099 
1100  if (interval_s != NULL && interval != rule_data->op_data->interval) {
1101  crm_trace("Interval doesn't match: %d != %d", interval, rule_data->op_data->interval);
1102  return FALSE;
1103  }
1104 
1105  if (!pcmk__str_eq(name, rule_data->op_data->op_name, pcmk__str_none)) {
1106  crm_trace("Name doesn't match: %s != %s", name, rule_data->op_data->op_name);
1107  return FALSE;
1108  }
1109 
1110  return TRUE;
1111 }
1112 
1122 gboolean
1123 pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
1124 {
1125  gboolean accept = FALSE;
1126  const char *op = NULL;
1127  const char *value = NULL;
1128 
1129  if (rule_data->role == RSC_ROLE_UNKNOWN) {
1130  return accept;
1131  }
1132 
1133  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
1135 
1136  if (pcmk__str_eq(op, "defined", pcmk__str_casei)) {
1137  if (rule_data->role > RSC_ROLE_STARTED) {
1138  accept = TRUE;
1139  }
1140 
1141  } else if (pcmk__str_eq(op, "not_defined", pcmk__str_casei)) {
1142  if ((rule_data->role > RSC_ROLE_UNKNOWN)
1143  && (rule_data->role < RSC_ROLE_UNPROMOTED)) {
1144  accept = TRUE;
1145  }
1146 
1147  } else if (pcmk__str_eq(op, "eq", pcmk__str_casei)) {
1148  if (text2role(value) == rule_data->role) {
1149  accept = TRUE;
1150  }
1151 
1152  } else if (pcmk__str_eq(op, "ne", pcmk__str_casei)) {
1153  // Test "ne" only with promotable clone roles
1154  if ((rule_data->role > RSC_ROLE_UNKNOWN)
1155  && (rule_data->role < RSC_ROLE_UNPROMOTED)) {
1156  accept = FALSE;
1157 
1158  } else if (text2role(value) != rule_data->role) {
1159  accept = TRUE;
1160  }
1161  }
1162  return accept;
1163 }
1164 
1165 gboolean
1166 pe__eval_rsc_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
1167 {
1168  const char *class = crm_element_value(expr, XML_AGENT_ATTR_CLASS);
1169  const char *provider = crm_element_value(expr, XML_AGENT_ATTR_PROVIDER);
1170  const char *type = crm_element_value(expr, XML_EXPR_ATTR_TYPE);
1171 
1172  crm_trace("Testing rsc_defaults expression: %s", ID(expr));
1173 
1174  if (rule_data->rsc_data == NULL) {
1175  crm_trace("No resource data provided");
1176  return FALSE;
1177  }
1178 
1179  if (class != NULL &&
1180  !pcmk__str_eq(class, rule_data->rsc_data->standard, pcmk__str_none)) {
1181  crm_trace("Class doesn't match: %s != %s", class, rule_data->rsc_data->standard);
1182  return FALSE;
1183  }
1184 
1185  if ((provider == NULL && rule_data->rsc_data->provider != NULL) ||
1186  (provider != NULL && rule_data->rsc_data->provider == NULL) ||
1187  !pcmk__str_eq(provider, rule_data->rsc_data->provider, pcmk__str_none)) {
1188  crm_trace("Provider doesn't match: %s != %s", provider, rule_data->rsc_data->provider);
1189  return FALSE;
1190  }
1191 
1192  if (type != NULL &&
1193  !pcmk__str_eq(type, rule_data->rsc_data->agent, pcmk__str_none)) {
1194  crm_trace("Agent doesn't match: %s != %s", type, rule_data->rsc_data->agent);
1195  return FALSE;
1196  }
1197 
1198  return TRUE;
1199 }
1200 
1201 // Deprecated functions kept only for backward API compatibility
1202 // LCOV_EXCL_START
1203 
1204 #include <crm/pengine/rules_compat.h>
1205 
1206 gboolean
1207 test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
1208 {
1209  return pe_evaluate_rules(ruleset, node_hash, now, NULL);
1210 }
1211 
1212 gboolean
1213 test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
1214 {
1215  return pe_test_rule(rule, node_hash, role, now, NULL, NULL);
1216 }
1217 
1218 gboolean
1219 pe_test_rule_re(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data)
1220 {
1221  pe_match_data_t match_data = {
1222  .re = re_match_data,
1223  .params = NULL,
1224  .meta = NULL,
1225  };
1226  return pe_test_rule(rule, node_hash, role, now, NULL, &match_data);
1227 }
1228 
1229 gboolean
1230 pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
1231  crm_time_t *now, pe_match_data_t *match_data)
1232 {
1233  return pe_test_rule(rule, node_hash, role, now, NULL, match_data);
1234 }
1235 
1236 gboolean
1237 test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
1238 {
1239  return pe_test_expression(expr, node_hash, role, now, NULL, NULL);
1240 }
1241 
1242 gboolean
1243 pe_test_expression_re(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_re_match_data_t * re_match_data)
1244 {
1245  pe_match_data_t match_data = {
1246  .re = re_match_data,
1247  .params = NULL,
1248  .meta = NULL,
1249  };
1250  return pe_test_expression(expr, node_hash, role, now, NULL, &match_data);
1251 }
1252 
1253 gboolean
1254 pe_test_expression_full(xmlNode *expr, GHashTable *node_hash,
1255  enum rsc_role_e role, crm_time_t *now,
1256  pe_match_data_t *match_data)
1257 {
1258  return pe_test_expression(expr, node_hash, role, now, NULL, match_data);
1259 }
1260 
1261 void
1262 unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name,
1263  GHashTable *node_hash, GHashTable *hash,
1264  const char *always_first, gboolean overwrite,
1265  crm_time_t *now)
1266 {
1267  pe_rule_eval_data_t rule_data = {
1268  .node_hash = node_hash,
1269  .role = RSC_ROLE_UNKNOWN,
1270  .now = now,
1271  .match_data = NULL,
1272  .rsc_data = NULL,
1273  .op_data = NULL
1274  };
1275 
1276  unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first,
1277  overwrite, &rule_data, NULL, unpack_attr_set);
1278 }
1279 
1280 // LCOV_EXCL_STOP
1281 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
A dumping ground.
void crm_time_add_years(crm_time_t *dt, int value)
Definition: iso8601.c:1527
gboolean pe_test_rule_re(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, pe_re_match_data_t *re_match_data)
Definition: rules.c:1219
const char * provider
Definition: common.h:184
int crm_time_get_isoweek(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d)
Definition: iso8601.c:399
Definition: rules.h:33
Deprecated Pacemaker rule API.
void crm_time_add_seconds(crm_time_t *dt, int value)
Add a given number of seconds to a date/time or duration.
Definition: iso8601.c:1422
char data[0]
Definition: cpg.c:55
bool pcmk__char_in_any_str(int ch,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:975
#define CRM_ATTR_KIND
Definition: crm.h:115
#define XML_EXPR_ATTR_TYPE
Definition: msg_xml.h:348
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:132
const char * name
Definition: cib.c:24
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
struct crm_time_s crm_time_t
Definition: iso8601.h:32
gboolean test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:1237
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:336
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
void pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *next_change)
Definition: rules.c:515
int char2score(const char *score)
Get the integer value of a score string.
Definition: scores.c:36
crm_time_t * pcmk_copy_time(const crm_time_t *source)
Definition: iso8601.c:1265
pe_re_match_data_t * re
Definition: common.h:177
#define XML_TAG_ATTRS
Definition: msg_xml.h:211
gboolean pe_test_expression_re(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, pe_re_match_data_t *re_match_data)
Definition: rules.c:1243
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:294
#define CRM_ATTR_ROLE
Definition: crm.h:116
#define XML_EXPR_ATTR_VALUE_SOURCE
Definition: msg_xml.h:349
void pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition: rules.c:538
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:391
#define CHECK_ONE(spec, name, var)
Definition: rules.c:230
enum crm_ais_msg_types type
Definition: cpg.c:48
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_CIB_TAG_NVPAIR
Definition: msg_xml.h:206
Definition: rules.h:34
int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d)
Definition: iso8601.c:391
gboolean pe_eval_rules(xmlNode *ruleset, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:614
void crm_time_add_hours(crm_time_t *dt, int value)
Definition: iso8601.c:1515
gboolean pe_test_expression_full(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, pe_match_data_t *match_data)
Definition: rules.c:1254
guint interval
Definition: common.h:190
pe_match_data_t * match_data
Definition: common.h:197
int pe__eval_date_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:1000
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:97
gboolean pe_test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, crm_time_t *next_change, pe_match_data_t *match_data)
Evaluate one rule subelement (pass/fail)
Definition: rules.c:88
pe_op_eval_data_t * op_data
Definition: common.h:199
Definition: rules.h:23
#define crm_debug(fmt, args...)
Definition: logging.h:364
void crm_time_set(crm_time_t *target, const crm_time_t *source)
Definition: iso8601.c:1196
gboolean pe_eval_subexpr(xmlNode *expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:680
void crm_time_add_weeks(crm_time_t *dt, int value)
Definition: iso8601.c:1521
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
#define XML_EXPR_ATTR_VALUE
Definition: msg_xml.h:347
void crm_time_add_months(crm_time_t *dt, int value)
Definition: iso8601.c:1467
#define CRM_ATTR_UNAME
Definition: crm.h:113
#define crm_trace(fmt, args...)
Definition: logging.h:365
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:3002
const char * op_name
Definition: common.h:189
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:270
Wrappers for and extensions to libxml2.
char * pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
Definition: rules.c:557
void crm_time_add_minutes(crm_time_t *dt, int value)
Definition: iso8601.c:1509
#define XML_EXPR_ATTR_OPERATION
Definition: msg_xml.h:346
gboolean pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:1123
GHashTable * meta
Definition: common.h:179
gboolean pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now, crm_time_t *next_change)
Evaluate any rules contained by given XML element.
Definition: rules.c:39
gboolean pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, pe_match_data_t *match_data)
Definition: rules.c:1230
int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d)
Definition: iso8601.c:358
enum rsc_role_e text2role(const char *role)
Definition: common.c:483
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:952
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:199
pe_rsc_eval_data_t * rsc_data
Definition: common.h:198
int crm_time_compare(const crm_time_t *a, const crm_time_t *b)
Definition: iso8601.c:1392
const char * agent
Definition: common.h:185
gboolean pe_eval_expr(xmlNode *rule, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:638
#define XML_RULE_ATTR_BOOLEAN_OP
Definition: msg_xml.h:339
gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:1213
void populate_hash(xmlNode *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length)
crm_time_t * pe_parse_xml_duration(crm_time_t *start, xmlNode *duration_spec)
Definition: rules.c:284
struct unpack_data_s unpack_data_t
CRM_TRACE_INIT_DATA(pe_rules)
GHashTable * params
Definition: common.h:178
struct sorted_set_s sorted_set_t
const char * standard
Definition: common.h:183
pcmk__action_result_t result
Definition: pcmk_fence.c:35
#define PCMK_XE_DATE_EXPRESSION
Definition: msg_xml.h:342
crm_time_t * now
Definition: common.h:196
#define crm_err(fmt, args...)
Definition: logging.h:359
GHashTable * node_hash
Definition: common.h:194
char guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:271
gboolean pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:1082
gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
Definition: rules.c:1207
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:92
regmatch_t * pmatch
Definition: common.h:173
int compare_version(const char *version1, const char *version2)
Definition: utils.c:189
gboolean pe__eval_rsc_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:1166
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:392
char uname[MAX_NAME]
Definition: cpg.c:50
gboolean pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:936
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
Definition: strings.c:810
Definition: rules.h:26
expression_type
Definition: rules.h:22
#define PCMK_XE_OP_EXPRESSION
Definition: msg_xml.h:343
#define XML_TAG_EXPRESSION
Definition: msg_xml.h:341
#define ID(x)
Definition: msg_xml.h:468
#define PCMK_XE_RSC_EXPRESSION
Definition: msg_xml.h:344
void unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now)
Definition: rules.c:1262
#define pe_err(fmt...)
Definition: internal.h:49
enum expression_type find_expression_type(xmlNode *expr)
Definition: rules.c:105
#define XML_TAG_RULE
Definition: msg_xml.h:335
enum rsc_role_e role
Definition: common.h:195
#define CRM_ATTR_ID
Definition: crm.h:114
int pe_cron_range_satisfied(crm_time_t *now, xmlNode *cron_spec)
Definition: rules.c:238
int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s)
Definition: iso8601.c:292
#define XML_EXPR_ATTR_ATTRIBUTE
Definition: msg_xml.h:345
void crm_time_add_days(crm_time_t *dt, int value)
Definition: iso8601.c:1442
char * string
Definition: common.h:171
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:269
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140