This source file includes following definitions.
- map_rule_input
- sort_pairs
- populate_hash
- unpack_attr_set
- make_pairs
- pe_eval_nvpairs
- pe_unpack_nvpairs
- pe_eval_rules
- pe_evaluate_rules
- pe_test_rule
- test_ruleset
- test_rule
- pe_test_rule_re
- pe_test_rule_full
- pe_test_expression
- test_expression
- pe_test_expression_re
- pe_test_expression_full
- pe_eval_expr
- pe_eval_subexpr
- unpack_instance_attributes
- find_expression_type
- pe_expand_re_matches
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13
14 #include <crm/crm.h>
15 #include <crm/common/xml.h>
16 #include <crm/pengine/rules.h>
17
18 #include <crm/common/iso8601_internal.h>
19 #include <crm/common/nvpair_internal.h>
20 #include <crm/common/rules_internal.h>
21 #include <crm/common/xml_internal.h>
22 #include <crm/pengine/internal.h>
23 #include <crm/pengine/rules_internal.h>
24
25 #include <sys/types.h>
26 #include <regex.h>
27
28 CRM_TRACE_INIT_DATA(pe_rules);
29
30
31
32
33
34
35
36
37 static void
38 map_rule_input(pcmk_rule_input_t *new, const pe_rule_eval_data_t *old)
39 {
40 if (old == NULL) {
41 return;
42 }
43 new->now = old->now;
44 new->node_attrs = old->node_hash;
45 if (old->rsc_data != NULL) {
46 new->rsc_standard = old->rsc_data->standard;
47 new->rsc_provider = old->rsc_data->provider;
48 new->rsc_agent = old->rsc_data->agent;
49 }
50 if (old->match_data != NULL) {
51 new->rsc_params = old->match_data->params;
52 new->rsc_meta = old->match_data->meta;
53 if (old->match_data->re != NULL) {
54 new->rsc_id = old->match_data->re->string;
55 new->rsc_id_submatches = old->match_data->re->pmatch;
56 new->rsc_id_nmatches = old->match_data->re->nregs;
57 }
58 }
59 if (old->op_data != NULL) {
60 new->op_name = old->op_data->op_name;
61 new->op_interval_ms = old->op_data->interval;
62 }
63 }
64
65 static gint
66 sort_pairs(gconstpointer a, gconstpointer b, gpointer user_data)
67 {
68 const xmlNode *pair_a = a;
69 const xmlNode *pair_b = b;
70 pcmk__nvpair_unpack_t *unpack_data = user_data;
71
72 const char *score = NULL;
73 int score_a = 0;
74 int score_b = 0;
75
76 if (a == NULL && b == NULL) {
77 return 0;
78 } else if (a == NULL) {
79 return 1;
80 } else if (b == NULL) {
81 return -1;
82 }
83
84 if (pcmk__str_eq(pcmk__xe_id(pair_a), unpack_data->first_id,
85 pcmk__str_none)) {
86 return -1;
87
88 } else if (pcmk__str_eq(pcmk__xe_id(pair_b), unpack_data->first_id,
89 pcmk__str_none)) {
90 return 1;
91 }
92
93 score = crm_element_value(pair_a, PCMK_XA_SCORE);
94 score_a = char2score(score);
95
96 score = crm_element_value(pair_b, PCMK_XA_SCORE);
97 score_b = char2score(score);
98
99
100
101
102
103 if (score_a < score_b) {
104 return unpack_data->overwrite? -1 : 1;
105 } else if (score_a > score_b) {
106 return unpack_data->overwrite? 1 : -1;
107 }
108 return 0;
109 }
110
111 static void
112 populate_hash(xmlNode *nvpair_list, GHashTable *hash, bool overwrite)
113 {
114 const char *name = NULL;
115 const char *value = NULL;
116 const char *old_value = NULL;
117 xmlNode *list = nvpair_list;
118 xmlNode *an_attr = NULL;
119
120 if (pcmk__xe_is(list->children, PCMK__XE_ATTRIBUTES)) {
121 list = list->children;
122 }
123
124 for (an_attr = pcmk__xe_first_child(list, NULL, NULL, NULL);
125 an_attr != NULL; an_attr = pcmk__xe_next(an_attr)) {
126
127 if (pcmk__xe_is(an_attr, PCMK_XE_NVPAIR)) {
128 xmlNode *ref_nvpair = expand_idref(an_attr, NULL);
129
130 name = crm_element_value(an_attr, PCMK_XA_NAME);
131 if ((name == NULL) && (ref_nvpair != NULL)) {
132 name = crm_element_value(ref_nvpair, PCMK_XA_NAME);
133 }
134
135 value = crm_element_value(an_attr, PCMK_XA_VALUE);
136 if ((value == NULL) && (ref_nvpair != NULL)) {
137 value = crm_element_value(ref_nvpair, PCMK_XA_VALUE);
138 }
139
140 if (name == NULL || value == NULL) {
141 continue;
142 }
143
144 old_value = g_hash_table_lookup(hash, name);
145
146 if (pcmk__str_eq(value, "#default", pcmk__str_casei)) {
147
148 pcmk__config_warn("Support for setting meta-attributes (such "
149 "as %s) to the explicit value '#default' is "
150 "deprecated and will be removed in a future "
151 "release", name);
152 if (old_value) {
153 crm_trace("Letting %s default (removing explicit value \"%s\")",
154 name, value);
155 g_hash_table_remove(hash, name);
156 }
157 continue;
158
159 } else if (old_value == NULL) {
160 crm_trace("Setting %s=\"%s\"", name, value);
161 pcmk__insert_dup(hash, name, value);
162
163 } else if (overwrite) {
164 crm_trace("Setting %s=\"%s\" (overwriting old value \"%s\")",
165 name, value, old_value);
166 pcmk__insert_dup(hash, name, value);
167 }
168 }
169 }
170 }
171
172 static void
173 unpack_attr_set(gpointer data, gpointer user_data)
174 {
175 xmlNode *pair = data;
176 pcmk__nvpair_unpack_t *unpack_data = user_data;
177
178 if (pcmk__evaluate_rules(pair, &(unpack_data->rule_input),
179 unpack_data->next_change) != pcmk_rc_ok) {
180 return;
181 }
182
183 crm_trace("Adding name/value pairs from %s %s overwrite",
184 pcmk__xe_id(pair), (unpack_data->overwrite? "with" : "without"));
185 populate_hash(pair, unpack_data->values, unpack_data->overwrite);
186 }
187
188
189
190
191
192
193
194
195
196
197 static GList *
198 make_pairs(const xmlNode *xml_obj, const char *set_name)
199 {
200 GList *unsorted = NULL;
201
202 if (xml_obj == NULL) {
203 return NULL;
204 }
205 for (xmlNode *attr_set = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
206 attr_set != NULL; attr_set = pcmk__xe_next(attr_set)) {
207
208 if ((set_name == NULL) || pcmk__xe_is(attr_set, set_name)) {
209 xmlNode *expanded_attr_set = expand_idref(attr_set, NULL);
210
211 if (expanded_attr_set == NULL) {
212 continue;
213 }
214 unsorted = g_list_prepend(unsorted, expanded_attr_set);
215 }
216 }
217 return unsorted;
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232 void
233 pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
234 const pe_rule_eval_data_t *rule_data, GHashTable *hash,
235 const char *always_first, gboolean overwrite,
236 crm_time_t *next_change)
237 {
238 GList *pairs = make_pairs(xml_obj, set_name);
239
240 if (pairs) {
241 pcmk__nvpair_unpack_t data = {
242 .values = hash,
243 .first_id = always_first,
244 .overwrite = overwrite,
245 .next_change = next_change,
246 };
247
248 map_rule_input(&(data.rule_input), rule_data);
249
250 pairs = g_list_sort_with_data(pairs, sort_pairs, &data);
251 g_list_foreach(pairs, unpack_attr_set, &data);
252 g_list_free(pairs);
253 }
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 void
270 pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
271 GHashTable *node_hash, GHashTable *hash,
272 const char *always_first, gboolean overwrite,
273 crm_time_t *now, crm_time_t *next_change)
274 {
275 pe_rule_eval_data_t rule_data = {
276 .node_hash = node_hash,
277 .now = now,
278 .match_data = NULL,
279 .rsc_data = NULL,
280 .op_data = NULL
281 };
282
283 pe_eval_nvpairs(NULL, xml_obj, set_name, &rule_data, hash,
284 always_first, overwrite, next_change);
285 }
286
287
288
289
290 #include <crm/pengine/rules_compat.h>
291
292 gboolean
293 pe_eval_rules(xmlNode *ruleset, const pe_rule_eval_data_t *rule_data,
294 crm_time_t *next_change)
295 {
296 pcmk_rule_input_t rule_input = { NULL, };
297
298 map_rule_input(&rule_input, rule_data);
299 return pcmk__evaluate_rules(ruleset, &rule_input,
300 next_change) == pcmk_rc_ok;
301 }
302
303 gboolean
304 pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now,
305 crm_time_t *next_change)
306 {
307 pcmk_rule_input_t rule_input = {
308 .node_attrs = node_hash,
309 .now = now,
310 };
311
312 return pcmk__evaluate_rules(ruleset, &rule_input, next_change);
313 }
314
315 gboolean
316 pe_test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
317 crm_time_t *now, crm_time_t *next_change,
318 pe_match_data_t *match_data)
319 {
320 pcmk_rule_input_t rule_input = {
321 .node_attrs = node_hash,
322 .now = now,
323 };
324
325 if (match_data != NULL) {
326 rule_input.rsc_params = match_data->params;
327 rule_input.rsc_meta = match_data->meta;
328 if (match_data->re != NULL) {
329 rule_input.rsc_id = match_data->re->string;
330 rule_input.rsc_id_submatches = match_data->re->pmatch;
331 rule_input.rsc_id_nmatches = match_data->re->nregs;
332 }
333 }
334 return pcmk_evaluate_rule(rule, &rule_input, next_change) == pcmk_rc_ok;
335 }
336
337 gboolean
338 test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
339 {
340 return pe_evaluate_rules(ruleset, node_hash, now, NULL);
341 }
342
343 gboolean
344 test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
345 {
346 return pe_test_rule(rule, node_hash, role, now, NULL, NULL);
347 }
348
349 gboolean
350 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)
351 {
352 pe_match_data_t match_data = {
353 .re = re_match_data,
354 .params = NULL,
355 .meta = NULL,
356 };
357 return pe_test_rule(rule, node_hash, role, now, NULL, &match_data);
358 }
359
360 gboolean
361 pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
362 crm_time_t *now, pe_match_data_t *match_data)
363 {
364 return pe_test_rule(rule, node_hash, role, now, NULL, match_data);
365 }
366
367 gboolean
368 pe_test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role,
369 crm_time_t *now, crm_time_t *next_change,
370 pe_match_data_t *match_data)
371 {
372 pcmk_rule_input_t rule_input = {
373 .now = now,
374 .node_attrs = node_hash,
375 };
376
377 if (match_data != NULL) {
378 rule_input.rsc_params = match_data->params;
379 rule_input.rsc_meta = match_data->meta;
380 if (match_data->re != NULL) {
381 rule_input.rsc_id = match_data->re->string;
382 rule_input.rsc_id_submatches = match_data->re->pmatch;
383 rule_input.rsc_id_nmatches = match_data->re->nregs;
384 }
385 }
386 return pcmk__evaluate_condition(expr, &rule_input,
387 next_change) == pcmk_rc_ok;
388 }
389
390 gboolean
391 test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
392 {
393 return pe_test_expression(expr, node_hash, role, now, NULL, NULL);
394 }
395
396 gboolean
397 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)
398 {
399 pe_match_data_t match_data = {
400 .re = re_match_data,
401 .params = NULL,
402 .meta = NULL,
403 };
404 return pe_test_expression(expr, node_hash, role, now, NULL, &match_data);
405 }
406
407 gboolean
408 pe_test_expression_full(xmlNode *expr, GHashTable *node_hash,
409 enum rsc_role_e role, crm_time_t *now,
410 pe_match_data_t *match_data)
411 {
412 return pe_test_expression(expr, node_hash, role, now, NULL, match_data);
413 }
414
415 gboolean
416 pe_eval_expr(xmlNode *rule, const pe_rule_eval_data_t *rule_data,
417 crm_time_t *next_change)
418 {
419 pcmk_rule_input_t rule_input = { NULL, };
420
421 map_rule_input(&rule_input, rule_data);
422 return pcmk_evaluate_rule(rule, &rule_input, next_change) == pcmk_rc_ok;
423 }
424
425 gboolean
426 pe_eval_subexpr(xmlNode *expr, const pe_rule_eval_data_t *rule_data,
427 crm_time_t *next_change)
428 {
429 pcmk_rule_input_t rule_input = { NULL, };
430
431 map_rule_input(&rule_input, rule_data);
432 return pcmk__evaluate_condition(expr, &rule_input,
433 next_change) == pcmk_rc_ok;
434 }
435
436 void
437 unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name,
438 GHashTable *node_hash, GHashTable *hash,
439 const char *always_first, gboolean overwrite,
440 crm_time_t *now)
441 {
442 pe_rule_eval_data_t rule_data = {
443 .node_hash = node_hash,
444 .now = now,
445 .match_data = NULL,
446 .rsc_data = NULL,
447 .op_data = NULL
448 };
449
450 pe_eval_nvpairs(NULL, xml_obj, set_name, &rule_data, hash, always_first,
451 overwrite, NULL);
452 }
453
454 enum expression_type
455 find_expression_type(xmlNode *expr)
456 {
457 return pcmk__condition_type(expr);
458 }
459
460 char *
461 pe_expand_re_matches(const char *string, const pe_re_match_data_t *match_data)
462 {
463 if (match_data == NULL) {
464 return NULL;
465 }
466 return pcmk__replace_submatches(string, match_data->string,
467 match_data->pmatch, match_data->nregs);
468 }
469
470
471