pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
rules.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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, "date_expression", pcmk__str_casei)) {
114  return time_expr;
115 
116  } else if (pcmk__str_eq(tag, "rsc_expression", pcmk__str_casei)) {
117  return rsc_expr;
118 
119  } else if (pcmk__str_eq(tag, "op_expression", pcmk__str_casei)) {
120  return op_expr;
121 
122  } else if (pcmk__str_eq(tag, XML_TAG_RULE, pcmk__str_casei)) {
123  return nested_rule;
124 
125  } else if (!pcmk__str_eq(tag, "expression", pcmk__str_casei)) {
126  return not_expr;
127 
128  } else if (pcmk__strcase_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_casei)) {
132  return role_expr;
133 
134 #if ENABLE_VERSIONED_ATTRS
135  } else if (pcmk__str_eq(attr, CRM_ATTR_RA_VERSION, pcmk__str_casei)) {
136  return version_expr;
137 #endif
138  }
139 
140  return attr_expr;
141 }
142 
143 gboolean
144 pe_test_role_expression(xmlNode *expr, enum rsc_role_e role, crm_time_t *now)
145 {
146  pe_rule_eval_data_t rule_data = {
147  .node_hash = NULL,
148  .role = role,
149  .now = now,
150  .match_data = NULL,
151  .rsc_data = NULL,
152  .op_data = NULL
153  };
154 
155  return pe__eval_role_expr(expr, &rule_data);
156 }
157 
158 gboolean
159 pe_test_attr_expression(xmlNode *expr, GHashTable *hash, crm_time_t *now,
160  pe_match_data_t *match_data)
161 {
162  pe_rule_eval_data_t rule_data = {
163  .node_hash = hash,
164  .role = RSC_ROLE_UNKNOWN,
165  .now = now,
166  .match_data = match_data,
167  .rsc_data = NULL,
168  .op_data = NULL
169  };
170 
171  return pe__eval_attr_expr(expr, &rule_data);
172 }
173 
174 /* As per the nethack rules:
175  *
176  * moon period = 29.53058 days ~= 30, year = 365.2422 days
177  * days moon phase advances on first day of year compared to preceding year
178  * = 365.2422 - 12*29.53058 ~= 11
179  * years in Metonic cycle (time until same phases fall on the same days of
180  * the month) = 18.6 ~= 19
181  * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
182  * (29 as initial condition)
183  * current phase in days = first day phase + days elapsed in year
184  * 6 moons ~= 177 days
185  * 177 ~= 8 reported phases * 22
186  * + 11/22 for rounding
187  *
188  * 0-7, with 0: new, 4: full
189  */
190 
191 static int
192 phase_of_the_moon(crm_time_t * now)
193 {
194  uint32_t epact, diy, goldn;
195  uint32_t y;
196 
197  crm_time_get_ordinal(now, &y, &diy);
198 
199  goldn = (y % 19) + 1;
200  epact = (11 * goldn + 18) % 30;
201  if ((epact == 25 && goldn > 11) || epact == 24)
202  epact++;
203 
204  return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
205 }
206 
207 static int
208 check_one(xmlNode *cron_spec, const char *xml_field, uint32_t time_field) {
209  int rc = pcmk_rc_undetermined;
210  const char *value = crm_element_value(cron_spec, xml_field);
211  long long low, high;
212 
213  if (value == NULL) {
214  /* Return pe_date_result_undetermined if the field is missing. */
215  goto bail;
216  }
217 
218  if (pcmk__parse_ll_range(value, &low, &high) == pcmk_rc_unknown_format) {
219  goto bail;
220  } else if (low == high) {
221  /* A single number was given, not a range. */
222  if (time_field < low) {
224  } else if (time_field > high) {
226  } else {
228  }
229  } else if (low != -1 && high != -1) {
230  /* This is a range with both bounds. */
231  if (time_field < low) {
233  } else if (time_field > high) {
235  } else {
237  }
238  } else if (low == -1) {
239  /* This is a range with no starting value. */
240  rc = time_field <= high ? pcmk_rc_within_range : pcmk_rc_after_range;
241  } else if (high == -1) {
242  /* This is a range with no ending value. */
243  rc = time_field >= low ? pcmk_rc_within_range : pcmk_rc_before_range;
244  }
245 
246 bail:
247  if (rc == pcmk_rc_within_range) {
248  crm_debug("Condition '%s' in %s: passed", value, xml_field);
249  } else {
250  crm_debug("Condition '%s' in %s: failed", value, xml_field);
251  }
252 
253  return rc;
254 }
255 
256 static gboolean
257 check_passes(int rc) {
258  /* _within_range is obvious. _undetermined is a pass because
259  * this is the return value if a field is not given. In this
260  * case, we just want to ignore it and check other fields to
261  * see if they place some restriction on what can pass.
262  */
264 }
265 
266 #define CHECK_ONE(spec, name, var) do { \
267  int subpart_rc = check_one(spec, name, var); \
268  if (check_passes(subpart_rc) == FALSE) { \
269  return subpart_rc; \
270  } \
271 } while (0)
272 
273 int
274 pe_cron_range_satisfied(crm_time_t * now, xmlNode * cron_spec)
275 {
276  uint32_t h, m, s, y, d, w;
277 
278  CRM_CHECK(now != NULL, return pcmk_rc_op_unsatisfied);
279 
280  crm_time_get_gregorian(now, &y, &m, &d);
281  CHECK_ONE(cron_spec, "years", y);
282  CHECK_ONE(cron_spec, "months", m);
283  CHECK_ONE(cron_spec, "monthdays", d);
284 
285  crm_time_get_timeofday(now, &h, &m, &s);
286  CHECK_ONE(cron_spec, "hours", h);
287  CHECK_ONE(cron_spec, "minutes", m);
288  CHECK_ONE(cron_spec, "seconds", s);
289 
290  crm_time_get_ordinal(now, &y, &d);
291  CHECK_ONE(cron_spec, "yeardays", d);
292 
293  crm_time_get_isoweek(now, &y, &w, &d);
294  CHECK_ONE(cron_spec, "weekyears", y);
295  CHECK_ONE(cron_spec, "weeks", w);
296  CHECK_ONE(cron_spec, "weekdays", d);
297 
298  CHECK_ONE(cron_spec, "moon", phase_of_the_moon(now));
299 
300  /* If we get here, either no fields were specified (which is success), or all
301  * the fields that were specified had their conditions met (which is also a
302  * success). Thus, the result is success.
303  */
304  return pcmk_rc_ok;
305 }
306 
307 #define update_field(xml_field, time_fn) \
308  value = crm_element_value(duration_spec, xml_field); \
309  if(value != NULL) { \
310  int value_i = crm_parse_int(value, "0"); \
311  time_fn(end, value_i); \
312  }
313 
314 crm_time_t *
315 pe_parse_xml_duration(crm_time_t * start, xmlNode * duration_spec)
316 {
317  crm_time_t *end = NULL;
318  const char *value = NULL;
319 
320  end = crm_time_new(NULL);
321  crm_time_set(end, start);
322 
330 
331  return end;
332 }
333 
344 gboolean
345 pe_test_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change)
346 {
347  pe_rule_eval_data_t rule_data = {
348  .node_hash = NULL,
349  .role = RSC_ROLE_UNKNOWN,
350  .now = now,
351  .match_data = NULL,
352  .rsc_data = NULL,
353  .op_data = NULL
354  };
355 
356  switch (pe__eval_date_expr(expr, &rule_data, next_change)) {
358  case pcmk_rc_ok:
359  return TRUE;
360 
361  default:
362  return FALSE;
363  }
364 }
365 
366 // Set next_change to t if t is earlier
367 static void
368 crm_time_set_if_earlier(crm_time_t *next_change, crm_time_t *t)
369 {
370  if ((next_change != NULL) && (t != NULL)) {
371  if (!crm_time_is_defined(next_change)
372  || (crm_time_compare(t, next_change) < 0)) {
373  crm_time_set(next_change, t);
374  }
375  }
376 }
377 
388 int
389 pe_eval_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change)
390 {
391  pe_rule_eval_data_t rule_data = {
392  .node_hash = NULL,
393  .role = RSC_ROLE_UNKNOWN,
394  .now = now,
395  .match_data = NULL,
396  .rsc_data = NULL,
397  .op_data = NULL
398  };
399 
400  return pe__eval_date_expr(expr, &rule_data, next_change);
401 }
402 
403 // Information about a block of nvpair elements
404 typedef struct sorted_set_s {
405  int score; // This block's score for sorting
406  const char *name; // This block's ID
407  const char *special_name; // ID that should sort first
408  xmlNode *attr_set; // This block
409 } sorted_set_t;
410 
411 static gint
412 sort_pairs(gconstpointer a, gconstpointer b)
413 {
414  const sorted_set_t *pair_a = a;
415  const sorted_set_t *pair_b = b;
416 
417  if (a == NULL && b == NULL) {
418  return 0;
419  } else if (a == NULL) {
420  return 1;
421  } else if (b == NULL) {
422  return -1;
423  }
424 
425  if (pcmk__str_eq(pair_a->name, pair_a->special_name, pcmk__str_casei)) {
426  return -1;
427 
428  } else if (pcmk__str_eq(pair_b->name, pair_a->special_name, pcmk__str_casei)) {
429  return 1;
430  }
431 
432  if (pair_a->score < pair_b->score) {
433  return 1;
434  } else if (pair_a->score > pair_b->score) {
435  return -1;
436  }
437  return 0;
438 }
439 
440 static void
441 populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlNode * top)
442 {
443  const char *name = NULL;
444  const char *value = NULL;
445  const char *old_value = NULL;
446  xmlNode *list = nvpair_list;
447  xmlNode *an_attr = NULL;
448 
449  name = crm_element_name(list->children);
450  if (pcmk__str_eq(XML_TAG_ATTRS, name, pcmk__str_casei)) {
451  list = list->children;
452  }
453 
454  for (an_attr = pcmk__xe_first_child(list); an_attr != NULL;
455  an_attr = pcmk__xe_next(an_attr)) {
456 
457  if (pcmk__str_eq((const char *)an_attr->name, XML_CIB_TAG_NVPAIR, pcmk__str_none)) {
458  xmlNode *ref_nvpair = expand_idref(an_attr, top);
459 
461  if (name == NULL) {
463  }
464 
465  value = crm_element_value(an_attr, XML_NVPAIR_ATTR_VALUE);
466  if (value == NULL) {
467  value = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_VALUE);
468  }
469 
470  if (name == NULL || value == NULL) {
471  continue;
472  }
473 
474  old_value = g_hash_table_lookup(hash, name);
475 
476  if (pcmk__str_eq(value, "#default", pcmk__str_casei)) {
477  if (old_value) {
478  crm_trace("Letting %s default (removing explicit value \"%s\")",
479  name, value);
480  g_hash_table_remove(hash, name);
481  }
482  continue;
483 
484  } else if (old_value == NULL) {
485  crm_trace("Setting %s=\"%s\"", name, value);
486  g_hash_table_insert(hash, strdup(name), strdup(value));
487 
488  } else if (overwrite) {
489  crm_trace("Setting %s=\"%s\" (overwriting old value \"%s\")",
490  name, value, old_value);
491  g_hash_table_replace(hash, strdup(name), strdup(value));
492  }
493  }
494  }
495 }
496 
497 #if ENABLE_VERSIONED_ATTRS
498 static xmlNode*
499 get_versioned_rule(xmlNode * attr_set)
500 {
501  xmlNode * rule = NULL;
502  xmlNode * expr = NULL;
503 
504  for (rule = pcmk__xe_first_child(attr_set); rule != NULL;
505  rule = pcmk__xe_next(rule)) {
506 
507  if (pcmk__str_eq((const char *)rule->name, XML_TAG_RULE,
508  pcmk__str_none)) {
509  for (expr = pcmk__xe_first_child(rule); expr != NULL;
510  expr = pcmk__xe_next(expr)) {
511 
512  if (find_expression_type(expr) == version_expr) {
513  return rule;
514  }
515  }
516  }
517  }
518 
519  return NULL;
520 }
521 
522 static void
523 add_versioned_attributes(xmlNode * attr_set, xmlNode * versioned_attrs)
524 {
525  xmlNode *attr_set_copy = NULL;
526  xmlNode *rule = NULL;
527  xmlNode *expr = NULL;
528 
529  if (!attr_set || !versioned_attrs) {
530  return;
531  }
532 
533  attr_set_copy = copy_xml(attr_set);
534 
535  rule = get_versioned_rule(attr_set_copy);
536  if (!rule) {
537  free_xml(attr_set_copy);
538  return;
539  }
540 
541  expr = pcmk__xe_first_child(rule);
542  while (expr != NULL) {
543  if (find_expression_type(expr) != version_expr) {
544  xmlNode *node = expr;
545 
546  expr = pcmk__xe_next(expr);
547  free_xml(node);
548  } else {
549  expr = pcmk__xe_next(expr);
550  }
551  }
552 
553  add_node_nocopy(versioned_attrs, NULL, attr_set_copy);
554 }
555 #endif
556 
557 typedef struct unpack_data_s {
558  gboolean overwrite;
559  void *hash;
560  crm_time_t *next_change;
561  pe_rule_eval_data_t *rule_data;
562  xmlNode *top;
563 } unpack_data_t;
564 
565 static void
566 unpack_attr_set(gpointer data, gpointer user_data)
567 {
568  sorted_set_t *pair = data;
569  unpack_data_t *unpack_data = user_data;
570 
571  if (!pe_eval_rules(pair->attr_set, unpack_data->rule_data,
572  unpack_data->next_change)) {
573  return;
574  }
575 
576 #if ENABLE_VERSIONED_ATTRS
577  if (get_versioned_rule(pair->attr_set) && !(unpack_data->rule_data->node_hash &&
578  g_hash_table_lookup_extended(unpack_data->rule_data->node_hash,
579  CRM_ATTR_RA_VERSION, NULL, NULL))) {
580  // we haven't actually tested versioned expressions yet
581  return;
582  }
583 #endif
584 
585  crm_trace("Adding attributes from %s (score %d) %s overwrite",
586  pair->name, pair->score,
587  (unpack_data->overwrite? "with" : "without"));
588  populate_hash(pair->attr_set, unpack_data->hash, unpack_data->overwrite, unpack_data->top);
589 }
590 
591 #if ENABLE_VERSIONED_ATTRS
592 static void
593 unpack_versioned_attr_set(gpointer data, gpointer user_data)
594 {
595  sorted_set_t *pair = data;
596  unpack_data_t *unpack_data = user_data;
597 
598  if (pe_eval_rules(pair->attr_set, unpack_data->rule_data,
599  unpack_data->next_change)) {
600  add_versioned_attributes(pair->attr_set, unpack_data->hash);
601  }
602 }
603 #endif
604 
616 static GList *
617 make_pairs(xmlNode *top, xmlNode *xml_obj, const char *set_name,
618  const char *always_first)
619 {
620  GListPtr unsorted = NULL;
621  const char *score = NULL;
622  sorted_set_t *pair = NULL;
623  xmlNode *attr_set = NULL;
624 
625  if (xml_obj == NULL) {
626  return NULL;
627  }
628  for (attr_set = pcmk__xe_first_child(xml_obj); attr_set != NULL;
629  attr_set = pcmk__xe_next(attr_set)) {
630 
631  /* Uncertain if set_name == NULL check is strictly necessary here */
632  if (pcmk__str_eq(set_name, (const char *)attr_set->name, pcmk__str_null_matches)) {
633  pair = NULL;
634  attr_set = expand_idref(attr_set, top);
635  if (attr_set == NULL) {
636  continue;
637  }
638 
639  pair = calloc(1, sizeof(sorted_set_t));
640  pair->name = ID(attr_set);
641  pair->special_name = always_first;
642  pair->attr_set = attr_set;
643 
644  score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE);
645  pair->score = char2score(score);
646 
647  unsorted = g_list_prepend(unsorted, pair);
648  }
649  }
650  return g_list_sort(unsorted, sort_pairs);
651 }
652 
667 static void
668 unpack_nvpair_blocks(xmlNode *top, xmlNode *xml_obj, const char *set_name,
669  void *hash, const char *always_first, gboolean overwrite,
670  pe_rule_eval_data_t *rule_data, crm_time_t *next_change,
671  GFunc unpack_func)
672 {
673  GList *pairs = make_pairs(top, xml_obj, set_name, always_first);
674 
675  if (pairs) {
676  unpack_data_t data = {
677  .hash = hash,
678  .overwrite = overwrite,
679  .next_change = next_change,
680  .top = top,
681  .rule_data = rule_data
682  };
683 
684  g_list_foreach(pairs, unpack_func, &data);
685  g_list_free_full(pairs, free);
686  }
687 }
688 
689 void
690 pe_eval_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name,
691  pe_rule_eval_data_t *rule_data, GHashTable *hash,
692  const char *always_first, gboolean overwrite,
693  crm_time_t *next_change)
694 {
695  unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first,
696  overwrite, rule_data, next_change, unpack_attr_set);
697 }
698 
712 void
713 pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name,
714  GHashTable *node_hash, GHashTable *hash,
715  const char *always_first, gboolean overwrite,
716  crm_time_t *now, crm_time_t *next_change)
717 {
718  pe_rule_eval_data_t rule_data = {
719  .node_hash = node_hash,
720  .role = RSC_ROLE_UNKNOWN,
721  .now = now,
722  .match_data = NULL,
723  .rsc_data = NULL,
724  .op_data = NULL
725  };
726 
727  pe_eval_nvpairs(top, xml_obj, set_name, &rule_data, hash,
728  always_first, overwrite, next_change);
729 }
730 
731 #if ENABLE_VERSIONED_ATTRS
732 void
733 pe_eval_versioned_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name,
734  pe_rule_eval_data_t *rule_data, xmlNode *hash,
735  crm_time_t *next_change)
736 {
737  unpack_nvpair_blocks(top, xml_obj, set_name, hash, NULL, FALSE, rule_data,
738  next_change, unpack_versioned_attr_set);
739 }
740 #endif
741 
742 char *
743 pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
744 {
745  size_t len = 0;
746  int i;
747  const char *p, *last_match_index;
748  char *p_dst, *result = NULL;
749 
750  if (pcmk__str_empty(string) || !match_data) {
751  return NULL;
752  }
753 
754  p = last_match_index = string;
755 
756  while (*p) {
757  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
758  i = *(p + 1) - '0';
759  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
760  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
761  len += p - last_match_index + (match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so);
762  last_match_index = p + 2;
763  }
764  p++;
765  }
766  p++;
767  }
768  len += p - last_match_index + 1;
769 
770  /* FIXME: Excessive? */
771  if (len - 1 <= 0) {
772  return NULL;
773  }
774 
775  p_dst = result = calloc(1, len);
776  p = string;
777 
778  while (*p) {
779  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
780  i = *(p + 1) - '0';
781  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
782  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
783  /* rm_eo can be equal to rm_so, but then there is nothing to do */
784  int match_len = match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so;
785  memcpy(p_dst, match_data->string + match_data->pmatch[i].rm_so, match_len);
786  p_dst += match_len;
787  }
788  p++;
789  } else {
790  *(p_dst) = *(p);
791  p_dst++;
792  }
793  p++;
794  }
795 
796  return result;
797 }
798 
799 #if ENABLE_VERSIONED_ATTRS
800 GHashTable*
801 pe_unpack_versioned_parameters(xmlNode *versioned_params, const char *ra_version)
802 {
803  GHashTable *hash = crm_str_table_new();
804 
805  if (versioned_params && ra_version) {
806  GHashTable *node_hash = crm_str_table_new();
807  xmlNode *attr_set = pcmk__xe_first_child(versioned_params);
808 
809  if (attr_set) {
810  g_hash_table_insert(node_hash, strdup(CRM_ATTR_RA_VERSION),
811  strdup(ra_version));
812  pe_unpack_nvpairs(NULL, versioned_params,
813  crm_element_name(attr_set), node_hash, hash, NULL,
814  FALSE, NULL, NULL);
815  }
816 
817  g_hash_table_destroy(node_hash);
818  }
819 
820  return hash;
821 }
822 #endif
823 
824 gboolean
825 pe_eval_rules(xmlNode *ruleset, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
826 {
827  // If there are no rules, pass by default
828  gboolean ruleset_default = TRUE;
829 
830  for (xmlNode *rule = first_named_child(ruleset, XML_TAG_RULE);
831  rule != NULL; rule = crm_next_same_xml(rule)) {
832 
833  ruleset_default = FALSE;
834  if (pe_eval_expr(rule, rule_data, next_change)) {
835  /* Only the deprecated "lifetime" element of location constraints
836  * may contain more than one rule at the top level -- the schema
837  * limits a block of nvpairs to a single top-level rule. So, this
838  * effectively means that a lifetime is active if any rule it
839  * contains is active.
840  */
841  return TRUE;
842  }
843  }
844 
845  return ruleset_default;
846 }
847 
848 gboolean
849 pe_eval_expr(xmlNode *rule, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
850 {
851  xmlNode *expr = NULL;
852  gboolean test = TRUE;
853  gboolean empty = TRUE;
854  gboolean passed = TRUE;
855  gboolean do_and = TRUE;
856  const char *value = NULL;
857 
858  rule = expand_idref(rule, NULL);
860  if (pcmk__str_eq(value, "or", pcmk__str_casei)) {
861  do_and = FALSE;
862  passed = FALSE;
863  }
864 
865  crm_trace("Testing rule %s", ID(rule));
866  for (expr = pcmk__xe_first_child(rule); expr != NULL;
867  expr = pcmk__xe_next(expr)) {
868 
869  test = pe_eval_subexpr(expr, rule_data, next_change);
870  empty = FALSE;
871 
872  if (test && do_and == FALSE) {
873  crm_trace("Expression %s/%s passed", ID(rule), ID(expr));
874  return TRUE;
875 
876  } else if (test == FALSE && do_and) {
877  crm_trace("Expression %s/%s failed", ID(rule), ID(expr));
878  return FALSE;
879  }
880  }
881 
882  if (empty) {
883  crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule));
884  }
885 
886  crm_trace("Rule %s %s", ID(rule), passed ? "passed" : "failed");
887  return passed;
888 }
889 
890 gboolean
891 pe_eval_subexpr(xmlNode *expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
892 {
893  gboolean accept = FALSE;
894  const char *uname = NULL;
895 
896  switch (find_expression_type(expr)) {
897  case nested_rule:
898  accept = pe_eval_expr(expr, rule_data, next_change);
899  break;
900  case attr_expr:
901  case loc_expr:
902  /* these expressions can never succeed if there is
903  * no node to compare with
904  */
905  if (rule_data->node_hash != NULL) {
906  accept = pe__eval_attr_expr(expr, rule_data);
907  }
908  break;
909 
910  case time_expr:
911  accept = pe_test_date_expression(expr, rule_data->now, next_change);
912  break;
913 
914  case role_expr:
915  accept = pe__eval_role_expr(expr, rule_data);
916  break;
917 
918  case rsc_expr:
919  accept = pe__eval_rsc_expr(expr, rule_data);
920  break;
921 
922  case op_expr:
923  accept = pe__eval_op_expr(expr, rule_data);
924  break;
925 
926 #if ENABLE_VERSIONED_ATTRS
927  case version_expr:
928  if (rule_data->node_hash &&
929  g_hash_table_lookup_extended(rule_data->node_hash,
930  CRM_ATTR_RA_VERSION, NULL, NULL)) {
931  accept = pe__eval_attr_expr(expr, rule_data);
932  } else {
933  // we are going to test it when we have ra-version
934  accept = TRUE;
935  }
936  break;
937 #endif
938 
939  default:
940  CRM_CHECK(FALSE /* bad type */ , return FALSE);
941  accept = FALSE;
942  }
943  if (rule_data->node_hash) {
944  uname = g_hash_table_lookup(rule_data->node_hash, CRM_ATTR_UNAME);
945  }
946 
947  crm_trace("Expression %s %s on %s",
948  ID(expr), accept ? "passed" : "failed", uname ? uname : "all nodes");
949  return accept;
950 }
951 
967 static int
968 compare_attr_expr_vals(const char *l_val, const char *r_val, const char *type,
969  const char *op)
970 {
971  int cmp = 0;
972 
973  if (l_val != NULL && r_val != NULL) {
974  if (type == NULL) {
975  if (pcmk__strcase_any_of(op, "lt", "lte", "gt", "gte", NULL)) {
976  if (pcmk__char_in_any_str('.', l_val, r_val, NULL)) {
977  type = "number";
978  } else {
979  type = "integer";
980  }
981 
982  } else {
983  type = "string";
984  }
985  crm_trace("Defaulting to %s based comparison for '%s' op", type, op);
986  }
987 
988  if (pcmk__str_eq(type, "string", pcmk__str_casei)) {
989  cmp = strcasecmp(l_val, r_val);
990 
991  } else if (pcmk__str_eq(type, "integer", pcmk__str_casei)) {
992  long long l_val_num = crm_parse_ll(l_val, NULL);
993  int rc1 = errno;
994 
995  long long r_val_num = crm_parse_ll(r_val, NULL);
996  int rc2 = errno;
997 
998  if (rc1 == 0 && rc2 == 0) {
999  if (l_val_num < r_val_num) {
1000  cmp = -1;
1001  } else if (l_val_num > r_val_num) {
1002  cmp = 1;
1003  } else {
1004  cmp = 0;
1005  }
1006 
1007  } else {
1008  crm_debug("Integer parse error. Comparing %s and %s as strings",
1009  l_val, r_val);
1010  cmp = compare_attr_expr_vals(l_val, r_val, "string", op);
1011  }
1012 
1013  } else if (pcmk__str_eq(type, "number", pcmk__str_casei)) {
1014  double l_val_num;
1015  double r_val_num;
1016 
1017  int rc1 = pcmk__scan_double(l_val, &l_val_num, NULL, NULL);
1018  int rc2 = pcmk__scan_double(r_val, &r_val_num, NULL, NULL);
1019 
1020  if (rc1 == pcmk_rc_ok && rc2 == pcmk_rc_ok) {
1021  if (l_val_num < r_val_num) {
1022  cmp = -1;
1023  } else if (l_val_num > r_val_num) {
1024  cmp = 1;
1025  } else {
1026  cmp = 0;
1027  }
1028 
1029  } else {
1030  crm_debug("Floating-point parse error. Comparing %s and %s as "
1031  "strings", l_val, r_val);
1032  cmp = compare_attr_expr_vals(l_val, r_val, "string", op);
1033  }
1034 
1035  } else if (pcmk__str_eq(type, "version", pcmk__str_casei)) {
1036  cmp = compare_version(l_val, r_val);
1037 
1038  }
1039 
1040  } else if (l_val == NULL && r_val == NULL) {
1041  cmp = 0;
1042  } else if (r_val == NULL) {
1043  cmp = 1;
1044  } else { // l_val == NULL && r_val != NULL
1045  cmp = -1;
1046  }
1047 
1048  return cmp;
1049 }
1050 
1065 static bool
1066 accept_attr_expr(const char *l_val, const char *r_val, const char *type,
1067  const char *op)
1068 {
1069  int cmp;
1070 
1071  if (pcmk__str_eq(op, "defined", pcmk__str_casei)) {
1072  return (l_val != NULL);
1073 
1074  } else if (pcmk__str_eq(op, "not_defined", pcmk__str_casei)) {
1075  return (l_val == NULL);
1076 
1077  }
1078 
1079  cmp = compare_attr_expr_vals(l_val, r_val, type, op);
1080 
1081  if (pcmk__str_eq(op, "eq", pcmk__str_casei)) {
1082  return (cmp == 0);
1083 
1084  } else if (pcmk__str_eq(op, "ne", pcmk__str_casei)) {
1085  return (cmp != 0);
1086 
1087  } else if (l_val == NULL || r_val == NULL) {
1088  // The comparison is meaningless from this point on
1089  return false;
1090 
1091  } else if (pcmk__str_eq(op, "lt", pcmk__str_casei)) {
1092  return (cmp < 0);
1093 
1094  } else if (pcmk__str_eq(op, "lte", pcmk__str_casei)) {
1095  return (cmp <= 0);
1096 
1097  } else if (pcmk__str_eq(op, "gt", pcmk__str_casei)) {
1098  return (cmp > 0);
1099 
1100  } else if (pcmk__str_eq(op, "gte", pcmk__str_casei)) {
1101  return (cmp >= 0);
1102  }
1103 
1104  return false; // Should never reach this point
1105 }
1106 
1107 gboolean
1108 pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
1109 {
1110  gboolean attr_allocated = FALSE;
1111  const char *h_val = NULL;
1112  GHashTable *table = NULL;
1113 
1114  const char *op = NULL;
1115  const char *type = NULL;
1116  const char *attr = NULL;
1117  const char *value = NULL;
1118  const char *value_source = NULL;
1119 
1122  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
1124  value_source = crm_element_value(expr, XML_EXPR_ATTR_VALUE_SOURCE);
1125 
1126  if (attr == NULL || op == NULL) {
1127  pe_err("Invalid attribute or operation in expression"
1128  " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value));
1129  return FALSE;
1130  }
1131 
1132  if (rule_data->match_data) {
1133  if (rule_data->match_data->re) {
1134  char *resolved_attr = pe_expand_re_matches(attr, rule_data->match_data->re);
1135 
1136  if (resolved_attr) {
1137  attr = (const char *) resolved_attr;
1138  attr_allocated = TRUE;
1139  }
1140  }
1141 
1142  if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
1143  table = rule_data->match_data->params;
1144  } else if (pcmk__str_eq(value_source, "meta", pcmk__str_casei)) {
1145  table = rule_data->match_data->meta;
1146  }
1147  }
1148 
1149  if (table) {
1150  const char *param_name = value;
1151  const char *param_value = NULL;
1152 
1153  if (param_name && param_name[0]) {
1154  if ((param_value = (const char *)g_hash_table_lookup(table, param_name))) {
1155  value = param_value;
1156  }
1157  }
1158  }
1159 
1160  if (rule_data->node_hash != NULL) {
1161  h_val = (const char *)g_hash_table_lookup(rule_data->node_hash, attr);
1162  }
1163 
1164  if (attr_allocated) {
1165  free((char *)attr);
1166  attr = NULL;
1167  }
1168 
1169  return accept_attr_expr(h_val, value, type, op);
1170 }
1171 
1172 
1173 
1174 int
1175 pe__eval_date_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
1176 {
1177  crm_time_t *start = NULL;
1178  crm_time_t *end = NULL;
1179  const char *value = NULL;
1180  const char *op = crm_element_value(expr, "operation");
1181 
1182  xmlNode *duration_spec = NULL;
1183  xmlNode *date_spec = NULL;
1184 
1185  // "undetermined" will also be returned for parsing errors
1186  int rc = pcmk_rc_undetermined;
1187 
1188  crm_trace("Testing expression: %s", ID(expr));
1189 
1190  duration_spec = first_named_child(expr, "duration");
1191  date_spec = first_named_child(expr, "date_spec");
1192 
1193  value = crm_element_value(expr, "start");
1194  if (value != NULL) {
1195  start = crm_time_new(value);
1196  }
1197  value = crm_element_value(expr, "end");
1198  if (value != NULL) {
1199  end = crm_time_new(value);
1200  }
1201 
1202  if (start != NULL && end == NULL && duration_spec != NULL) {
1203  end = pe_parse_xml_duration(start, duration_spec);
1204  }
1205 
1206  if (pcmk__str_eq(op, "in_range", pcmk__str_null_matches | pcmk__str_casei)) {
1207  if ((start == NULL) && (end == NULL)) {
1208  // in_range requires at least one of start or end
1209  } else if ((start != NULL) && (crm_time_compare(rule_data->now, start) < 0)) {
1211  crm_time_set_if_earlier(next_change, start);
1212  } else if ((end != NULL) && (crm_time_compare(rule_data->now, end) > 0)) {
1214  } else {
1216  if (end && next_change) {
1217  // Evaluation doesn't change until second after end
1218  crm_time_add_seconds(end, 1);
1219  crm_time_set_if_earlier(next_change, end);
1220  }
1221  }
1222 
1223  } else if (pcmk__str_eq(op, "date_spec", pcmk__str_casei)) {
1224  rc = pe_cron_range_satisfied(rule_data->now, date_spec);
1225  // @TODO set next_change appropriately
1226 
1227  } else if (pcmk__str_eq(op, "gt", pcmk__str_casei)) {
1228  if (start == NULL) {
1229  // gt requires start
1230  } else if (crm_time_compare(rule_data->now, start) > 0) {
1232  } else {
1234 
1235  // Evaluation doesn't change until second after start
1236  crm_time_add_seconds(start, 1);
1237  crm_time_set_if_earlier(next_change, start);
1238  }
1239 
1240  } else if (pcmk__str_eq(op, "lt", pcmk__str_casei)) {
1241  if (end == NULL) {
1242  // lt requires end
1243  } else if (crm_time_compare(rule_data->now, end) < 0) {
1245  crm_time_set_if_earlier(next_change, end);
1246  } else {
1248  }
1249  }
1250 
1251  crm_time_free(start);
1252  crm_time_free(end);
1253  return rc;
1254 }
1255 
1256 gboolean
1257 pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) {
1258  const char *name = crm_element_value(expr, XML_NVPAIR_ATTR_NAME);
1259  const char *interval_s = crm_element_value(expr, XML_LRM_ATTR_INTERVAL);
1260  guint interval;
1261 
1262  crm_trace("Testing op_defaults expression: %s", ID(expr));
1263 
1264  if (rule_data->op_data == NULL) {
1265  crm_trace("No operations data provided");
1266  return FALSE;
1267  }
1268 
1269  interval = crm_parse_interval_spec(interval_s);
1270  if (interval == 0 && errno != 0) {
1271  crm_trace("Could not parse interval: %s", interval_s);
1272  return FALSE;
1273  }
1274 
1275  if (interval_s != NULL && interval != rule_data->op_data->interval) {
1276  crm_trace("Interval doesn't match: %d != %d", interval, rule_data->op_data->interval);
1277  return FALSE;
1278  }
1279 
1280  if (!pcmk__str_eq(name, rule_data->op_data->op_name, pcmk__str_none)) {
1281  crm_trace("Name doesn't match: %s != %s", name, rule_data->op_data->op_name);
1282  return FALSE;
1283  }
1284 
1285  return TRUE;
1286 }
1287 
1288 gboolean
1289 pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
1290 {
1291  gboolean accept = FALSE;
1292  const char *op = NULL;
1293  const char *value = NULL;
1294 
1295  if (rule_data->role == RSC_ROLE_UNKNOWN) {
1296  return accept;
1297  }
1298 
1299  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
1301 
1302  if (pcmk__str_eq(op, "defined", pcmk__str_casei)) {
1303  if (rule_data->role > RSC_ROLE_STARTED) {
1304  accept = TRUE;
1305  }
1306 
1307  } else if (pcmk__str_eq(op, "not_defined", pcmk__str_casei)) {
1308  if (rule_data->role < RSC_ROLE_SLAVE && rule_data->role > RSC_ROLE_UNKNOWN) {
1309  accept = TRUE;
1310  }
1311 
1312  } else if (pcmk__str_eq(op, "eq", pcmk__str_casei)) {
1313  if (text2role(value) == rule_data->role) {
1314  accept = TRUE;
1315  }
1316 
1317  } else if (pcmk__str_eq(op, "ne", pcmk__str_casei)) {
1318  // Test "ne" only with promotable clone roles
1319  if (rule_data->role < RSC_ROLE_SLAVE && rule_data->role > RSC_ROLE_UNKNOWN) {
1320  accept = FALSE;
1321 
1322  } else if (text2role(value) != rule_data->role) {
1323  accept = TRUE;
1324  }
1325  }
1326  return accept;
1327 }
1328 
1329 gboolean
1330 pe__eval_rsc_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
1331 {
1332  const char *class = crm_element_value(expr, XML_AGENT_ATTR_CLASS);
1333  const char *provider = crm_element_value(expr, XML_AGENT_ATTR_PROVIDER);
1334  const char *type = crm_element_value(expr, XML_EXPR_ATTR_TYPE);
1335 
1336  crm_trace("Testing rsc_defaults expression: %s", ID(expr));
1337 
1338  if (rule_data->rsc_data == NULL) {
1339  crm_trace("No resource data provided");
1340  return FALSE;
1341  }
1342 
1343  if (class != NULL &&
1344  !pcmk__str_eq(class, rule_data->rsc_data->standard, pcmk__str_none)) {
1345  crm_trace("Class doesn't match: %s != %s", class, rule_data->rsc_data->standard);
1346  return FALSE;
1347  }
1348 
1349  if ((provider == NULL && rule_data->rsc_data->provider != NULL) ||
1350  (provider != NULL && rule_data->rsc_data->provider == NULL) ||
1351  !pcmk__str_eq(provider, rule_data->rsc_data->provider, pcmk__str_none)) {
1352  crm_trace("Provider doesn't match: %s != %s", provider, rule_data->rsc_data->provider);
1353  return FALSE;
1354  }
1355 
1356  if (type != NULL &&
1357  !pcmk__str_eq(type, rule_data->rsc_data->agent, pcmk__str_none)) {
1358  crm_trace("Agent doesn't match: %s != %s", type, rule_data->rsc_data->agent);
1359  return FALSE;
1360  }
1361 
1362  return TRUE;
1363 }
1364 
1365 // Deprecated functions kept only for backward API compatibility
1366 gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now);
1367 gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
1368  crm_time_t *now);
1369 gboolean pe_test_rule_re(xmlNode *rule, GHashTable *node_hash,
1370  enum rsc_role_e role, crm_time_t *now,
1371  pe_re_match_data_t *re_match_data);
1372 gboolean pe_test_rule_full(xmlNode *rule, GHashTable *node_hash,
1373  enum rsc_role_e role, crm_time_t *now,
1374  pe_match_data_t *match_data);
1375 gboolean test_expression(xmlNode *expr, GHashTable *node_hash,
1376  enum rsc_role_e role, crm_time_t *now);
1377 gboolean pe_test_expression_re(xmlNode *expr, GHashTable *node_hash,
1378  enum rsc_role_e role, crm_time_t *now,
1379  pe_re_match_data_t *re_match_data);
1380 gboolean pe_test_expression_full(xmlNode *expr, GHashTable *node_hash,
1381  enum rsc_role_e role, crm_time_t *now,
1382  pe_match_data_t *match_data);
1383 void unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj,
1384  const char *set_name, GHashTable *node_hash,
1385  GHashTable *hash, const char *always_first,
1386  gboolean overwrite, crm_time_t *now);
1387 
1388 gboolean
1389 test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
1390 {
1391  return pe_evaluate_rules(ruleset, node_hash, now, NULL);
1392 }
1393 
1394 gboolean
1395 test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
1396 {
1397  return pe_test_rule(rule, node_hash, role, now, NULL, NULL);
1398 }
1399 
1400 gboolean
1401 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)
1402 {
1403  pe_match_data_t match_data = {
1404  .re = re_match_data,
1405  .params = NULL,
1406  .meta = NULL,
1407  };
1408  return pe_test_rule(rule, node_hash, role, now, NULL, &match_data);
1409 }
1410 
1411 gboolean
1412 pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
1413  crm_time_t *now, pe_match_data_t *match_data)
1414 {
1415  return pe_test_rule(rule, node_hash, role, now, NULL, match_data);
1416 }
1417 
1418 gboolean
1419 test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
1420 {
1421  return pe_test_expression(expr, node_hash, role, now, NULL, NULL);
1422 }
1423 
1424 gboolean
1425 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)
1426 {
1427  pe_match_data_t match_data = {
1428  .re = re_match_data,
1429  .params = NULL,
1430  .meta = NULL,
1431  };
1432  return pe_test_expression(expr, node_hash, role, now, NULL, &match_data);
1433 }
1434 
1435 gboolean
1436 pe_test_expression_full(xmlNode *expr, GHashTable *node_hash,
1437  enum rsc_role_e role, crm_time_t *now,
1438  pe_match_data_t *match_data)
1439 {
1440  return pe_test_expression(expr, node_hash, role, now, NULL, match_data);
1441 }
1442 
1443 void
1444 unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name,
1445  GHashTable *node_hash, GHashTable *hash,
1446  const char *always_first, gboolean overwrite,
1447  crm_time_t *now)
1448 {
1449  pe_rule_eval_data_t rule_data = {
1450  .node_hash = node_hash,
1451  .role = RSC_ROLE_UNKNOWN,
1452  .now = now,
1453  .match_data = NULL,
1454  .rsc_data = NULL,
1455  .op_data = NULL
1456  };
1457 
1458  unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first,
1459  overwrite, &rule_data, NULL, unpack_attr_set);
1460 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
char uname[MAX_NAME]
Definition: internal.h:85
A dumping ground.
void crm_time_add_years(crm_time_t *dt, int value)
Definition: iso8601.c:1522
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:1401
const char * provider
Definition: common.h:163
Definition: rules.h:31
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:1417
bool pcmk__char_in_any_str(int ch,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:889
#define CRM_ATTR_KIND
Definition: crm.h:112
#define XML_EXPR_ATTR_TYPE
Definition: msg_xml.h:312
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:133
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:842
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:1419
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:303
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2777
int char2score(const char *score)
Definition: utils.c:61
pe_re_match_data_t * re
Definition: common.h:156
#define XML_TAG_ATTRS
Definition: msg_xml.h:172
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:1425
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:261
#define CRM_ATTR_ROLE
Definition: crm.h:113
#define XML_EXPR_ATTR_VALUE_SOURCE
Definition: msg_xml.h:313
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:713
int pe_eval_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change)
Definition: rules.c:389
int crm_time_get_ordinal(crm_time_t *dt, uint32_t *y, uint32_t *d)
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:346
#define CHECK_ONE(spec, name, var)
Definition: rules.c:266
guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:307
#define CRM_ATTR_RA_VERSION
Definition: crm.h:120
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:167
Definition: rules.h:32
gboolean pe_eval_rules(xmlNode *ruleset, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:825
void crm_time_add_hours(crm_time_t *dt, int value)
Definition: iso8601.c:1510
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:1436
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:796
guint interval
Definition: common.h:169
pe_match_data_t * match_data
Definition: common.h:176
int pe__eval_date_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:1175
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:178
int rc
Definition: pcmk_fence.c:35
Definition: rules.h:24
#define crm_debug(fmt, args...)
Definition: logging.h:352
gboolean pe_eval_subexpr(xmlNode *expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:891
void crm_time_add_weeks(crm_time_t *dt, int value)
Definition: iso8601.c:1516
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
gboolean pe_test_attr_expression(xmlNode *expr, GHashTable *hash, crm_time_t *now, pe_match_data_t *match_data)
Definition: rules.c:159
#define XML_EXPR_ATTR_VALUE
Definition: msg_xml.h:311
void crm_time_add_months(crm_time_t *dt, int value)
Definition: iso8601.c:1462
#define CRM_ATTR_UNAME
Definition: crm.h:110
#define crm_trace(fmt, args...)
Definition: logging.h:353
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:2850
const char * op_name
Definition: common.h:168
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:237
Wrappers for and extensions to libxml2.
char * pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
Definition: rules.c:743
void crm_time_add_minutes(crm_time_t *dt, int value)
Definition: iso8601.c:1504
#define XML_EXPR_ATTR_OPERATION
Definition: msg_xml.h:310
gboolean pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:1289
GHashTable * meta
Definition: common.h:158
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
void free_xml(xmlNode *child)
Definition: xml.c:790
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:1412
enum rsc_role_e text2role(const char *role)
Definition: common.c:484
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:178
pe_rsc_eval_data_t * rsc_data
Definition: common.h:177
const char * agent
Definition: common.h:164
gboolean pe_eval_expr(xmlNode *rule, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
Definition: rules.c:849
#define XML_RULE_ATTR_BOOLEAN_OP
Definition: msg_xml.h:306
gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:1395
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:315
struct unpack_data_s unpack_data_t
CRM_TRACE_INIT_DATA(pe_rules)
GHashTable * params
Definition: common.h:157
long long crm_parse_ll(const char *text, const char *default_text)
Parse a long long integer value from a string.
Definition: strings.c:107
struct sorted_set_s sorted_set_t
void pe_eval_nvpairs(xmlNode *top, 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:690
const char * standard
Definition: common.h:162
crm_time_t * now
Definition: common.h:175
gboolean pe_test_role_expression(xmlNode *expr, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:144
int crm_time_get_gregorian(crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d)
#define crm_err(fmt, args...)
Definition: logging.h:347
int crm_time_get_timeofday(crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s)
GHashTable * node_hash
Definition: common.h:173
gboolean pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:1257
gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
Definition: rules.c:1389
void crm_time_set(crm_time_t *target, crm_time_t *source)
Definition: iso8601.c:1193
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:93
regmatch_t * pmatch
Definition: common.h:152
int compare_version(const char *version1, const char *version2)
Definition: utils.c:225
gboolean pe__eval_rsc_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:1330
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:347
char data[0]
Definition: internal.h:90
gboolean pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
Definition: rules.c:1108
#define crm_str(x)
Definition: logging.h:373
int crm_time_compare(crm_time_t *dt, crm_time_t *rhs)
Definition: iso8601.c:1387
rsc_role_e
Definition: common.h:91
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
Definition: xml.c:655
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
Definition: strings.c:727
Definition: rules.h:27
expression_type
Definition: rules.h:23
#define ID(x)
Definition: msg_xml.h:425
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:1444
#define pe_err(fmt...)
Definition: internal.h:22
char * name
Definition: pcmk_fence.c:31
enum expression_type find_expression_type(xmlNode *expr)
Definition: rules.c:105
#define XML_TAG_RULE
Definition: msg_xml.h:302
enum rsc_role_e role
Definition: common.h:174
gboolean pe_test_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change)
Definition: rules.c:345
#define CRM_ATTR_ID
Definition: crm.h:111
int pe_cron_range_satisfied(crm_time_t *now, xmlNode *cron_spec)
Definition: rules.c:274
GList * GListPtr
Definition: crm.h:214
int crm_time_get_isoweek(crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d)
#define XML_EXPR_ATTR_ATTRIBUTE
Definition: msg_xml.h:309
void crm_time_add_days(crm_time_t *dt, int value)
Definition: iso8601.c:1437
char * string
Definition: common.h:150
#define update_field(xml_field, time_fn)
Definition: rules.c:307
enum crm_ais_msg_types type
Definition: internal.h:83
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:236
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2803
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:141