pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
rules.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2023 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU 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(const 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(const xmlNode *cron_spec, const char *xml_field, uint32_t time_field)
173 {
174  int rc = pcmk_rc_undetermined;
175  const char *value = crm_element_value(cron_spec, xml_field);
176  long long low, high;
177 
178  if (value == NULL) {
179  /* Return pe_date_result_undetermined if the field is missing. */
180  goto bail;
181  }
182 
183  if (pcmk__parse_ll_range(value, &low, &high) != pcmk_rc_ok) {
184  goto bail;
185  } else if (low == high) {
186  /* A single number was given, not a range. */
187  if (time_field < low) {
189  } else if (time_field > high) {
190  rc = pcmk_rc_after_range;
191  } else {
193  }
194  } else if (low != -1 && high != -1) {
195  /* This is a range with both bounds. */
196  if (time_field < low) {
198  } else if (time_field > high) {
199  rc = pcmk_rc_after_range;
200  } else {
202  }
203  } else if (low == -1) {
204  /* This is a range with no starting value. */
205  rc = time_field <= high ? pcmk_rc_within_range : pcmk_rc_after_range;
206  } else if (high == -1) {
207  /* This is a range with no ending value. */
208  rc = time_field >= low ? pcmk_rc_within_range : pcmk_rc_before_range;
209  }
210 
211 bail:
212  if (rc == pcmk_rc_within_range) {
213  crm_debug("Condition '%s' in %s: passed", value, xml_field);
214  } else {
215  crm_debug("Condition '%s' in %s: failed", value, xml_field);
216  }
217 
218  return rc;
219 }
220 
221 static gboolean
222 check_passes(int rc) {
223  /* _within_range is obvious. _undetermined is a pass because
224  * this is the return value if a field is not given. In this
225  * case, we just want to ignore it and check other fields to
226  * see if they place some restriction on what can pass.
227  */
228  return rc == pcmk_rc_within_range || rc == pcmk_rc_undetermined;
229 }
230 
231 #define CHECK_ONE(spec, name, var) do { \
232  int subpart_rc = check_one(spec, name, var); \
233  if (check_passes(subpart_rc) == FALSE) { \
234  return subpart_rc; \
235  } \
236 } while (0)
237 
238 int
239 pe_cron_range_satisfied(const crm_time_t *now, const xmlNode *cron_spec)
240 {
241  uint32_t h, m, s, y, d, w;
242 
243  CRM_CHECK(now != NULL, return pcmk_rc_op_unsatisfied);
244 
245  crm_time_get_gregorian(now, &y, &m, &d);
246  CHECK_ONE(cron_spec, "years", y);
247  CHECK_ONE(cron_spec, "months", m);
248  CHECK_ONE(cron_spec, "monthdays", d);
249 
250  crm_time_get_timeofday(now, &h, &m, &s);
251  CHECK_ONE(cron_spec, "hours", h);
252  CHECK_ONE(cron_spec, "minutes", m);
253  CHECK_ONE(cron_spec, "seconds", s);
254 
255  crm_time_get_ordinal(now, &y, &d);
256  CHECK_ONE(cron_spec, "yeardays", d);
257 
258  crm_time_get_isoweek(now, &y, &w, &d);
259  CHECK_ONE(cron_spec, "weekyears", y);
260  CHECK_ONE(cron_spec, "weeks", w);
261  CHECK_ONE(cron_spec, "weekdays", d);
262 
263  CHECK_ONE(cron_spec, "moon", phase_of_the_moon(now));
264  if (crm_element_value(cron_spec, "moon") != NULL) {
265  pcmk__config_warn("Support for 'moon' in date_spec elements "
266  "(such as %s) is deprecated and will be removed "
267  "in a future release of Pacemaker", ID(cron_spec));
268  }
269 
270  /* If we get here, either no fields were specified (which is success), or all
271  * the fields that were specified had their conditions met (which is also a
272  * success). Thus, the result is success.
273  */
274  return pcmk_rc_ok;
275 }
276 
277 static void
278 update_field(crm_time_t *t, const xmlNode *xml, const char *attr,
279  void (*time_fn)(crm_time_t *, int))
280 {
281  long long value;
282 
283  if ((pcmk__scan_ll(crm_element_value(xml, attr), &value, 0LL) == pcmk_rc_ok)
284  && (value != 0LL) && (value >= INT_MIN) && (value <= INT_MAX)) {
285  time_fn(t, (int) value);
286  }
287 }
288 
289 static crm_time_t *
290 parse_xml_duration(const crm_time_t *start, const xmlNode *duration_spec)
291 {
292  crm_time_t *end = pcmk_copy_time(start);
293 
294  update_field(end, duration_spec, "years", crm_time_add_years);
295  update_field(end, duration_spec, "months", crm_time_add_months);
296  update_field(end, duration_spec, "weeks", crm_time_add_weeks);
297  update_field(end, duration_spec, "days", crm_time_add_days);
298  update_field(end, duration_spec, "hours", crm_time_add_hours);
299  update_field(end, duration_spec, "minutes", crm_time_add_minutes);
300  update_field(end, duration_spec, "seconds", crm_time_add_seconds);
301 
302  return end;
303 }
304 
305 // Set next_change to t if t is earlier
306 static void
307 crm_time_set_if_earlier(crm_time_t *next_change, crm_time_t *t)
308 {
309  if ((next_change != NULL) && (t != NULL)) {
310  if (!crm_time_is_defined(next_change)
311  || (crm_time_compare(t, next_change) < 0)) {
312  crm_time_set(next_change, t);
313  }
314  }
315 }
316 
317 // Information about a block of nvpair elements
318 typedef struct sorted_set_s {
319  int score; // This block's score for sorting
320  const char *name; // This block's ID
321  const char *special_name; // ID that should sort first
322  xmlNode *attr_set; // This block
323 } sorted_set_t;
324 
325 static gint
326 sort_pairs(gconstpointer a, gconstpointer b)
327 {
328  const sorted_set_t *pair_a = a;
329  const sorted_set_t *pair_b = b;
330 
331  if (a == NULL && b == NULL) {
332  return 0;
333  } else if (a == NULL) {
334  return 1;
335  } else if (b == NULL) {
336  return -1;
337  }
338 
339  if (pcmk__str_eq(pair_a->name, pair_a->special_name, pcmk__str_casei)) {
340  return -1;
341 
342  } else if (pcmk__str_eq(pair_b->name, pair_a->special_name, pcmk__str_casei)) {
343  return 1;
344  }
345 
346  if (pair_a->score < pair_b->score) {
347  return 1;
348  } else if (pair_a->score > pair_b->score) {
349  return -1;
350  }
351  return 0;
352 }
353 
354 static void
355 populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlNode * top)
356 {
357  const char *name = NULL;
358  const char *value = NULL;
359  const char *old_value = NULL;
360  xmlNode *list = nvpair_list;
361  xmlNode *an_attr = NULL;
362 
363  name = crm_element_name(list->children);
364  if (pcmk__str_eq(XML_TAG_ATTRS, name, pcmk__str_casei)) {
365  list = list->children;
366  }
367 
368  for (an_attr = pcmk__xe_first_child(list); an_attr != NULL;
369  an_attr = pcmk__xe_next(an_attr)) {
370 
371  if (pcmk__str_eq((const char *)an_attr->name, XML_CIB_TAG_NVPAIR, pcmk__str_none)) {
372  xmlNode *ref_nvpair = expand_idref(an_attr, top);
373 
375  if (name == NULL) {
377  }
378 
379  value = crm_element_value(an_attr, XML_NVPAIR_ATTR_VALUE);
380  if (value == NULL) {
381  value = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_VALUE);
382  }
383 
384  if (name == NULL || value == NULL) {
385  continue;
386  }
387 
388  old_value = g_hash_table_lookup(hash, name);
389 
390  if (pcmk__str_eq(value, "#default", pcmk__str_casei)) {
391  if (old_value) {
392  crm_trace("Letting %s default (removing explicit value \"%s\")",
393  name, value);
394  g_hash_table_remove(hash, name);
395  }
396  continue;
397 
398  } else if (old_value == NULL) {
399  crm_trace("Setting %s=\"%s\"", name, value);
400  g_hash_table_insert(hash, strdup(name), strdup(value));
401 
402  } else if (overwrite) {
403  crm_trace("Setting %s=\"%s\" (overwriting old value \"%s\")",
404  name, value, old_value);
405  g_hash_table_replace(hash, strdup(name), strdup(value));
406  }
407  }
408  }
409 }
410 
411 typedef struct unpack_data_s {
412  gboolean overwrite;
413  void *hash;
414  crm_time_t *next_change;
415  const pe_rule_eval_data_t *rule_data;
416  xmlNode *top;
417 } unpack_data_t;
418 
419 static void
420 unpack_attr_set(gpointer data, gpointer user_data)
421 {
422  sorted_set_t *pair = data;
423  unpack_data_t *unpack_data = user_data;
424 
425  if (!pe_eval_rules(pair->attr_set, unpack_data->rule_data,
426  unpack_data->next_change)) {
427  return;
428  }
429 
430  crm_trace("Adding attributes from %s (score %d) %s overwrite",
431  pair->name, pair->score,
432  (unpack_data->overwrite? "with" : "without"));
433  populate_hash(pair->attr_set, unpack_data->hash, unpack_data->overwrite, unpack_data->top);
434 }
435 
447 static GList *
448 make_pairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
449  const char *always_first)
450 {
451  GList *unsorted = NULL;
452 
453  if (xml_obj == NULL) {
454  return NULL;
455  }
456  for (xmlNode *attr_set = pcmk__xe_first_child(xml_obj); attr_set != NULL;
457  attr_set = pcmk__xe_next(attr_set)) {
458 
459  if (pcmk__str_eq(set_name, (const char *) attr_set->name,
461  const char *score = NULL;
462  sorted_set_t *pair = NULL;
463  xmlNode *expanded_attr_set = expand_idref(attr_set, top);
464 
465  if (expanded_attr_set == NULL) {
466  // Schema (if not "none") prevents this
467  continue;
468  }
469 
470  pair = calloc(1, sizeof(sorted_set_t));
471  pair->name = ID(expanded_attr_set);
472  pair->special_name = always_first;
473  pair->attr_set = expanded_attr_set;
474 
475  score = crm_element_value(expanded_attr_set, XML_RULE_ATTR_SCORE);
476  pair->score = char2score(score);
477 
478  unsorted = g_list_prepend(unsorted, pair);
479  }
480  }
481  return g_list_sort(unsorted, sort_pairs);
482 }
483 
496 void
497 pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
498  const pe_rule_eval_data_t *rule_data, GHashTable *hash,
499  const char *always_first, gboolean overwrite,
500  crm_time_t *next_change)
501 {
502  GList *pairs = make_pairs(top, xml_obj, set_name, always_first);
503 
504  if (pairs) {
505  unpack_data_t data = {
506  .hash = hash,
507  .overwrite = overwrite,
508  .next_change = next_change,
509  .top = top,
510  .rule_data = rule_data
511  };
512 
513  g_list_foreach(pairs, unpack_attr_set, &data);
514  g_list_free_full(pairs, free);
515  }
516 }
517 
531 void
532 pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
533  GHashTable *node_hash, GHashTable *hash,
534  const char *always_first, gboolean overwrite,
535  crm_time_t *now, crm_time_t *next_change)
536 {
537  pe_rule_eval_data_t rule_data = {
538  .node_hash = node_hash,
539  .role = RSC_ROLE_UNKNOWN,
540  .now = now,
541  .match_data = NULL,
542  .rsc_data = NULL,
543  .op_data = NULL
544  };
545 
546  pe_eval_nvpairs(top, xml_obj, set_name, &rule_data, hash,
547  always_first, overwrite, next_change);
548 }
549 
559 char *
560 pe_expand_re_matches(const char *string, const pe_re_match_data_t *match_data)
561 {
562  size_t len = 0;
563  int i;
564  const char *p, *last_match_index;
565  char *p_dst, *result = NULL;
566 
567  if (pcmk__str_empty(string) || !match_data) {
568  return NULL;
569  }
570 
571  p = last_match_index = string;
572 
573  while (*p) {
574  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
575  i = *(p + 1) - '0';
576  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
577  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
578  len += p - last_match_index + (match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so);
579  last_match_index = p + 2;
580  }
581  p++;
582  }
583  p++;
584  }
585  len += p - last_match_index + 1;
586 
587  /* FIXME: Excessive? */
588  if (len - 1 <= 0) {
589  return NULL;
590  }
591 
592  p_dst = result = calloc(1, len);
593  p = string;
594 
595  while (*p) {
596  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
597  i = *(p + 1) - '0';
598  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
599  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
600  /* rm_eo can be equal to rm_so, but then there is nothing to do */
601  int match_len = match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so;
602  memcpy(p_dst, match_data->string + match_data->pmatch[i].rm_so, match_len);
603  p_dst += match_len;
604  }
605  p++;
606  } else {
607  *(p_dst) = *(p);
608  p_dst++;
609  }
610  p++;
611  }
612 
613  return result;
614 }
615 
625 gboolean
626 pe_eval_rules(xmlNode *ruleset, const pe_rule_eval_data_t *rule_data,
627  crm_time_t *next_change)
628 {
629  // If there are no rules, pass by default
630  gboolean ruleset_default = TRUE;
631 
632  for (xmlNode *rule = first_named_child(ruleset, XML_TAG_RULE);
633  rule != NULL; rule = crm_next_same_xml(rule)) {
634 
635  ruleset_default = FALSE;
636  if (pe_eval_expr(rule, rule_data, next_change)) {
637  /* Only the deprecated "lifetime" element of location constraints
638  * may contain more than one rule at the top level -- the schema
639  * limits a block of nvpairs to a single top-level rule. So, this
640  * effectively means that a lifetime is active if any rule it
641  * contains is active.
642  */
643  return TRUE;
644  }
645  }
646 
647  return ruleset_default;
648 }
649 
659 gboolean
660 pe_eval_expr(xmlNode *rule, const pe_rule_eval_data_t *rule_data,
661  crm_time_t *next_change)
662 {
663  xmlNode *expr = NULL;
664  gboolean test = TRUE;
665  gboolean empty = TRUE;
666  gboolean passed = TRUE;
667  gboolean do_and = TRUE;
668  const char *value = NULL;
669 
670  rule = expand_idref(rule, NULL);
672  if (pcmk__str_eq(value, "or", pcmk__str_casei)) {
673  do_and = FALSE;
674  passed = FALSE;
675  }
676 
677  crm_trace("Testing rule %s", ID(rule));
678  for (expr = pcmk__xe_first_child(rule); expr != NULL;
679  expr = pcmk__xe_next(expr)) {
680 
681  test = pe_eval_subexpr(expr, rule_data, next_change);
682  empty = FALSE;
683 
684  if (test && do_and == FALSE) {
685  crm_trace("Expression %s/%s passed", ID(rule), ID(expr));
686  return TRUE;
687 
688  } else if (test == FALSE && do_and) {
689  crm_trace("Expression %s/%s failed", ID(rule), ID(expr));
690  return FALSE;
691  }
692  }
693 
694  if (empty) {
695  crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule));
696  }
697 
698  crm_trace("Rule %s %s", ID(rule), passed ? "passed" : "failed");
699  return passed;
700 }
701 
711 gboolean
712 pe_eval_subexpr(xmlNode *expr, const pe_rule_eval_data_t *rule_data,
713  crm_time_t *next_change)
714 {
715  gboolean accept = FALSE;
716  const char *uname = NULL;
717 
718  switch (find_expression_type(expr)) {
719  case nested_rule:
720  accept = pe_eval_expr(expr, rule_data, next_change);
721  break;
722  case attr_expr:
723  case loc_expr:
724  /* these expressions can never succeed if there is
725  * no node to compare with
726  */
727  if (rule_data->node_hash != NULL) {
728  accept = pe__eval_attr_expr(expr, rule_data);
729  }
730  break;
731 
732  case time_expr:
733  switch (pe__eval_date_expr(expr, rule_data, next_change)) {
735  case pcmk_rc_ok:
736  accept = TRUE;
737  break;
738 
739  default:
740  accept = FALSE;
741  break;
742  }
743  break;
744 
745  case role_expr:
746  accept = pe__eval_role_expr(expr, rule_data);
747  break;
748 
749  case rsc_expr:
750  accept = pe__eval_rsc_expr(expr, rule_data);
751  break;
752 
753  case op_expr:
754  accept = pe__eval_op_expr(expr, rule_data);
755  break;
756 
757  default:
758  CRM_CHECK(FALSE /* bad type */ , return FALSE);
759  accept = FALSE;
760  }
761  if (rule_data->node_hash) {
762  uname = g_hash_table_lookup(rule_data->node_hash, CRM_ATTR_UNAME);
763  }
764 
765  crm_trace("Expression %s %s on %s",
766  ID(expr), accept ? "passed" : "failed", uname ? uname : "all nodes");
767  return accept;
768 }
769 
785 static int
786 compare_attr_expr_vals(const char *l_val, const char *r_val, const char *type,
787  const char *op)
788 {
789  int cmp = 0;
790 
791  if (l_val != NULL && r_val != NULL) {
792  if (type == NULL) {
793  if (pcmk__strcase_any_of(op, "lt", "lte", "gt", "gte", NULL)) {
794  if (pcmk__char_in_any_str('.', l_val, r_val, NULL)) {
795  type = "number";
796  } else {
797  type = "integer";
798  }
799 
800  } else {
801  type = "string";
802  }
803  crm_trace("Defaulting to %s based comparison for '%s' op", type, op);
804  }
805 
806  if (pcmk__str_eq(type, "string", pcmk__str_casei)) {
807  cmp = strcasecmp(l_val, r_val);
808 
809  } else if (pcmk__str_eq(type, "integer", pcmk__str_casei)) {
810  long long l_val_num;
811  int rc1 = pcmk__scan_ll(l_val, &l_val_num, 0LL);
812 
813  long long r_val_num;
814  int rc2 = pcmk__scan_ll(r_val, &r_val_num, 0LL);
815 
816  if ((rc1 == pcmk_rc_ok) && (rc2 == pcmk_rc_ok)) {
817  if (l_val_num < r_val_num) {
818  cmp = -1;
819  } else if (l_val_num > r_val_num) {
820  cmp = 1;
821  } else {
822  cmp = 0;
823  }
824 
825  } else {
826  crm_debug("Integer parse error. Comparing %s and %s as strings",
827  l_val, r_val);
828  cmp = compare_attr_expr_vals(l_val, r_val, "string", op);
829  }
830 
831  } else if (pcmk__str_eq(type, "number", pcmk__str_casei)) {
832  double l_val_num;
833  double r_val_num;
834 
835  int rc1 = pcmk__scan_double(l_val, &l_val_num, NULL, NULL);
836  int rc2 = pcmk__scan_double(r_val, &r_val_num, NULL, NULL);
837 
838  if (rc1 == pcmk_rc_ok && rc2 == pcmk_rc_ok) {
839  if (l_val_num < r_val_num) {
840  cmp = -1;
841  } else if (l_val_num > r_val_num) {
842  cmp = 1;
843  } else {
844  cmp = 0;
845  }
846 
847  } else {
848  crm_debug("Floating-point parse error. Comparing %s and %s as "
849  "strings", l_val, r_val);
850  cmp = compare_attr_expr_vals(l_val, r_val, "string", op);
851  }
852 
853  } else if (pcmk__str_eq(type, "version", pcmk__str_casei)) {
854  cmp = compare_version(l_val, r_val);
855 
856  }
857 
858  } else if (l_val == NULL && r_val == NULL) {
859  cmp = 0;
860  } else if (r_val == NULL) {
861  cmp = 1;
862  } else { // l_val == NULL && r_val != NULL
863  cmp = -1;
864  }
865 
866  return cmp;
867 }
868 
883 static bool
884 accept_attr_expr(const char *l_val, const char *r_val, const char *type,
885  const char *op)
886 {
887  int cmp;
888 
889  if (pcmk__str_eq(op, "defined", pcmk__str_casei)) {
890  return (l_val != NULL);
891 
892  } else if (pcmk__str_eq(op, "not_defined", pcmk__str_casei)) {
893  return (l_val == NULL);
894 
895  }
896 
897  cmp = compare_attr_expr_vals(l_val, r_val, type, op);
898 
899  if (pcmk__str_eq(op, "eq", pcmk__str_casei)) {
900  return (cmp == 0);
901 
902  } else if (pcmk__str_eq(op, "ne", pcmk__str_casei)) {
903  return (cmp != 0);
904 
905  } else if (l_val == NULL || r_val == NULL) {
906  // The comparison is meaningless from this point on
907  return false;
908 
909  } else if (pcmk__str_eq(op, "lt", pcmk__str_casei)) {
910  return (cmp < 0);
911 
912  } else if (pcmk__str_eq(op, "lte", pcmk__str_casei)) {
913  return (cmp <= 0);
914 
915  } else if (pcmk__str_eq(op, "gt", pcmk__str_casei)) {
916  return (cmp > 0);
917 
918  } else if (pcmk__str_eq(op, "gte", pcmk__str_casei)) {
919  return (cmp >= 0);
920  }
921 
922  return false; // Should never reach this point
923 }
924 
933 static const char *
934 expand_value_source(const char *value, const char *value_source,
935  const pe_match_data_t *match_data)
936 {
937  GHashTable *table = NULL;
938 
939  if (pcmk__str_empty(value)) {
940  return NULL; // value_source is irrelevant
941 
942  } else if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
943  table = match_data->params;
944 
945  } else if (pcmk__str_eq(value_source, "meta", pcmk__str_casei)) {
946  table = match_data->meta;
947 
948  } else { // literal
949  return value;
950  }
951 
952  if (table == NULL) {
953  return NULL;
954  }
955  return (const char *) g_hash_table_lookup(table, value);
956 }
957 
968 gboolean
969 pe__eval_attr_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
970 {
971  gboolean attr_allocated = FALSE;
972  const char *h_val = NULL;
973 
974  const char *op = NULL;
975  const char *type = NULL;
976  const char *attr = NULL;
977  const char *value = NULL;
978  const char *value_source = NULL;
979 
982  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
984  value_source = crm_element_value(expr, XML_EXPR_ATTR_VALUE_SOURCE);
985 
986  if (attr == NULL) {
987  pe_err("Expression %s invalid: " XML_EXPR_ATTR_ATTRIBUTE
988  " not specified", pcmk__s(ID(expr), "without ID"));
989  return FALSE;
990  } else if (op == NULL) {
991  pe_err("Expression %s invalid: " XML_EXPR_ATTR_OPERATION
992  " not specified", pcmk__s(ID(expr), "without ID"));
993  }
994 
995  if (rule_data->match_data != NULL) {
996  // Expand any regular expression submatches (%0-%9) in attribute name
997  if (rule_data->match_data->re != NULL) {
998  char *resolved_attr = pe_expand_re_matches(attr, rule_data->match_data->re);
999 
1000  if (resolved_attr != NULL) {
1001  attr = (const char *) resolved_attr;
1002  attr_allocated = TRUE;
1003  }
1004  }
1005 
1006  // Get value appropriate to value-source
1007  value = expand_value_source(value, value_source, rule_data->match_data);
1008  }
1009 
1010  if (rule_data->node_hash != NULL) {
1011  h_val = (const char *)g_hash_table_lookup(rule_data->node_hash, attr);
1012  }
1013 
1014  if (attr_allocated) {
1015  free((char *)attr);
1016  attr = NULL;
1017  }
1018 
1019  return accept_attr_expr(h_val, value, type, op);
1020 }
1021 
1032 int
1033 pe__eval_date_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data,
1034  crm_time_t *next_change)
1035 {
1036  crm_time_t *start = NULL;
1037  crm_time_t *end = NULL;
1038  const char *value = NULL;
1039  const char *op = crm_element_value(expr, "operation");
1040 
1041  xmlNode *duration_spec = NULL;
1042  xmlNode *date_spec = NULL;
1043 
1044  // "undetermined" will also be returned for parsing errors
1045  int rc = pcmk_rc_undetermined;
1046 
1047  crm_trace("Testing expression: %s", ID(expr));
1048 
1049  duration_spec = first_named_child(expr, "duration");
1050  date_spec = first_named_child(expr, "date_spec");
1051 
1052  value = crm_element_value(expr, "start");
1053  if (value != NULL) {
1054  start = crm_time_new(value);
1055  }
1056  value = crm_element_value(expr, "end");
1057  if (value != NULL) {
1058  end = crm_time_new(value);
1059  }
1060 
1061  if (start != NULL && end == NULL && duration_spec != NULL) {
1062  end = parse_xml_duration(start, duration_spec);
1063  }
1064 
1065  if (pcmk__str_eq(op, "in_range", pcmk__str_null_matches | pcmk__str_casei)) {
1066  if ((start == NULL) && (end == NULL)) {
1067  // in_range requires at least one of start or end
1068  } else if ((start != NULL) && (crm_time_compare(rule_data->now, start) < 0)) {
1069  rc = pcmk_rc_before_range;
1070  crm_time_set_if_earlier(next_change, start);
1071  } else if ((end != NULL) && (crm_time_compare(rule_data->now, end) > 0)) {
1072  rc = pcmk_rc_after_range;
1073  } else {
1074  rc = pcmk_rc_within_range;
1075  if (end && next_change) {
1076  // Evaluation doesn't change until second after end
1077  crm_time_add_seconds(end, 1);
1078  crm_time_set_if_earlier(next_change, end);
1079  }
1080  }
1081 
1082  } else if (pcmk__str_eq(op, "date_spec", pcmk__str_casei)) {
1083  rc = pe_cron_range_satisfied(rule_data->now, date_spec);
1084  // @TODO set next_change appropriately
1085 
1086  } else if (pcmk__str_eq(op, "gt", pcmk__str_casei)) {
1087  if (start == NULL) {
1088  // gt requires start
1089  } else if (crm_time_compare(rule_data->now, start) > 0) {
1090  rc = pcmk_rc_within_range;
1091  } else {
1092  rc = pcmk_rc_before_range;
1093 
1094  // Evaluation doesn't change until second after start
1095  crm_time_add_seconds(start, 1);
1096  crm_time_set_if_earlier(next_change, start);
1097  }
1098 
1099  } else if (pcmk__str_eq(op, "lt", pcmk__str_casei)) {
1100  if (end == NULL) {
1101  // lt requires end
1102  } else if (crm_time_compare(rule_data->now, end) < 0) {
1103  rc = pcmk_rc_within_range;
1104  crm_time_set_if_earlier(next_change, end);
1105  } else {
1106  rc = pcmk_rc_after_range;
1107  }
1108  }
1109 
1110  crm_time_free(start);
1111  crm_time_free(end);
1112  return rc;
1113 }
1114 
1115 gboolean
1116 pe__eval_op_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
1117 {
1118  const char *name = crm_element_value(expr, XML_NVPAIR_ATTR_NAME);
1119  const char *interval_s = crm_element_value(expr, XML_LRM_ATTR_INTERVAL);
1120  guint interval;
1121 
1122  crm_trace("Testing op_defaults expression: %s", ID(expr));
1123 
1124  if (rule_data->op_data == NULL) {
1125  crm_trace("No operations data provided");
1126  return FALSE;
1127  }
1128 
1129  interval = crm_parse_interval_spec(interval_s);
1130  if (interval == 0 && errno != 0) {
1131  crm_trace("Could not parse interval: %s", interval_s);
1132  return FALSE;
1133  }
1134 
1135  if (interval_s != NULL && interval != rule_data->op_data->interval) {
1136  crm_trace("Interval doesn't match: %d != %d", interval, rule_data->op_data->interval);
1137  return FALSE;
1138  }
1139 
1140  if (!pcmk__str_eq(name, rule_data->op_data->op_name, pcmk__str_none)) {
1141  crm_trace("Name doesn't match: %s != %s", name, rule_data->op_data->op_name);
1142  return FALSE;
1143  }
1144 
1145  return TRUE;
1146 }
1147 
1157 gboolean
1158 pe__eval_role_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
1159 {
1160  gboolean accept = FALSE;
1161  const char *op = NULL;
1162  const char *value = NULL;
1163 
1164  if (rule_data->role == RSC_ROLE_UNKNOWN) {
1165  return accept;
1166  }
1167 
1168  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
1170 
1171  if (pcmk__str_eq(op, "defined", pcmk__str_casei)) {
1172  if (rule_data->role > RSC_ROLE_STARTED) {
1173  accept = TRUE;
1174  }
1175 
1176  } else if (pcmk__str_eq(op, "not_defined", pcmk__str_casei)) {
1177  if ((rule_data->role > RSC_ROLE_UNKNOWN)
1178  && (rule_data->role < RSC_ROLE_UNPROMOTED)) {
1179  accept = TRUE;
1180  }
1181 
1182  } else if (pcmk__str_eq(op, "eq", pcmk__str_casei)) {
1183  if (text2role(value) == rule_data->role) {
1184  accept = TRUE;
1185  }
1186 
1187  } else if (pcmk__str_eq(op, "ne", pcmk__str_casei)) {
1188  // Test "ne" only with promotable clone roles
1189  if ((rule_data->role > RSC_ROLE_UNKNOWN)
1190  && (rule_data->role < RSC_ROLE_UNPROMOTED)) {
1191  accept = FALSE;
1192 
1193  } else if (text2role(value) != rule_data->role) {
1194  accept = TRUE;
1195  }
1196  }
1197  return accept;
1198 }
1199 
1200 gboolean
1201 pe__eval_rsc_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
1202 {
1203  const char *class = crm_element_value(expr, XML_AGENT_ATTR_CLASS);
1204  const char *provider = crm_element_value(expr, XML_AGENT_ATTR_PROVIDER);
1205  const char *type = crm_element_value(expr, XML_EXPR_ATTR_TYPE);
1206 
1207  crm_trace("Testing rsc_defaults expression: %s", ID(expr));
1208 
1209  if (rule_data->rsc_data == NULL) {
1210  crm_trace("No resource data provided");
1211  return FALSE;
1212  }
1213 
1214  if (class != NULL &&
1215  !pcmk__str_eq(class, rule_data->rsc_data->standard, pcmk__str_none)) {
1216  crm_trace("Class doesn't match: %s != %s", class, rule_data->rsc_data->standard);
1217  return FALSE;
1218  }
1219 
1220  if ((provider == NULL && rule_data->rsc_data->provider != NULL) ||
1221  (provider != NULL && rule_data->rsc_data->provider == NULL) ||
1222  !pcmk__str_eq(provider, rule_data->rsc_data->provider, pcmk__str_none)) {
1223  crm_trace("Provider doesn't match: %s != %s", provider, rule_data->rsc_data->provider);
1224  return FALSE;
1225  }
1226 
1227  if (type != NULL &&
1228  !pcmk__str_eq(type, rule_data->rsc_data->agent, pcmk__str_none)) {
1229  crm_trace("Agent doesn't match: %s != %s", type, rule_data->rsc_data->agent);
1230  return FALSE;
1231  }
1232 
1233  return TRUE;
1234 }
1235 
1236 // Deprecated functions kept only for backward API compatibility
1237 // LCOV_EXCL_START
1238 
1239 #include <crm/pengine/rules_compat.h>
1240 
1241 gboolean
1242 test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
1243 {
1244  return pe_evaluate_rules(ruleset, node_hash, now, NULL);
1245 }
1246 
1247 gboolean
1248 test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
1249 {
1250  return pe_test_rule(rule, node_hash, role, now, NULL, NULL);
1251 }
1252 
1253 gboolean
1254 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)
1255 {
1256  pe_match_data_t match_data = {
1257  .re = re_match_data,
1258  .params = NULL,
1259  .meta = NULL,
1260  };
1261  return pe_test_rule(rule, node_hash, role, now, NULL, &match_data);
1262 }
1263 
1264 gboolean
1265 pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
1266  crm_time_t *now, pe_match_data_t *match_data)
1267 {
1268  return pe_test_rule(rule, node_hash, role, now, NULL, match_data);
1269 }
1270 
1271 gboolean
1272 test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
1273 {
1274  return pe_test_expression(expr, node_hash, role, now, NULL, NULL);
1275 }
1276 
1277 gboolean
1278 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)
1279 {
1280  pe_match_data_t match_data = {
1281  .re = re_match_data,
1282  .params = NULL,
1283  .meta = NULL,
1284  };
1285  return pe_test_expression(expr, node_hash, role, now, NULL, &match_data);
1286 }
1287 
1288 gboolean
1289 pe_test_expression_full(xmlNode *expr, GHashTable *node_hash,
1290  enum rsc_role_e role, crm_time_t *now,
1291  pe_match_data_t *match_data)
1292 {
1293  return pe_test_expression(expr, node_hash, role, now, NULL, match_data);
1294 }
1295 
1296 void
1297 unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name,
1298  GHashTable *node_hash, GHashTable *hash,
1299  const char *always_first, gboolean overwrite,
1300  crm_time_t *now)
1301 {
1302  pe_rule_eval_data_t rule_data = {
1303  .node_hash = node_hash,
1304  .role = RSC_ROLE_UNKNOWN,
1305  .now = now,
1306  .match_data = NULL,
1307  .rsc_data = NULL,
1308  .op_data = NULL
1309  };
1310 
1311  pe_eval_nvpairs(top, xml_obj, set_name, &rule_data, hash, always_first,
1312  overwrite, NULL);
1313 }
1314 
1315 // LCOV_EXCL_STOP
1316 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
int pe__eval_date_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:1033
void pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, const pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition: rules.c:497
A dumping ground.
void crm_time_add_years(crm_time_t *dt, int value)
Definition: iso8601.c:1654
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:1254
const char * provider
Definition: common.h:183
int crm_time_get_isoweek(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d)
Definition: iso8601.c:406
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:1548
char data[0]
Definition: cpg.c:55
bool pcmk__char_in_any_str(int ch,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:980
#define CRM_ATTR_KIND
Definition: crm.h:115
#define XML_EXPR_ATTR_TYPE
Definition: msg_xml.h:360
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:142
const char * name
Definition: cib.c:24
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:933
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define pcmk__config_warn(fmt...)
gboolean test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:1272
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:351
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2521
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:1374
pe_re_match_data_t * re
Definition: common.h:176
#define XML_TAG_ATTRS
Definition: msg_xml.h:224
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:1278
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:309
#define CRM_ATTR_ROLE
Definition: crm.h:116
#define XML_EXPR_ATTR_VALUE_SOURCE
Definition: msg_xml.h:361
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:403
#define CHECK_ONE(spec, name, var)
Definition: rules.c:231
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:219
Definition: rules.h:34
int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d)
Definition: iso8601.c:398
void crm_time_add_hours(crm_time_t *dt, int value)
Definition: iso8601.c:1642
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:1289
guint interval
Definition: common.h:189
pe_match_data_t * match_data
Definition: common.h:196
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:198
void pe_unpack_nvpairs(xmlNode *top, const 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:532
Definition: rules.h:23
#define crm_debug(fmt, args...)
Definition: logging.h:382
void crm_time_set(crm_time_t *target, const crm_time_t *source)
Definition: iso8601.c:1305
void crm_time_add_weeks(crm_time_t *dt, int value)
Definition: iso8601.c:1648
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
#define XML_EXPR_ATTR_VALUE
Definition: msg_xml.h:359
void crm_time_add_months(crm_time_t *dt, int value)
Definition: iso8601.c:1593
#define CRM_ATTR_UNAME
Definition: crm.h:113
#define crm_trace(fmt, args...)
Definition: logging.h:383
gboolean pe__eval_attr_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
Definition: rules.c:969
gboolean pe_eval_subexpr(xmlNode *expr, const pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Evaluate a single rule expression, including any subexpressions.
Definition: rules.c:712
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:2593
gboolean pe_eval_expr(xmlNode *rule, const pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Evaluate all of a rule&#39;s expressions.
Definition: rules.c:660
const char * op_name
Definition: common.h:188
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:283
Wrappers for and extensions to libxml2.
int pe_cron_range_satisfied(const crm_time_t *now, const xmlNode *cron_spec)
Definition: rules.c:239
void crm_time_add_minutes(crm_time_t *dt, int value)
Definition: iso8601.c:1636
#define XML_EXPR_ATTR_OPERATION
Definition: msg_xml.h:358
GHashTable * meta
Definition: common.h:178
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:1265
int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d)
Definition: iso8601.c:365
enum rsc_role_e text2role(const char *role)
Definition: common.c:479
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:957
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:197
int crm_time_compare(const crm_time_t *a, const crm_time_t *b)
Definition: iso8601.c:1518
const char * agent
Definition: common.h:184
#define XML_RULE_ATTR_BOOLEAN_OP
Definition: msg_xml.h:354
gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:1248
void populate_hash(xmlNode *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length)
struct unpack_data_s unpack_data_t
CRM_TRACE_INIT_DATA(pe_rules)
GHashTable * params
Definition: common.h:177
struct sorted_set_s sorted_set_t
const char * standard
Definition: common.h:182
pcmk__action_result_t result
Definition: pcmk_fence.c:35
#define PCMK_XE_DATE_EXPRESSION
Definition: msg_xml.h:36
crm_time_t * now
Definition: common.h:195
#define crm_err(fmt, args...)
Definition: logging.h:377
GHashTable * node_hash
Definition: common.h:193
char guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:271
gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
Definition: rules.c:1242
gboolean pe__eval_op_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
Definition: rules.c:1116
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:109
regmatch_t * pmatch
Definition: common.h:172
int compare_version(const char *version1, const char *version2)
Definition: utils.c:189
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:404
char uname[MAX_NAME]
Definition: cpg.c:50
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
gboolean pe_eval_rules(xmlNode *ruleset, const pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Evaluate rules.
Definition: rules.c:626
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
Definition: strings.c:810
Definition: rules.h:26
gboolean pe__eval_role_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
Definition: rules.c:1158
expression_type
Definition: rules.h:22
#define PCMK_XE_OP_EXPRESSION
Definition: msg_xml.h:37
#define XML_TAG_EXPRESSION
Definition: msg_xml.h:356
gboolean pe__eval_rsc_expr(const xmlNode *expr, const pe_rule_eval_data_t *rule_data)
Definition: rules.c:1201
#define ID(x)
Definition: msg_xml.h:480
#define PCMK_XE_RSC_EXPRESSION
Definition: msg_xml.h:44
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:1297
#define pe_err(fmt...)
Definition: internal.h:52
enum expression_type find_expression_type(xmlNode *expr)
Definition: rules.c:105
#define XML_TAG_RULE
Definition: msg_xml.h:350
enum rsc_role_e role
Definition: common.h:194
#define CRM_ATTR_ID
Definition: crm.h:114
int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s)
Definition: iso8601.c:299
char * pe_expand_re_matches(const char *string, const pe_re_match_data_t *match_data)
Expand any regular expression submatches (%0-%9) in a string.
Definition: rules.c:560
#define XML_EXPR_ATTR_ATTRIBUTE
Definition: msg_xml.h:357
void crm_time_add_days(crm_time_t *dt, int value)
Definition: iso8601.c:1568
char * string
Definition: common.h:170
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:282
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2547
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150