This source file includes following definitions.
- evaluate_lifetime
- pcmk__unpack_constraints
- pcmk__find_constraint_resource
- find_constraint_tag
- pcmk__valid_resource_or_tag
- pcmk__expand_tags_in_sets
- pcmk__tag_to_set
- pcmk__create_internal_constraints
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <stdbool.h>
15 #include <regex.h>
16 #include <glib.h>
17
18 #include <crm/crm.h>
19 #include <crm/cib.h>
20 #include <crm/common/xml.h>
21 #include <crm/common/xml_internal.h>
22 #include <crm/common/iso8601.h>
23 #include <crm/pengine/status.h>
24 #include <crm/pengine/internal.h>
25 #include <crm/pengine/rules.h>
26 #include <pacemaker-internal.h>
27 #include "libpacemaker_private.h"
28
29 static bool
30 evaluate_lifetime(xmlNode *lifetime, pcmk_scheduler_t *scheduler)
31 {
32 bool result = false;
33 crm_time_t *next_change = crm_time_new_undefined();
34 pcmk_rule_input_t rule_input = {
35 .now = scheduler->now,
36 };
37
38 result = (pcmk__evaluate_rules(lifetime, &rule_input,
39 next_change) == pcmk_rc_ok);
40
41 if (crm_time_is_defined(next_change)) {
42 time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
43
44 pe__update_recheck_time(recheck, scheduler, "constraint lifetime");
45 }
46 crm_time_free(next_change);
47 return result;
48 }
49
50
51
52
53
54
55
56
57
58
59 void
60 pcmk__unpack_constraints(pcmk_scheduler_t *scheduler)
61 {
62 xmlNode *xml_constraints = pcmk_find_cib_element(scheduler->input,
63 PCMK_XE_CONSTRAINTS);
64
65 for (xmlNode *xml_obj = pcmk__xe_first_child(xml_constraints, NULL, NULL,
66 NULL);
67 xml_obj != NULL; xml_obj = pcmk__xe_next(xml_obj)) {
68
69 xmlNode *lifetime = NULL;
70 const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
71 const char *tag = (const char *) xml_obj->name;
72
73 if (id == NULL) {
74 pcmk__config_err("Ignoring <%s> constraint without "
75 PCMK_XA_ID, tag);
76 continue;
77 }
78
79 crm_trace("Unpacking %s constraint '%s'", tag, id);
80
81 lifetime = pcmk__xe_first_child(xml_obj, PCMK__XE_LIFETIME, NULL, NULL);
82 if (lifetime != NULL) {
83 pcmk__config_warn("Support for '" PCMK__XE_LIFETIME "' element "
84 "(in %s) is deprecated and will be dropped "
85 "in a later release", id);
86 }
87
88 if ((lifetime != NULL) && !evaluate_lifetime(lifetime, scheduler)) {
89 crm_info("Constraint %s %s is not active", tag, id);
90
91 } else if (pcmk__str_eq(PCMK_XE_RSC_ORDER, tag, pcmk__str_none)) {
92 pcmk__unpack_ordering(xml_obj, scheduler);
93
94 } else if (pcmk__str_eq(PCMK_XE_RSC_COLOCATION, tag, pcmk__str_none)) {
95 pcmk__unpack_colocation(xml_obj, scheduler);
96
97 } else if (pcmk__str_eq(PCMK_XE_RSC_LOCATION, tag, pcmk__str_none)) {
98 pcmk__unpack_location(xml_obj, scheduler);
99
100 } else if (pcmk__str_eq(PCMK_XE_RSC_TICKET, tag, pcmk__str_none)) {
101 pcmk__unpack_rsc_ticket(xml_obj, scheduler);
102
103 } else {
104 pcmk__config_err("Unsupported constraint type: %s", tag);
105 }
106 }
107 }
108
109 pcmk_resource_t *
110 pcmk__find_constraint_resource(GList *rsc_list, const char *id)
111 {
112 if (id == NULL) {
113 return NULL;
114 }
115 for (GList *iter = rsc_list; iter != NULL; iter = iter->next) {
116 pcmk_resource_t *parent = iter->data;
117 pcmk_resource_t *match = parent->fns->find_rsc(parent, id, NULL,
118 pcmk_rsc_match_history);
119
120 if (match != NULL) {
121 if (!pcmk__str_eq(match->id, id, pcmk__str_none)) {
122
123 match = uber_parent(match);
124 crm_debug("Found %s for %s", match->id, id);
125 }
126 return match;
127 }
128 }
129 crm_trace("No match for %s", id);
130 return NULL;
131 }
132
133
134
135
136
137
138
139
140
141
142
143
144 static bool
145 find_constraint_tag(const pcmk_scheduler_t *scheduler, const char *id,
146 pcmk_tag_t **tag)
147 {
148 *tag = NULL;
149
150
151 if (g_hash_table_lookup_extended(scheduler->template_rsc_sets, id,
152 NULL, (gpointer *) tag)) {
153 if (*tag == NULL) {
154 crm_notice("No resource is derived from template '%s'", id);
155 return false;
156 }
157 return true;
158 }
159
160
161 if (g_hash_table_lookup_extended(scheduler->tags, id,
162 NULL, (gpointer *) tag)) {
163 if (*tag == NULL) {
164 crm_notice("No resource is tagged with '%s'", id);
165 return false;
166 }
167 return true;
168 }
169
170 pcmk__config_warn("No resource, template, or tag named '%s'", id);
171 return false;
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 bool
188 pcmk__valid_resource_or_tag(const pcmk_scheduler_t *scheduler, const char *id,
189 pcmk_resource_t **rsc, pcmk_tag_t **tag)
190 {
191 if (rsc != NULL) {
192 *rsc = pcmk__find_constraint_resource(scheduler->resources, id);
193 if (*rsc != NULL) {
194 return true;
195 }
196 }
197
198 if ((tag != NULL) && find_constraint_tag(scheduler, id, tag)) {
199 return true;
200 }
201
202 return false;
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221 xmlNode *
222 pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
223 {
224 xmlNode *new_xml = NULL;
225 bool any_refs = false;
226
227
228 if (pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, NULL,
229 NULL) == NULL) {
230 return NULL;
231 }
232
233 new_xml = pcmk__xml_copy(NULL, xml_obj);
234
235 for (xmlNode *set = pcmk__xe_first_child(new_xml, PCMK_XE_RESOURCE_SET,
236 NULL, NULL);
237 set != NULL; set = pcmk__xe_next_same(set)) {
238
239 GList *tag_refs = NULL;
240 GList *iter = NULL;
241
242 for (xmlNode *xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF,
243 NULL, NULL);
244 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
245
246 pcmk_resource_t *rsc = NULL;
247 pcmk_tag_t *tag = NULL;
248
249 if (!pcmk__valid_resource_or_tag(scheduler, pcmk__xe_id(xml_rsc),
250 &rsc, &tag)) {
251 pcmk__config_err("Ignoring resource sets for constraint '%s' "
252 "because '%s' is not a valid resource or tag",
253 pcmk__xe_id(xml_obj), pcmk__xe_id(xml_rsc));
254 free_xml(new_xml);
255 return NULL;
256
257 } else if (rsc) {
258 continue;
259
260 } else if (tag) {
261
262
263
264 xmlNode *last_ref = xml_rsc;
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 for (iter = tag->refs; iter != NULL; iter = iter->next) {
286 const char *obj_ref = iter->data;
287 xmlNode *new_rsc_ref = NULL;
288
289 new_rsc_ref = xmlNewDocRawNode(set->doc, NULL,
290 (pcmkXmlStr)
291 PCMK_XE_RESOURCE_REF,
292 NULL);
293 crm_xml_add(new_rsc_ref, PCMK_XA_ID, obj_ref);
294 xmlAddNextSibling(last_ref, new_rsc_ref);
295
296 last_ref = new_rsc_ref;
297 }
298
299 any_refs = true;
300
301
302
303
304 tag_refs = g_list_append(tag_refs, xml_rsc);
305 }
306 }
307
308
309
310
311
312
313
314
315
316
317
318 for (iter = tag_refs; iter != NULL; iter = iter->next) {
319 xmlNode *tag_ref = iter->data;
320
321 free_xml(tag_ref);
322 }
323 g_list_free(tag_refs);
324 }
325
326 if (!any_refs) {
327 free_xml(new_xml);
328 new_xml = NULL;
329 }
330 return new_xml;
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344 bool
345 pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr,
346 bool convert_rsc, const pcmk_scheduler_t *scheduler)
347 {
348 const char *cons_id = NULL;
349 const char *id = NULL;
350
351 pcmk_resource_t *rsc = NULL;
352 pcmk_tag_t *tag = NULL;
353
354 *rsc_set = NULL;
355
356 CRM_CHECK((xml_obj != NULL) && (attr != NULL), return false);
357
358 cons_id = pcmk__xe_id(xml_obj);
359 if (cons_id == NULL) {
360 pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
361 xml_obj->name);
362 return false;
363 }
364
365 id = crm_element_value(xml_obj, attr);
366 if (id == NULL) {
367 return true;
368 }
369
370 if (!pcmk__valid_resource_or_tag(scheduler, id, &rsc, &tag)) {
371 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
372 "valid resource or tag", cons_id, id);
373 return false;
374
375 } else if (tag) {
376
377
378
379
380 *rsc_set = pcmk__xe_create(xml_obj, PCMK_XE_RESOURCE_SET);
381 crm_xml_add(*rsc_set, PCMK_XA_ID, id);
382
383 for (GList *iter = tag->refs; iter != NULL; iter = iter->next) {
384 const char *obj_ref = iter->data;
385 xmlNode *rsc_ref = NULL;
386
387 rsc_ref = pcmk__xe_create(*rsc_set, PCMK_XE_RESOURCE_REF);
388 crm_xml_add(rsc_ref, PCMK_XA_ID, obj_ref);
389 }
390
391
392 pcmk__xe_set_bool_attr(*rsc_set, PCMK_XA_SEQUENTIAL, false);
393
394 } else if ((rsc != NULL) && convert_rsc) {
395
396
397
398
399 xmlNode *rsc_ref = NULL;
400
401 *rsc_set = pcmk__xe_create(xml_obj, PCMK_XE_RESOURCE_SET);
402 crm_xml_add(*rsc_set, PCMK_XA_ID, id);
403
404 rsc_ref = pcmk__xe_create(*rsc_set, PCMK_XE_RESOURCE_REF);
405 crm_xml_add(rsc_ref, PCMK_XA_ID, id);
406
407 } else {
408 return true;
409 }
410
411
412 if (*rsc_set != NULL) {
413 pcmk__xe_remove_attr(xml_obj, attr);
414 }
415
416 return true;
417 }
418
419
420
421
422
423
424
425 void
426 pcmk__create_internal_constraints(pcmk_scheduler_t *scheduler)
427 {
428 crm_trace("Create internal constraints");
429 for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
430 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
431
432 rsc->cmds->internal_constraints(rsc);
433 }
434 }