This source file includes following definitions.
- eval_date_expression
- init_rule_check
- eval_rule
- pcmk__check_rules
- pcmk_check_rules
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/cib/internal.h>
13 #include <crm/common/cib.h>
14 #include <crm/common/iso8601.h>
15 #include <crm/msg_xml.h>
16 #include <crm/pengine/internal.h>
17 #include <crm/pengine/rules_internal.h>
18 #include <pacemaker-internal.h>
19
20
21
22
23
24
25
26
27
28
29 static int
30 eval_date_expression(const xmlNode *expr, crm_time_t *now)
31 {
32 pe_rule_eval_data_t rule_data = {
33 .node_hash = NULL,
34 .role = pcmk_role_unknown,
35 .now = now,
36 .match_data = NULL,
37 .rsc_data = NULL,
38 .op_data = NULL
39 };
40
41 return pe__eval_date_expr(expr, &rule_data, NULL);
42 }
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 static int
61 init_rule_check(pcmk__output_t *out, xmlNodePtr input, const crm_time_t *date,
62 pcmk_scheduler_t **scheduler)
63 {
64
65 pcmk_scheduler_t *new_scheduler = NULL;
66
67 new_scheduler = pe_new_working_set();
68 if (new_scheduler == NULL) {
69 return ENOMEM;
70 }
71
72 pe__set_working_set_flags(new_scheduler,
73 pcmk_sched_no_counts|pcmk_sched_no_compat);
74
75
76
77
78 if (input != NULL) {
79 new_scheduler->input = copy_xml(input);
80 if (new_scheduler->input == NULL) {
81 out->err(out, "Failed to copy input XML");
82 pe_free_working_set(new_scheduler);
83 return ENOMEM;
84 }
85
86 } else {
87 int rc = cib__signon_query(out, NULL, &(new_scheduler->input));
88
89 if (rc != pcmk_rc_ok) {
90 pe_free_working_set(new_scheduler);
91 return rc;
92 }
93 }
94
95
96
97 if (date != NULL) {
98
99 new_scheduler->now = pcmk_copy_time(date);
100 }
101
102
103 cluster_status(new_scheduler);
104 *scheduler = new_scheduler;
105
106 return pcmk_rc_ok;
107 }
108
109 #define XPATH_NODE_RULE "//" XML_TAG_RULE "[@" XML_ATTR_ID "='%s']"
110
111
112
113
114
115
116
117
118
119
120
121 static int
122 eval_rule(pcmk_scheduler_t *scheduler, const char *rule_id, const char **error)
123 {
124 xmlNodePtr cib_constraints = NULL;
125 xmlNodePtr match = NULL;
126 xmlXPathObjectPtr xpath_obj = NULL;
127 char *xpath = NULL;
128 int rc = pcmk_rc_ok;
129 int num_results = 0;
130
131 *error = NULL;
132
133
134 cib_constraints = pcmk_find_cib_element(scheduler->input,
135 XML_CIB_TAG_CONSTRAINTS);
136
137
138
139
140
141
142
143
144
145
146
147 xpath = crm_strdup_printf(XPATH_NODE_RULE, rule_id);
148 xpath_obj = xpath_search(cib_constraints, xpath);
149 num_results = numXpathResults(xpath_obj);
150
151 free(xpath);
152 freeXpathObject(xpath_obj);
153
154 if (num_results == 0) {
155 *error = "Rule not found";
156 return ENXIO;
157 }
158
159 if (num_results > 1) {
160
161 *error = "Found more than one rule with matching ID";
162 return pcmk_rc_duplicate_id;
163 }
164
165
166 xpath = crm_strdup_printf(XPATH_NODE_RULE "//date_expression", rule_id);
167 xpath_obj = xpath_search(cib_constraints, xpath);
168 num_results = numXpathResults(xpath_obj);
169
170 free(xpath);
171 freeXpathObject(xpath_obj);
172
173 if (num_results != 1) {
174 if (num_results == 0) {
175 *error = "Rule does not have a date expression";
176 } else {
177 *error = "Rule has more than one date expression";
178 }
179 return EOPNOTSUPP;
180 }
181
182
183 xpath = crm_strdup_printf(XPATH_NODE_RULE "//date_expression["
184 "@" XML_EXPR_ATTR_OPERATION "!='date_spec']",
185 rule_id);
186 xpath_obj = xpath_search(cib_constraints, xpath);
187 num_results = numXpathResults(xpath_obj);
188
189 free(xpath);
190
191 if (num_results == 0) {
192 freeXpathObject(xpath_obj);
193
194 xpath = crm_strdup_printf(XPATH_NODE_RULE "//date_expression["
195 "@" XML_EXPR_ATTR_OPERATION "='date_spec' "
196 "and date_spec/@years "
197 "and not(date_spec/@moon)]", rule_id);
198 xpath_obj = xpath_search(cib_constraints, xpath);
199 num_results = numXpathResults(xpath_obj);
200
201 free(xpath);
202
203 if (num_results == 0) {
204 freeXpathObject(xpath_obj);
205 *error = "Rule must either not use date_spec, or use date_spec "
206 "with years= but not moon=";
207 return EOPNOTSUPP;
208 }
209 }
210
211 match = getXpathResult(xpath_obj, 0);
212
213
214
215
216 CRM_ASSERT(match != NULL);
217 CRM_ASSERT(find_expression_type(match) == time_expr);
218
219 rc = eval_date_expression(match, scheduler->now);
220 if (rc == pcmk_rc_undetermined) {
221
222
223
224 *error = "Error parsing rule";
225 }
226
227 freeXpathObject(xpath_obj);
228 return rc;
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 int
245 pcmk__check_rules(pcmk__output_t *out, xmlNodePtr input, const crm_time_t *date,
246 const char **rule_ids)
247 {
248 pcmk_scheduler_t *scheduler = NULL;
249 int rc = pcmk_rc_ok;
250
251 CRM_ASSERT(out != NULL);
252
253 if (rule_ids == NULL) {
254
255 return pcmk_rc_ok;
256 }
257
258 rc = init_rule_check(out, input, date, &scheduler);
259 if (rc != pcmk_rc_ok) {
260 return rc;
261 }
262
263 for (const char **rule_id = rule_ids; *rule_id != NULL; rule_id++) {
264 const char *error = NULL;
265 int last_rc = eval_rule(scheduler, *rule_id, &error);
266
267 out->message(out, "rule-check", *rule_id, last_rc, error);
268
269 if (last_rc != pcmk_rc_ok) {
270 rc = last_rc;
271 }
272 }
273
274 pe_free_working_set(scheduler);
275 return rc;
276 }
277
278
279 int
280 pcmk_check_rules(xmlNodePtr *xml, xmlNodePtr input, const crm_time_t *date,
281 const char **rule_ids)
282 {
283 pcmk__output_t *out = NULL;
284 int rc = pcmk_rc_ok;
285
286 rc = pcmk__xml_output_new(&out, xml);
287 if (rc != pcmk_rc_ok) {
288 return rc;
289 }
290
291 pcmk__register_lib_messages(out);
292
293 rc = pcmk__check_rules(out, input, date, rule_ids);
294 pcmk__xml_output_finish(out, xml);
295 return rc;
296 }