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 int score_a = 0;
73 int score_b = 0;
74 int rc = pcmk_rc_ok;
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 rc = pcmk__xe_get_score(pair_a, PCMK_XA_SCORE, &score_a, 0);
94 if (rc != pcmk_rc_ok) {
95 pcmk__config_warn("Using 0 as %s score because '%s' "
96 "is not a valid score: %s",
97 pcmk__xe_id(pair_a),
98 crm_element_value(pair_a, PCMK_XA_SCORE),
99 pcmk_rc_str(rc));
100 }
101
102 rc = pcmk__xe_get_score(pair_b, PCMK_XA_SCORE, &score_b, 0);
103 if (rc != pcmk_rc_ok) {
104 pcmk__config_warn("Using 0 as %s score because '%s' "
105 "is not a valid score: %s",
106 pcmk__xe_id(pair_b),
107 crm_element_value(pair_b, PCMK_XA_SCORE),
108 pcmk_rc_str(rc));
109 }
110
111
112
113
114
115 if (score_a < score_b) {
116 return unpack_data->overwrite? -1 : 1;
117 } else if (score_a > score_b) {
118 return unpack_data->overwrite? 1 : -1;
119 }
120 return 0;
121 }
122
123 static void
124 populate_hash(xmlNode *nvpair_list, GHashTable *hash, bool overwrite)
125 {
126 const char *name = NULL;
127 const char *value = NULL;
128 const char *old_value = NULL;
129 xmlNode *list = nvpair_list;
130 xmlNode *an_attr = NULL;
131
132 if (pcmk__xe_is(list->children, PCMK__XE_ATTRIBUTES)) {
133 list = list->children;
134 }
135
136 for (an_attr = pcmk__xe_first_child(list, NULL, NULL, NULL);
137 an_attr != NULL; an_attr = pcmk__xe_next(an_attr)) {
138
139 if (pcmk__xe_is(an_attr, PCMK_XE_NVPAIR)) {
140 xmlNode *ref_nvpair = expand_idref(an_attr, NULL);
141
142 name = crm_element_value(an_attr, PCMK_XA_NAME);
143 if ((name == NULL) && (ref_nvpair != NULL)) {
144 name = crm_element_value(ref_nvpair, PCMK_XA_NAME);
145 }
146
147 value = crm_element_value(an_attr, PCMK_XA_VALUE);
148 if ((value == NULL) && (ref_nvpair != NULL)) {
149 value = crm_element_value(ref_nvpair, PCMK_XA_VALUE);
150 }
151
152 if (name == NULL || value == NULL) {
153 continue;
154 }
155
156 old_value = g_hash_table_lookup(hash, name);
157
158 if (pcmk__str_eq(value, "#default", pcmk__str_casei)) {
159
160 pcmk__config_warn("Support for setting meta-attributes (such "
161 "as %s) to the explicit value '#default' is "
162 "deprecated and will be removed in a future "
163 "release", name);
164 if (old_value) {
165 crm_trace("Letting %s default (removing explicit value \"%s\")",
166 name, value);
167 g_hash_table_remove(hash, name);
168 }
169 continue;
170
171 } else if (old_value == NULL) {
172 crm_trace("Setting %s=\"%s\"", name, value);
173 pcmk__insert_dup(hash, name, value);
174
175 } else if (overwrite) {
176 crm_trace("Setting %s=\"%s\" (overwriting old value \"%s\")",
177 name, value, old_value);
178 pcmk__insert_dup(hash, name, value);
179 }
180 }
181 }
182 }
183
184 static void
185 unpack_attr_set(gpointer data, gpointer user_data)
186 {
187 xmlNode *pair = data;
188 pcmk__nvpair_unpack_t *unpack_data = user_data;
189
190 if (pcmk__evaluate_rules(pair, &(unpack_data->rule_input),
191 unpack_data->next_change) != pcmk_rc_ok) {
192 return;
193 }
194
195 crm_trace("Adding name/value pairs from %s %s overwrite",
196 pcmk__xe_id(pair), (unpack_data->overwrite? "with" : "without"));
197 populate_hash(pair, unpack_data->values, unpack_data->overwrite);
198 }
199
200
201
202
203
204
205
206
207
208
209 static GList *
210 make_pairs(const xmlNode *xml_obj, const char *set_name)
211 {
212 GList *unsorted = NULL;
213
214 if (xml_obj == NULL) {
215 return NULL;
216 }
217 for (xmlNode *attr_set = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
218 attr_set != NULL; attr_set = pcmk__xe_next(attr_set)) {
219
220 if ((set_name == NULL) || pcmk__xe_is(attr_set, set_name)) {
221 xmlNode *expanded_attr_set = expand_idref(attr_set, NULL);
222
223 if (expanded_attr_set == NULL) {
224 continue;
225 }
226 unsorted = g_list_prepend(unsorted, expanded_attr_set);
227 }
228 }
229 return unsorted;
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244 void
245 pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
246 const pe_rule_eval_data_t *rule_data, GHashTable *hash,
247 const char *always_first, gboolean overwrite,
248 crm_time_t *next_change)
249 {
250 GList *pairs = make_pairs(xml_obj, set_name);
251
252 if (pairs) {
253 pcmk__nvpair_unpack_t data = {
254 .values = hash,
255 .first_id = always_first,
256 .overwrite = overwrite,
257 .next_change = next_change,
258 };
259
260 map_rule_input(&(data.rule_input), rule_data);
261
262 pairs = g_list_sort_with_data(pairs, sort_pairs, &data);
263 g_list_foreach(pairs, unpack_attr_set, &data);
264 g_list_free(pairs);
265 }
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 void
282 pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
283 GHashTable *node_hash, GHashTable *hash,
284 const char *always_first, gboolean overwrite,
285 crm_time_t *now, crm_time_t *next_change)
286 {
287 pe_rule_eval_data_t rule_data = {
288 .node_hash = node_hash,
289 .now = now,
290 .match_data = NULL,
291 .rsc_data = NULL,
292 .op_data = NULL
293 };
294
295 pe_eval_nvpairs(NULL, xml_obj, set_name, &rule_data, hash,
296 always_first, overwrite, next_change);
297 }
298
299
300
301
302 #include <crm/pengine/rules_compat.h>
303
304 gboolean
305 pe_eval_rules(xmlNode *ruleset, const pe_rule_eval_data_t *rule_data,
306 crm_time_t *next_change)
307 {
308 pcmk_rule_input_t rule_input = { NULL, };
309
310 map_rule_input(&rule_input, rule_data);
311 return pcmk__evaluate_rules(ruleset, &rule_input,
312 next_change) == pcmk_rc_ok;
313 }
314
315 gboolean
316 pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now,
317 crm_time_t *next_change)
318 {
319 pcmk_rule_input_t rule_input = {
320 .node_attrs = node_hash,
321 .now = now,
322 };
323
324 return pcmk__evaluate_rules(ruleset, &rule_input, next_change);
325 }
326
327 gboolean
328 pe_test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
329 crm_time_t *now, crm_time_t *next_change,
330 pe_match_data_t *match_data)
331 {
332 pcmk_rule_input_t rule_input = {
333 .node_attrs = node_hash,
334 .now = now,
335 };
336
337 if (match_data != NULL) {
338 rule_input.rsc_params = match_data->params;
339 rule_input.rsc_meta = match_data->meta;
340 if (match_data->re != NULL) {
341 rule_input.rsc_id = match_data->re->string;
342 rule_input.rsc_id_submatches = match_data->re->pmatch;
343 rule_input.rsc_id_nmatches = match_data->re->nregs;
344 }
345 }
346 return pcmk_evaluate_rule(rule, &rule_input, next_change) == pcmk_rc_ok;
347 }
348
349 gboolean
350 test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now)
351 {
352 return pe_evaluate_rules(ruleset, node_hash, now, NULL);
353 }
354
355 gboolean
356 test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
357 {
358 return pe_test_rule(rule, node_hash, role, now, NULL, NULL);
359 }
360
361 gboolean
362 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)
363 {
364 pe_match_data_t match_data = {
365 .re = re_match_data,
366 .params = NULL,
367 .meta = NULL,
368 };
369 return pe_test_rule(rule, node_hash, role, now, NULL, &match_data);
370 }
371
372 gboolean
373 pe_test_rule_full(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role,
374 crm_time_t *now, pe_match_data_t *match_data)
375 {
376 return pe_test_rule(rule, node_hash, role, now, NULL, match_data);
377 }
378
379 gboolean
380 pe_test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role,
381 crm_time_t *now, crm_time_t *next_change,
382 pe_match_data_t *match_data)
383 {
384 pcmk_rule_input_t rule_input = {
385 .now = now,
386 .node_attrs = node_hash,
387 };
388
389 if (match_data != NULL) {
390 rule_input.rsc_params = match_data->params;
391 rule_input.rsc_meta = match_data->meta;
392 if (match_data->re != NULL) {
393 rule_input.rsc_id = match_data->re->string;
394 rule_input.rsc_id_submatches = match_data->re->pmatch;
395 rule_input.rsc_id_nmatches = match_data->re->nregs;
396 }
397 }
398 return pcmk__evaluate_condition(expr, &rule_input,
399 next_change) == pcmk_rc_ok;
400 }
401
402 gboolean
403 test_expression(xmlNode * expr, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
404 {
405 return pe_test_expression(expr, node_hash, role, now, NULL, NULL);
406 }
407
408 gboolean
409 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)
410 {
411 pe_match_data_t match_data = {
412 .re = re_match_data,
413 .params = NULL,
414 .meta = NULL,
415 };
416 return pe_test_expression(expr, node_hash, role, now, NULL, &match_data);
417 }
418
419 gboolean
420 pe_test_expression_full(xmlNode *expr, GHashTable *node_hash,
421 enum rsc_role_e role, crm_time_t *now,
422 pe_match_data_t *match_data)
423 {
424 return pe_test_expression(expr, node_hash, role, now, NULL, match_data);
425 }
426
427 gboolean
428 pe_eval_expr(xmlNode *rule, const pe_rule_eval_data_t *rule_data,
429 crm_time_t *next_change)
430 {
431 pcmk_rule_input_t rule_input = { NULL, };
432
433 map_rule_input(&rule_input, rule_data);
434 return pcmk_evaluate_rule(rule, &rule_input, next_change) == pcmk_rc_ok;
435 }
436
437 gboolean
438 pe_eval_subexpr(xmlNode *expr, const pe_rule_eval_data_t *rule_data,
439 crm_time_t *next_change)
440 {
441 pcmk_rule_input_t rule_input = { NULL, };
442
443 map_rule_input(&rule_input, rule_data);
444 return pcmk__evaluate_condition(expr, &rule_input,
445 next_change) == pcmk_rc_ok;
446 }
447
448 void
449 unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name,
450 GHashTable *node_hash, GHashTable *hash,
451 const char *always_first, gboolean overwrite,
452 crm_time_t *now)
453 {
454 pe_rule_eval_data_t rule_data = {
455 .node_hash = node_hash,
456 .now = now,
457 .match_data = NULL,
458 .rsc_data = NULL,
459 .op_data = NULL
460 };
461
462 pe_eval_nvpairs(NULL, xml_obj, set_name, &rule_data, hash, always_first,
463 overwrite, NULL);
464 }
465
466 enum expression_type
467 find_expression_type(xmlNode *expr)
468 {
469 return pcmk__condition_type(expr);
470 }
471
472 char *
473 pe_expand_re_matches(const char *string, const pe_re_match_data_t *match_data)
474 {
475 if (match_data == NULL) {
476 return NULL;
477 }
478 return pcmk__replace_submatches(string, match_data->string,
479 match_data->pmatch, match_data->nregs);
480 }
481
482
483