pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rules.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <crm_internal.h>
20 #include <crm/crm.h>
21 #include <crm/msg_xml.h>
22 #include <crm/common/xml.h>
23 
24 #include <glib.h>
25 
26 #include <crm/pengine/rules.h>
28 #include <crm/pengine/internal.h>
29 
30 #include <sys/types.h>
31 #include <regex.h>
32 #include <ctype.h>
33 
34 CRM_TRACE_INIT_DATA(pe_rules);
35 
36 gboolean
37 test_ruleset(xmlNode * ruleset, GHashTable * node_hash, crm_time_t * now)
38 {
39  gboolean ruleset_default = TRUE;
40  xmlNode *rule = NULL;
41 
42  for (rule = __xml_first_child(ruleset); rule != NULL; rule = __xml_next_element(rule)) {
43  if (crm_str_eq((const char *)rule->name, XML_TAG_RULE, TRUE)) {
44  ruleset_default = FALSE;
45  if (test_rule(rule, node_hash, RSC_ROLE_UNKNOWN, now)) {
46  return TRUE;
47  }
48  }
49  }
50 
51  return ruleset_default;
52 }
53 
54 gboolean
55 test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
56 {
57  return pe_test_rule_full(rule, node_hash, role, now, NULL);
58 }
59 
60 gboolean
61 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)
62 {
63  pe_match_data_t match_data = {
64  .re = re_match_data,
65  .params = NULL,
66  .meta = NULL,
67  };
68  return pe_test_rule_full(rule, node_hash, role, now, &match_data);
69 }
70 
71 gboolean
72 pe_test_rule_full(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_match_data_t * match_data)
73 {
74  xmlNode *expr = NULL;
75  gboolean test = TRUE;
76  gboolean empty = TRUE;
77  gboolean passed = TRUE;
78  gboolean do_and = TRUE;
79  const char *value = NULL;
80 
81  rule = expand_idref(rule, NULL);
83  if (safe_str_eq(value, "or")) {
84  do_and = FALSE;
85  passed = FALSE;
86  }
87 
88  crm_trace("Testing rule %s", ID(rule));
89  for (expr = __xml_first_child(rule); expr != NULL; expr = __xml_next_element(expr)) {
90  test = pe_test_expression_full(expr, node_hash, role, now, match_data);
91  empty = FALSE;
92 
93  if (test && do_and == FALSE) {
94  crm_trace("Expression %s/%s passed", ID(rule), ID(expr));
95  return TRUE;
96 
97  } else if (test == FALSE && do_and) {
98  crm_trace("Expression %s/%s failed", ID(rule), ID(expr));
99  return FALSE;
100  }
101  }
102 
103  if (empty) {
104  crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule));
105  }
106 
107  crm_trace("Rule %s %s", ID(rule), passed ? "passed" : "failed");
108  return passed;
109 }
110 
111 gboolean
112 test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
113 {
114  return pe_test_expression_full(expr, node_hash, role, now, NULL);
115 }
116 
117 gboolean
118 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)
119 {
120  pe_match_data_t match_data = {
121  .re = re_match_data,
122  .params = NULL,
123  .meta = NULL,
124  };
125  return pe_test_expression_full(expr, node_hash, role, now, &match_data);
126 }
127 
128 gboolean
129 pe_test_expression_full(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now, pe_match_data_t * match_data)
130 {
131  gboolean accept = FALSE;
132  const char *uname = NULL;
133 
134  switch (find_expression_type(expr)) {
135  case nested_rule:
136  accept = pe_test_rule_full(expr, node_hash, role, now, match_data);
137  break;
138  case attr_expr:
139  case loc_expr:
140  /* these expressions can never succeed if there is
141  * no node to compare with
142  */
143  if (node_hash != NULL) {
144  accept = pe_test_attr_expression_full(expr, node_hash, now, match_data);
145  }
146  break;
147 
148  case time_expr:
149  accept = pe_test_date_expression(expr, now);
150  break;
151 
152  case role_expr:
153  accept = pe_test_role_expression(expr, role, now);
154  break;
155 
156 #ifdef ENABLE_VERSIONED_ATTRS
157  case version_expr:
158  if (node_hash && g_hash_table_lookup_extended(node_hash,
160  NULL, NULL)) {
161  accept = pe_test_attr_expression(expr, node_hash, now);
162  } else {
163  // we are going to test it when we have ra-version
164  accept = TRUE;
165  }
166  break;
167 #endif
168 
169  default:
170  CRM_CHECK(FALSE /* bad type */ , return FALSE);
171  accept = FALSE;
172  }
173  if (node_hash) {
174  uname = g_hash_table_lookup(node_hash, CRM_ATTR_UNAME);
175  }
176 
177  crm_trace("Expression %s %s on %s",
178  ID(expr), accept ? "passed" : "failed", uname ? uname : "all nodes");
179  return accept;
180 }
181 
182 enum expression_type
183 find_expression_type(xmlNode * expr)
184 {
185  const char *tag = NULL;
186  const char *attr = NULL;
187 
189  tag = crm_element_name(expr);
190 
191  if (safe_str_eq(tag, "date_expression")) {
192  return time_expr;
193 
194  } else if (safe_str_eq(tag, XML_TAG_RULE)) {
195  return nested_rule;
196 
197  } else if (safe_str_neq(tag, "expression")) {
198  return not_expr;
199 
200  } else if (safe_str_eq(attr, CRM_ATTR_UNAME)
201  || safe_str_eq(attr, CRM_ATTR_KIND)
202  || safe_str_eq(attr, CRM_ATTR_ID)) {
203  return loc_expr;
204 
205  } else if (safe_str_eq(attr, CRM_ATTR_ROLE)) {
206  return role_expr;
207 
208 #ifdef ENABLE_VERSIONED_ATTRS
209  } else if (safe_str_eq(attr, CRM_ATTR_RA_VERSION)) {
210  return version_expr;
211 #endif
212  }
213 
214  return attr_expr;
215 }
216 
217 gboolean
218 pe_test_role_expression(xmlNode * expr, enum rsc_role_e role, crm_time_t * now)
219 {
220  gboolean accept = FALSE;
221  const char *op = NULL;
222  const char *value = NULL;
223 
224  if (role == RSC_ROLE_UNKNOWN) {
225  return accept;
226  }
227 
228  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
230 
231  if (safe_str_eq(op, "defined")) {
232  if (role > RSC_ROLE_STARTED) {
233  accept = TRUE;
234  }
235 
236  } else if (safe_str_eq(op, "not_defined")) {
237  if (role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) {
238  accept = TRUE;
239  }
240 
241  } else if (safe_str_eq(op, "eq")) {
242  if (text2role(value) == role) {
243  accept = TRUE;
244  }
245 
246  } else if (safe_str_eq(op, "ne")) {
247  // Test "ne" only with promotable clone roles
248  if (role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) {
249  accept = FALSE;
250 
251  } else if (text2role(value) != role) {
252  accept = TRUE;
253  }
254  }
255  return accept;
256 }
257 
258 gboolean
259 pe_test_attr_expression(xmlNode * expr, GHashTable * hash, crm_time_t * now)
260 {
261  return pe_test_attr_expression_full(expr, hash, now, NULL);
262 }
263 
264 gboolean
265 pe_test_attr_expression_full(xmlNode * expr, GHashTable * hash, crm_time_t * now, pe_match_data_t * match_data)
266 {
267  gboolean accept = FALSE;
268  gboolean attr_allocated = FALSE;
269  int cmp = 0;
270  const char *h_val = NULL;
271  GHashTable *table = NULL;
272 
273  const char *op = NULL;
274  const char *type = NULL;
275  const char *attr = NULL;
276  const char *value = NULL;
277  const char *value_source = NULL;
278 
281  value = crm_element_value(expr, XML_EXPR_ATTR_VALUE);
283  value_source = crm_element_value(expr, XML_EXPR_ATTR_VALUE_SOURCE);
284 
285  if (attr == NULL || op == NULL) {
286  pe_err("Invalid attribute or operation in expression"
287  " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value));
288  return FALSE;
289  }
290 
291  if (match_data) {
292  if (match_data->re) {
293  char *resolved_attr = pe_expand_re_matches(attr, match_data->re);
294 
295  if (resolved_attr) {
296  attr = (const char *) resolved_attr;
297  attr_allocated = TRUE;
298  }
299  }
300 
301  if (safe_str_eq(value_source, "param")) {
302  table = match_data->params;
303  } else if (safe_str_eq(value_source, "meta")) {
304  table = match_data->meta;
305  }
306  }
307 
308  if (table) {
309  const char *param_name = value;
310  const char *param_value = NULL;
311 
312  if (param_name && param_name[0]) {
313  if ((param_value = (const char *)g_hash_table_lookup(table, param_name))) {
314  value = param_value;
315  }
316  }
317  }
318 
319  if (hash != NULL) {
320  h_val = (const char *)g_hash_table_lookup(hash, attr);
321  }
322 
323  if (attr_allocated) {
324  free((char *)attr);
325  attr = NULL;
326  }
327 
328  if (value != NULL && h_val != NULL) {
329  if (type == NULL) {
330  if (safe_str_eq(op, "lt")
331  || safe_str_eq(op, "lte")
332  || safe_str_eq(op, "gt")
333  || safe_str_eq(op, "gte")) {
334  type = "number";
335 
336  } else {
337  type = "string";
338  }
339  crm_trace("Defaulting to %s based comparison for '%s' op", type, op);
340  }
341 
342  if (safe_str_eq(type, "string")) {
343  cmp = strcasecmp(h_val, value);
344 
345  } else if (safe_str_eq(type, "number")) {
346  int h_val_f = crm_parse_int(h_val, NULL);
347  int value_f = crm_parse_int(value, NULL);
348 
349  if (h_val_f < value_f) {
350  cmp = -1;
351  } else if (h_val_f > value_f) {
352  cmp = 1;
353  } else {
354  cmp = 0;
355  }
356 
357  } else if (safe_str_eq(type, "version")) {
358  cmp = compare_version(h_val, value);
359 
360  }
361 
362  } else if (value == NULL && h_val == NULL) {
363  cmp = 0;
364  } else if (value == NULL) {
365  cmp = 1;
366  } else {
367  cmp = -1;
368  }
369 
370  if (safe_str_eq(op, "defined")) {
371  if (h_val != NULL) {
372  accept = TRUE;
373  }
374 
375  } else if (safe_str_eq(op, "not_defined")) {
376  if (h_val == NULL) {
377  accept = TRUE;
378  }
379 
380  } else if (safe_str_eq(op, "eq")) {
381  if ((h_val == value) || cmp == 0) {
382  accept = TRUE;
383  }
384 
385  } else if (safe_str_eq(op, "ne")) {
386  if ((h_val == NULL && value != NULL)
387  || (h_val != NULL && value == NULL)
388  || cmp != 0) {
389  accept = TRUE;
390  }
391 
392  } else if (value == NULL || h_val == NULL) {
393  // The comparison is meaningless from this point on
394  accept = FALSE;
395 
396  } else if (safe_str_eq(op, "lt")) {
397  if (cmp < 0) {
398  accept = TRUE;
399  }
400 
401  } else if (safe_str_eq(op, "lte")) {
402  if (cmp <= 0) {
403  accept = TRUE;
404  }
405 
406  } else if (safe_str_eq(op, "gt")) {
407  if (cmp > 0) {
408  accept = TRUE;
409  }
410 
411  } else if (safe_str_eq(op, "gte")) {
412  if (cmp >= 0) {
413  accept = TRUE;
414  }
415  }
416 
417  return accept;
418 }
419 
420 /* As per the nethack rules:
421  *
422  * moon period = 29.53058 days ~= 30, year = 365.2422 days
423  * days moon phase advances on first day of year compared to preceding year
424  * = 365.2422 - 12*29.53058 ~= 11
425  * years in Metonic cycle (time until same phases fall on the same days of
426  * the month) = 18.6 ~= 19
427  * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
428  * (29 as initial condition)
429  * current phase in days = first day phase + days elapsed in year
430  * 6 moons ~= 177 days
431  * 177 ~= 8 reported phases * 22
432  * + 11/22 for rounding
433  *
434  * 0-7, with 0: new, 4: full
435  */
436 
437 static int
438 phase_of_the_moon(crm_time_t * now)
439 {
440  uint32_t epact, diy, goldn;
441  uint32_t y;
442 
443  crm_time_get_ordinal(now, &y, &diy);
444 
445  goldn = (y % 19) + 1;
446  epact = (11 * goldn + 18) % 30;
447  if ((epact == 25 && goldn > 11) || epact == 24)
448  epact++;
449 
450  return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
451 }
452 
453 static gboolean
454 decodeNVpair(const char *srcstring, char separator, char **name, char **value)
455 {
456  const char *seploc = NULL;
457 
458  CRM_ASSERT(name != NULL && value != NULL);
459  *name = NULL;
460  *value = NULL;
461 
462  crm_trace("Attempting to decode: [%s]", srcstring);
463  if (srcstring != NULL) {
464  seploc = strchr(srcstring, separator);
465  if (seploc) {
466  *name = strndup(srcstring, seploc - srcstring);
467  if (*(seploc + 1)) {
468  *value = strdup(seploc + 1);
469  }
470  return TRUE;
471  }
472  }
473  return FALSE;
474 }
475 
476 #define cron_check(xml_field, time_field) \
477  value = crm_element_value(cron_spec, xml_field); \
478  if(value != NULL) { \
479  gboolean pass = TRUE; \
480  decodeNVpair(value, '-', &value_low, &value_high); \
481  if(value_low == NULL) { \
482  value_low = strdup(value); \
483  } \
484  value_low_i = crm_parse_int(value_low, "0"); \
485  value_high_i = crm_parse_int(value_high, "-1"); \
486  if(value_high_i < 0) { \
487  if(value_low_i != time_field) { \
488  pass = FALSE; \
489  } \
490  } else if(value_low_i > time_field) { \
491  pass = FALSE; \
492  } else if(value_high_i < time_field) { \
493  pass = FALSE; \
494  } \
495  free(value_low); \
496  free(value_high); \
497  if(pass == FALSE) { \
498  crm_debug("Condition '%s' in %s: failed", value, xml_field); \
499  return pass; \
500  } \
501  crm_debug("Condition '%s' in %s: passed", value, xml_field); \
502  }
503 
504 gboolean
505 pe_cron_range_satisfied(crm_time_t * now, xmlNode * cron_spec)
506 {
507  const char *value = NULL;
508  char *value_low = NULL;
509  char *value_high = NULL;
510 
511  int value_low_i = 0;
512  int value_high_i = 0;
513 
514  uint32_t h, m, s, y, d, w;
515 
516  CRM_CHECK(now != NULL, return FALSE);
517 
518  crm_time_get_timeofday(now, &h, &m, &s);
519 
520  cron_check("seconds", s);
521  cron_check("minutes", m);
522  cron_check("hours", h);
523 
524  crm_time_get_gregorian(now, &y, &m, &d);
525 
526  cron_check("monthdays", d);
527  cron_check("months", m);
528  cron_check("years", y);
529 
530  crm_time_get_ordinal(now, &y, &d);
531 
532  cron_check("yeardays", d);
533 
534  crm_time_get_isoweek(now, &y, &w, &d);
535 
536  cron_check("weekyears", y);
537  cron_check("weeks", w);
538  cron_check("weekdays", d);
539 
540  cron_check("moon", phase_of_the_moon(now));
541 
542  return TRUE;
543 }
544 
545 #define update_field(xml_field, time_fn) \
546  value = crm_element_value(duration_spec, xml_field); \
547  if(value != NULL) { \
548  int value_i = crm_parse_int(value, "0"); \
549  time_fn(end, value_i); \
550  }
551 
552 crm_time_t *
553 pe_parse_xml_duration(crm_time_t * start, xmlNode * duration_spec)
554 {
555  crm_time_t *end = NULL;
556  const char *value = NULL;
557 
558  end = crm_time_new(NULL);
559  crm_time_set(end, start);
560 
568 
569  return end;
570 }
571 
572 gboolean
574 {
575  pe_eval_date_result_t result = pe_eval_date_expression(time_expr, now);
576  const char *op = crm_element_value(time_expr, "operation");
577 
578  if (result == pe_date_within_range) {
579  return TRUE;
580 
581  } else if ((safe_str_eq(op, "date_spec") || safe_str_eq(op, "in_range") || op == NULL) &&
582  result == pe_date_op_satisfied) {
583  return TRUE;
584 
585  } else if ((safe_str_eq(op, "eq") || safe_str_eq(op, "neq")) &&
586  result == pe_date_op_satisfied) {
587  return TRUE;
588 
589  } else {
590  return FALSE;
591  }
592 }
593 
596 {
597  crm_time_t *start = NULL;
598  crm_time_t *end = NULL;
599  const char *value = NULL;
600  const char *op = crm_element_value(time_expr, "operation");
601 
602  xmlNode *duration_spec = NULL;
603  xmlNode *date_spec = NULL;
604 
606 
607  crm_trace("Testing expression: %s", ID(time_expr));
608 
609  duration_spec = first_named_child(time_expr, "duration");
610  date_spec = first_named_child(time_expr, "date_spec");
611 
612  value = crm_element_value(time_expr, "start");
613  if (value != NULL) {
614  start = crm_time_new(value);
615  }
616  value = crm_element_value(time_expr, "end");
617  if (value != NULL) {
618  end = crm_time_new(value);
619  }
620 
621  if (start != NULL && end == NULL && duration_spec != NULL) {
622  end = pe_parse_xml_duration(start, duration_spec);
623  }
624  if (op == NULL) {
625  op = "in_range";
626  }
627 
628  if (safe_str_eq(op, "date_spec") || safe_str_eq(op, "in_range")) {
629  if (start != NULL && crm_time_compare(start, now) > 0) {
631  } else if (end != NULL && crm_time_compare(end, now) < 0) {
632  rc = pe_date_after_range;
633  } else if (safe_str_eq(op, "in_range")) {
635  } else {
636  rc = pe_cron_range_satisfied(now, date_spec) ? pe_date_op_satisfied
638  }
639 
640  } else if (safe_str_eq(op, "gt")) {
642 
643  } else if (safe_str_eq(op, "lt")) {
645 
646  } else if (safe_str_eq(op, "eq")) {
647  rc = crm_time_compare(start, now) == 0 ? pe_date_op_satisfied
649 
650  } else if (safe_str_eq(op, "neq")) {
651  rc = crm_time_compare(start, now) != 0 ? pe_date_op_satisfied
653  }
654 
655  crm_time_free(start);
656  crm_time_free(end);
657  return rc;
658 }
659 
660 typedef struct sorted_set_s {
661  int score;
662  const char *name;
663  const char *special_name;
664  xmlNode *attr_set;
665 } sorted_set_t;
666 
667 static gint
668 sort_pairs(gconstpointer a, gconstpointer b)
669 {
670  const sorted_set_t *pair_a = a;
671  const sorted_set_t *pair_b = b;
672 
673  if (a == NULL && b == NULL) {
674  return 0;
675  } else if (a == NULL) {
676  return 1;
677  } else if (b == NULL) {
678  return -1;
679  }
680 
681  if (safe_str_eq(pair_a->name, pair_a->special_name)) {
682  return -1;
683 
684  } else if (safe_str_eq(pair_b->name, pair_a->special_name)) {
685  return 1;
686  }
687 
688  if (pair_a->score < pair_b->score) {
689  return 1;
690  } else if (pair_a->score > pair_b->score) {
691  return -1;
692  }
693  return 0;
694 }
695 
696 static void
697 populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlNode * top)
698 {
699  const char *name = NULL;
700  const char *value = NULL;
701  const char *old_value = NULL;
702  xmlNode *list = nvpair_list;
703  xmlNode *an_attr = NULL;
704 
705  name = crm_element_name(list->children);
706  if (safe_str_eq(XML_TAG_ATTRS, name)) {
707  list = list->children;
708  }
709 
710  for (an_attr = __xml_first_child(list); an_attr != NULL; an_attr = __xml_next_element(an_attr)) {
711  if (crm_str_eq((const char *)an_attr->name, XML_CIB_TAG_NVPAIR, TRUE)) {
712  xmlNode *ref_nvpair = expand_idref(an_attr, top);
713 
714  name = crm_element_value(an_attr, XML_NVPAIR_ATTR_NAME);
715  if (name == NULL) {
716  name = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_NAME);
717  }
718 
719  crm_trace("Setting attribute: %s", name);
720  value = crm_element_value(an_attr, XML_NVPAIR_ATTR_VALUE);
721  if (value == NULL) {
722  value = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_VALUE);
723  }
724 
725  if (name == NULL || value == NULL) {
726  continue;
727 
728  }
729 
730  old_value = g_hash_table_lookup(hash, name);
731 
732  if (safe_str_eq(value, "#default")) {
733  if (old_value) {
734  crm_trace("Removing value for %s (%s)", name, value);
735  g_hash_table_remove(hash, name);
736  }
737  continue;
738 
739  } else if (old_value == NULL) {
740  g_hash_table_insert(hash, strdup(name), strdup(value));
741 
742  } else if (overwrite) {
743  crm_debug("Overwriting value of %s: %s -> %s", name, old_value, value);
744  g_hash_table_replace(hash, strdup(name), strdup(value));
745  }
746  }
747  }
748 }
749 
750 #ifdef ENABLE_VERSIONED_ATTRS
751 static xmlNode*
752 get_versioned_rule(xmlNode * attr_set)
753 {
754  xmlNode * rule = NULL;
755  xmlNode * expr = NULL;
756 
757  for (rule = __xml_first_child(attr_set); rule != NULL; rule = __xml_next_element(rule)) {
758  if (crm_str_eq((const char *)rule->name, XML_TAG_RULE, TRUE)) {
759  for (expr = __xml_first_child(rule); expr != NULL; expr = __xml_next_element(expr)) {
760  if (find_expression_type(expr) == version_expr) {
761  return rule;
762  }
763  }
764  }
765  }
766 
767  return NULL;
768 }
769 
770 static void
771 add_versioned_attributes(xmlNode * attr_set, xmlNode * versioned_attrs)
772 {
773  xmlNode *attr_set_copy = NULL;
774  xmlNode *rule = NULL;
775  xmlNode *expr = NULL;
776 
777  if (!attr_set || !versioned_attrs) {
778  return;
779  }
780 
781  attr_set_copy = copy_xml(attr_set);
782 
783  rule = get_versioned_rule(attr_set_copy);
784  if (!rule) {
785  free_xml(attr_set_copy);
786  return;
787  }
788 
789  expr = __xml_first_child(rule);
790  while (expr != NULL) {
791  if (find_expression_type(expr) != version_expr) {
792  xmlNode *node = expr;
793 
794  expr = __xml_next_element(expr);
795  free_xml(node);
796  } else {
797  expr = __xml_next_element(expr);
798  }
799  }
800 
801  add_node_nocopy(versioned_attrs, NULL, attr_set_copy);
802 }
803 #endif
804 
805 typedef struct unpack_data_s {
806  gboolean overwrite;
807  GHashTable *node_hash;
808  void *hash;
809  crm_time_t *now;
810  xmlNode *top;
811 } unpack_data_t;
812 
813 static void
814 unpack_attr_set(gpointer data, gpointer user_data)
815 {
816  sorted_set_t *pair = data;
817  unpack_data_t *unpack_data = user_data;
818 
819  if (test_ruleset(pair->attr_set, unpack_data->node_hash, unpack_data->now) == FALSE) {
820  return;
821  }
822 
823 #ifdef ENABLE_VERSIONED_ATTRS
824  if (get_versioned_rule(pair->attr_set) && !(unpack_data->node_hash &&
825  g_hash_table_lookup_extended(unpack_data->node_hash,
826  CRM_ATTR_RA_VERSION, NULL, NULL))) {
827  // we haven't actually tested versioned expressions yet
828  return;
829  }
830 #endif
831 
832  crm_trace("Adding attributes from %s", pair->name);
833  populate_hash(pair->attr_set, unpack_data->hash, unpack_data->overwrite, unpack_data->top);
834 }
835 
836 #ifdef ENABLE_VERSIONED_ATTRS
837 static void
838 unpack_versioned_attr_set(gpointer data, gpointer user_data)
839 {
840  sorted_set_t *pair = data;
841  unpack_data_t *unpack_data = user_data;
842 
843  if (test_ruleset(pair->attr_set, unpack_data->node_hash, unpack_data->now) == FALSE) {
844  return;
845  }
846 
847  add_versioned_attributes(pair->attr_set, unpack_data->hash);
848 }
849 #endif
850 
851 static GListPtr
852 make_pairs_and_populate_data(xmlNode * top, xmlNode * xml_obj, const char *set_name,
853  GHashTable * node_hash, void * hash, const char *always_first,
854  gboolean overwrite, crm_time_t * now, unpack_data_t * data)
855 {
856  GListPtr unsorted = NULL;
857  const char *score = NULL;
858  sorted_set_t *pair = NULL;
859  xmlNode *attr_set = NULL;
860 
861  if (xml_obj == NULL) {
862  crm_trace("No instance attributes");
863  return NULL;
864  }
865 
866  crm_trace("Checking for attributes");
867  for (attr_set = __xml_first_child(xml_obj); attr_set != NULL; attr_set = __xml_next_element(attr_set)) {
868  /* Uncertain if set_name == NULL check is strictly necessary here */
869  if (set_name == NULL || crm_str_eq((const char *)attr_set->name, set_name, TRUE)) {
870  pair = NULL;
871  attr_set = expand_idref(attr_set, top);
872  if (attr_set == NULL) {
873  continue;
874  }
875 
876  pair = calloc(1, sizeof(sorted_set_t));
877  pair->name = ID(attr_set);
878  pair->special_name = always_first;
879  pair->attr_set = attr_set;
880 
881  score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE);
882  pair->score = char2score(score);
883 
884  unsorted = g_list_prepend(unsorted, pair);
885  }
886  }
887 
888  if (pair != NULL) {
889  data->hash = hash;
890  data->node_hash = node_hash;
891  data->now = now;
892  data->overwrite = overwrite;
893  data->top = top;
894  }
895 
896  if (unsorted) {
897  return g_list_sort(unsorted, sort_pairs);
898  }
899 
900  return NULL;
901 }
902 
903 void
904 unpack_instance_attributes(xmlNode * top, xmlNode * xml_obj, const char *set_name,
905  GHashTable * node_hash, GHashTable * hash, const char *always_first,
906  gboolean overwrite, crm_time_t * now)
907 {
909  GListPtr pairs = make_pairs_and_populate_data(top, xml_obj, set_name, node_hash, hash,
910  always_first, overwrite, now, &data);
911 
912  if (pairs) {
913  g_list_foreach(pairs, unpack_attr_set, &data);
914  g_list_free_full(pairs, free);
915  }
916 }
917 
918 #ifdef ENABLE_VERSIONED_ATTRS
919 void
920 pe_unpack_versioned_attributes(xmlNode * top, xmlNode * xml_obj, const char *set_name,
921  GHashTable * node_hash, xmlNode * hash, crm_time_t * now)
922 {
924  GListPtr pairs = make_pairs_and_populate_data(top, xml_obj, set_name, node_hash, hash,
925  NULL, FALSE, now, &data);
926 
927  if (pairs) {
928  g_list_foreach(pairs, unpack_versioned_attr_set, &data);
929  g_list_free_full(pairs, free);
930  }
931 }
932 #endif
933 
934 char *
935 pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
936 {
937  size_t len = 0;
938  int i;
939  const char *p, *last_match_index;
940  char *p_dst, *result = NULL;
941 
942  if (!string || string[0] == '\0' || !match_data) {
943  return NULL;
944  }
945 
946  p = last_match_index = string;
947 
948  while (*p) {
949  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
950  i = *(p + 1) - '0';
951  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
952  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
953  len += p - last_match_index + (match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so);
954  last_match_index = p + 2;
955  }
956  p++;
957  }
958  p++;
959  }
960  len += p - last_match_index + 1;
961 
962  /* FIXME: Excessive? */
963  if (len - 1 <= 0) {
964  return NULL;
965  }
966 
967  p_dst = result = calloc(1, len);
968  p = string;
969 
970  while (*p) {
971  if (*p == '%' && *(p + 1) && isdigit(*(p + 1))) {
972  i = *(p + 1) - '0';
973  if (match_data->nregs >= i && match_data->pmatch[i].rm_so != -1 &&
974  match_data->pmatch[i].rm_eo > match_data->pmatch[i].rm_so) {
975  /* rm_eo can be equal to rm_so, but then there is nothing to do */
976  int match_len = match_data->pmatch[i].rm_eo - match_data->pmatch[i].rm_so;
977  memcpy(p_dst, match_data->string + match_data->pmatch[i].rm_so, match_len);
978  p_dst += match_len;
979  }
980  p++;
981  } else {
982  *(p_dst) = *(p);
983  p_dst++;
984  }
985  p++;
986  }
987 
988  return result;
989 }
990 
991 #ifdef ENABLE_VERSIONED_ATTRS
992 GHashTable*
993 pe_unpack_versioned_parameters(xmlNode *versioned_params, const char *ra_version)
994 {
995  GHashTable *hash = crm_str_table_new();
996 
997  if (versioned_params && ra_version) {
998  GHashTable *node_hash = crm_str_table_new();
999  xmlNode *attr_set = __xml_first_child(versioned_params);
1000 
1001  if (attr_set) {
1002  g_hash_table_insert(node_hash, strdup(CRM_ATTR_RA_VERSION),
1003  strdup(ra_version));
1004  unpack_instance_attributes(NULL, versioned_params, crm_element_name(attr_set),
1005  node_hash, hash, NULL, FALSE, NULL);
1006  }
1007 
1008  g_hash_table_destroy(node_hash);
1009  }
1010 
1011  return hash;
1012 }
1013 #endif
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:156
char uname[MAX_NAME]
Definition: internal.h:87
A dumping ground.
void crm_time_add_years(crm_time_t *dt, int value)
Definition: iso8601.c:1266
#define cron_check(xml_field, time_field)
Definition: rules.c:476
pe_eval_date_result_t pe_eval_date_expression(xmlNode *time_expr, crm_time_t *now)
Definition: rules.c:595
void crm_time_add_seconds(crm_time_t *dt, int value)
Definition: iso8601.c:1160
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:157
#define CRM_ATTR_KIND
Definition: crm.h:90
#define XML_EXPR_ATTR_TYPE
Definition: msg_xml.h:305
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define XML_RULE_ATTR_SCORE
Definition: msg_xml.h:296
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:118
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:4155
int char2score(const char *score)
Definition: utils.c:199
pe_re_match_data_t * re
Definition: rules.h:51
#define XML_TAG_ATTRS
Definition: msg_xml.h:165
#define CRM_ATTR_ROLE
Definition: crm.h:91
#define XML_EXPR_ATTR_VALUE_SOURCE
Definition: msg_xml.h:306
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:110
int crm_time_get_ordinal(crm_time_t *dt, uint32_t *y, uint32_t *d)
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:339
#define CRM_ATTR_RA_VERSION
Definition: crm.h:98
gboolean pe_test_role_expression(xmlNode *expr, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:218
#define XML_CIB_TAG_NVPAIR
Definition: msg_xml.h:160
char * strndup(const char *str, size_t len)
void crm_time_add_hours(crm_time_t *dt, int value)
Definition: iso8601.c:1254
enum expression_type find_expression_type(xmlNode *expr)
Definition: rules.c:183
#define CRM_TRACE_INIT_DATA(name)
Definition: logging.h:111
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2020
Definition: rules.h:35
gboolean pe_test_date_expression(xmlNode *time_expr, crm_time_t *now)
Definition: rules.c:573
#define crm_debug(fmt, args...)
Definition: logging.h:245
crm_time_t * pe_parse_xml_duration(crm_time_t *start, xmlNode *duration_spec)
Definition: rules.c:553
void crm_time_add_weeks(crm_time_t *dt, int value)
Definition: iso8601.c:1260
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:423
gboolean pe_test_attr_expression(xmlNode *expr, GHashTable *hash, crm_time_t *now)
Definition: rules.c:259
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:72
#define XML_EXPR_ATTR_VALUE
Definition: msg_xml.h:304
void crm_time_add_months(crm_time_t *dt, int value)
Definition: iso8601.c:1206
#define CRM_ATTR_UNAME
Definition: crm.h:88
#define crm_trace(fmt, args...)
Definition: logging.h:246
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition: xml.c:4227
Wrappers for and extensions to libxml2.
void crm_time_add_minutes(crm_time_t *dt, int value)
Definition: iso8601.c:1248
#define XML_EXPR_ATTR_OPERATION
Definition: msg_xml.h:303
GHashTable * meta
Definition: rules.h:53
char * pe_expand_re_matches(const char *string, pe_re_match_data_t *match_data)
Definition: rules.c:935
void free_xml(xmlNode *child)
Definition: xml.c:2014
enum rsc_role_e text2role(const char *role)
Definition: common.c:350
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:220
#define XML_RULE_ATTR_BOOLEAN_OP
Definition: msg_xml.h:299
void populate_hash(xmlNode *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length)
gboolean pe_test_attr_expression_full(xmlNode *expr, GHashTable *hash, crm_time_t *now, pe_match_data_t *match_data)
Definition: rules.c:265
struct unpack_data_s unpack_data_t
GHashTable * params
Definition: rules.h:52
struct sorted_set_s sorted_set_t
gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
Definition: rules.c:37
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:240
int crm_time_get_timeofday(crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s)
#define CRM_ASSERT(expr)
Definition: results.h:42
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:129
void crm_time_set(crm_time_t *target, crm_time_t *source)
Definition: iso8601.c:966
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:84
regmatch_t * pmatch
Definition: rules.h:47
int compare_version(const char *version1, const char *version2)
Definition: utils.c:461
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:340
char data[0]
Definition: internal.h:92
#define crm_str(x)
Definition: logging.h:266
int crm_time_compare(crm_time_t *dt, crm_time_t *rhs)
Definition: iso8601.c:1133
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:61
rsc_role_e
Definition: common.h:86
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
Definition: xml.c:1882
Definition: rules.h:38
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:904
gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:55
expression_type
Definition: rules.h:34
#define ID(x)
Definition: msg_xml.h:414
#define pe_err(fmt...)
Definition: internal.h:20
gboolean pe_cron_range_satisfied(crm_time_t *now, xmlNode *cron_spec)
Definition: rules.c:505
pe_eval_date_result_t
#define safe_str_eq(a, b)
Definition: util.h:59
#define XML_TAG_RULE
Definition: msg_xml.h:295
#define CRM_ATTR_ID
Definition: crm.h:89
GList * GListPtr
Definition: crm.h:192
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:302
void crm_time_add_days(crm_time_t *dt, int value)
Definition: iso8601.c:1181
char * string
Definition: rules.h:45
#define update_field(xml_field, time_fn)
Definition: rules.c:545
enum crm_ais_msg_types type
Definition: internal.h:85
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:101
gboolean test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now)
Definition: rules.c:112