pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pcmk_sched_constraints.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2021 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
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/msg_xml.h>
21#include <crm/common/xml.h>
23#include <crm/common/iso8601.h>
24#include <crm/pengine/status.h>
26#include <crm/pengine/rules.h>
27#include <pacemaker-internal.h>
29
30static bool
31evaluate_lifetime(xmlNode *lifetime, pe_working_set_t *data_set)
32{
33 bool result = FALSE;
34 crm_time_t *next_change = crm_time_new_undefined();
35
36 result = pe_evaluate_rules(lifetime, NULL, data_set->now, next_change);
37 if (crm_time_is_defined(next_change)) {
38 time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
39
41 }
42 crm_time_free(next_change);
43 return result;
44}
45
55void
57{
58 xmlNode *xml_constraints = pcmk_find_cib_element(data_set->input,
60
61 for (xmlNode *xml_obj = pcmk__xe_first_child(xml_constraints);
62 xml_obj != NULL; xml_obj = pcmk__xe_next(xml_obj)) {
63
64 xmlNode *lifetime = NULL;
65 const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
66 const char *tag = crm_element_name(xml_obj);
67
68 if (id == NULL) {
69 pcmk__config_err("Ignoring <%s> constraint without "
70 XML_ATTR_ID, tag);
71 continue;
72 }
73
74 crm_trace("Unpacking %s constraint '%s'", tag, id);
75
76 lifetime = first_named_child(xml_obj, "lifetime");
77 if (lifetime != NULL) {
78 pcmk__config_warn("Support for 'lifetime' attribute (in %s) is "
79 "deprecated (the rules it contains should "
80 "instead be direct descendents of the "
81 "constraint object)", id);
82 }
83
84 if ((lifetime != NULL) && !evaluate_lifetime(lifetime, data_set)) {
85 crm_info("Constraint %s %s is not active", tag, id);
86
87 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_ORDER, tag, pcmk__str_casei)) {
89
90 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_DEPEND, tag, pcmk__str_casei)) {
92
93 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_LOCATION, tag, pcmk__str_casei)) {
95
96 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_TICKET, tag, pcmk__str_casei)) {
98
99 } else {
100 pe_err("Unsupported constraint type: %s", tag);
101 }
102 }
103}
104
106pcmk__find_constraint_resource(GList *rsc_list, const char *id)
107{
108 GList *rIter = NULL;
109
110 for (rIter = rsc_list; id && rIter; rIter = rIter->next) {
111 pe_resource_t *parent = rIter->data;
112 pe_resource_t *match = parent->fns->find_rsc(parent, id, NULL,
114
115 if (match != NULL) {
116 if(!pcmk__str_eq(match->id, id, pcmk__str_casei)) {
117 /* We found an instance of a clone instead */
118 match = uber_parent(match);
119 crm_debug("Found %s for %s", match->id, id);
120 }
121 return match;
122 }
123 }
124 crm_trace("No match for %s", id);
125 return NULL;
126}
127
139static bool
140find_constraint_tag(pe_working_set_t *data_set, const char *id, pe_tag_t **tag)
141{
142 *tag = NULL;
143
144 // Check whether id refers to a resource set template
145 if (g_hash_table_lookup_extended(data_set->template_rsc_sets, id,
146 NULL, (gpointer *) tag)) {
147 if (*tag == NULL) {
148 crm_warn("No resource is derived from template '%s'", id);
149 return false;
150 }
151 return true;
152 }
153
154 // If not, check whether id refers to a tag
155 if (g_hash_table_lookup_extended(data_set->tags, id,
156 NULL, (gpointer *) tag)) {
157 if (*tag == NULL) {
158 crm_warn("No resource is tagged with '%s'", id);
159 return false;
160 }
161 return true;
162 }
163
164 crm_warn("No template or tag named '%s'", id);
165 return false;
166}
167
181bool
183 pe_resource_t **rsc, pe_tag_t **tag)
184{
185 if (rsc != NULL) {
187 if (*rsc != NULL) {
188 return true;
189 }
190 }
191
192 if ((tag != NULL) && find_constraint_tag(data_set, id, tag)) {
193 return true;
194 }
195
196 return false;
197}
198
213xmlNode *
215{
216 xmlNode *new_xml = NULL;
217 bool any_refs = false;
218
219 // Short-circuit if there are no sets
220 if (first_named_child(xml_obj, XML_CONS_TAG_RSC_SET) == NULL) {
221 return NULL;
222 }
223
224 new_xml = copy_xml(xml_obj);
225
226 for (xmlNode *set = first_named_child(new_xml, XML_CONS_TAG_RSC_SET);
227 set != NULL; set = crm_next_same_xml(set)) {
228
229 GList *tag_refs = NULL;
230 GList *gIter = NULL;
231
232 for (xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
233 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
234
235 pe_resource_t *rsc = NULL;
236 pe_tag_t *tag = NULL;
237
238 if (!pcmk__valid_resource_or_tag(data_set, ID(xml_rsc), &rsc,
239 &tag)) {
240 pcmk__config_err("Ignoring resource sets for constraint '%s' "
241 "because '%s' is not a valid resource or tag",
242 ID(xml_obj), ID(xml_rsc));
243 free_xml(new_xml);
244 return NULL;
245
246 } else if (rsc) {
247 continue;
248
249 } else if (tag) {
250 /* The resource_ref under the resource_set references a template/tag */
251 xmlNode *last_ref = xml_rsc;
252
253 /* A sample:
254
255 Original XML:
256
257 <resource_set id="tag1-colocation-0" sequential="true">
258 <resource_ref id="rsc1"/>
259 <resource_ref id="tag1"/>
260 <resource_ref id="rsc4"/>
261 </resource_set>
262
263 Now we are appending rsc2 and rsc3 which are tagged with tag1 right after it:
264
265 <resource_set id="tag1-colocation-0" sequential="true">
266 <resource_ref id="rsc1"/>
267 <resource_ref id="tag1"/>
268 <resource_ref id="rsc2"/>
269 <resource_ref id="rsc3"/>
270 <resource_ref id="rsc4"/>
271 </resource_set>
272
273 */
274
275 for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
276 const char *obj_ref = (const char *) gIter->data;
277 xmlNode *new_rsc_ref = NULL;
278
279 new_rsc_ref = xmlNewDocRawNode(getDocPtr(set), NULL,
281 crm_xml_add(new_rsc_ref, XML_ATTR_ID, obj_ref);
282 xmlAddNextSibling(last_ref, new_rsc_ref);
283
284 last_ref = new_rsc_ref;
285 }
286
287 any_refs = true;
288
289 /* Freeing the resource_ref now would break the XML child
290 * iteration, so just remember it for freeing later.
291 */
292 tag_refs = g_list_append(tag_refs, xml_rsc);
293 }
294 }
295
296 /* Now free '<resource_ref id="tag1"/>', and finally get:
297
298 <resource_set id="tag1-colocation-0" sequential="true">
299 <resource_ref id="rsc1"/>
300 <resource_ref id="rsc2"/>
301 <resource_ref id="rsc3"/>
302 <resource_ref id="rsc4"/>
303 </resource_set>
304
305 */
306 for (gIter = tag_refs; gIter != NULL; gIter = gIter->next) {
307 xmlNode *tag_ref = gIter->data;
308
309 free_xml(tag_ref);
310 }
311 g_list_free(tag_refs);
312 }
313
314 if (!any_refs) {
315 free_xml(new_xml);
316 new_xml = NULL;
317 }
318 return new_xml;
319}
320
331bool
332pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr,
333 bool convert_rsc, pe_working_set_t *data_set)
334{
335 const char *cons_id = NULL;
336 const char *id = NULL;
337
338 pe_resource_t *rsc = NULL;
339 pe_tag_t *tag = NULL;
340
341 *rsc_set = NULL;
342
343 CRM_CHECK((xml_obj != NULL) && (attr != NULL), return false);
344
345 cons_id = ID(xml_obj);
346 if (cons_id == NULL) {
347 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
348 crm_element_name(xml_obj));
349 return false;
350 }
351
352 id = crm_element_value(xml_obj, attr);
353 if (id == NULL) {
354 return true;
355 }
356
357 if (!pcmk__valid_resource_or_tag(data_set, id, &rsc, &tag)) {
358 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
359 "valid resource or tag", cons_id, id);
360 return false;
361
362 } else if (tag) {
363 GList *gIter = NULL;
364
365 /* A template/tag is referenced by the "attr" attribute (first, then, rsc or with-rsc).
366 Add the template/tag's corresponding "resource_set" which contains the resources derived
367 from it or tagged with it under the constraint. */
368 *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
369 crm_xml_add(*rsc_set, XML_ATTR_ID, id);
370
371 for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
372 const char *obj_ref = (const char *) gIter->data;
373 xmlNode *rsc_ref = NULL;
374
375 rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
376 crm_xml_add(rsc_ref, XML_ATTR_ID, obj_ref);
377 }
378
379 /* Set sequential="false" for the resource_set */
380 pcmk__xe_set_bool_attr(*rsc_set, "sequential", false);
381
382 } else if ((rsc != NULL) && convert_rsc) {
383 /* Even a regular resource is referenced by "attr", convert it into a resource_set.
384 Because the other side of the constraint could be a template/tag reference. */
385 xmlNode *rsc_ref = NULL;
386
387 *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
388 crm_xml_add(*rsc_set, XML_ATTR_ID, id);
389
390 rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
391 crm_xml_add(rsc_ref, XML_ATTR_ID, id);
392
393 } else {
394 return true;
395 }
396
397 /* Remove the "attr" attribute referencing the template/tag */
398 if (*rsc_set != NULL) {
399 xml_remove_prop(xml_obj, attr);
400 }
401
402 return true;
403}
404
411void
413{
414 crm_trace("Create internal constraints");
415 for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
416 pe_resource_t *rsc = (pe_resource_t *) iter->data;
417
418 rsc->cmds->internal_constraints(rsc);
419 }
420}
const char * parent
Definition: cib.c:25
Cluster Configuration.
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:153
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: nvpair.c:942
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:912
A dumping ground.
ISO_8601 Date handling.
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition: iso8601.c:352
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:132
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:116
struct crm_time_s crm_time_t
Definition: iso8601.h:32
G_GNUC_INTERNAL void pcmk__unpack_ordering(xmlNode *xml_obj, pe_working_set_t *data_set)
G_GNUC_INTERNAL void pcmk__unpack_colocation(xmlNode *xml_obj, pe_working_set_t *data_set)
G_GNUC_INTERNAL void pcmk__unpack_rsc_ticket(xmlNode *xml_obj, pe_working_set_t *data_set)
G_GNUC_INTERNAL void pcmk__unpack_location(xmlNode *xml_obj, pe_working_set_t *data_set)
#define crm_info(fmt, args...)
Definition: logging.h:362
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:216
#define ID(x)
Definition: msg_xml.h:468
#define XML_CONS_TAG_RSC_LOCATION
Definition: msg_xml.h:353
#define XML_CONS_TAG_RSC_TICKET
Definition: msg_xml.h:354
#define XML_CONS_TAG_RSC_DEPEND
Definition: msg_xml.h:351
#define XML_CONS_TAG_RSC_SET
Definition: msg_xml.h:355
#define XML_CONS_TAG_RSC_ORDER
Definition: msg_xml.h:352
#define XML_ATTR_ID
Definition: msg_xml.h:134
#define XML_CIB_TAG_CONSTRAINTS
Definition: msg_xml.h:189
pe_working_set_t * data_set
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
pcmk__action_result_t result
Definition: pcmk_fence.c:35
bool pcmk__valid_resource_or_tag(pe_working_set_t *data_set, const char *id, pe_resource_t **rsc, pe_tag_t **tag)
xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, pe_working_set_t *data_set)
void pcmk__unpack_constraints(pe_working_set_t *data_set)
bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, pe_working_set_t *data_set)
pe_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
void pcmk__create_internal_constraints(pe_working_set_t *data_set)
@ pe_find_renamed
match resource ID or LRM history ID
Definition: pe_types.h:85
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition: utils.c:703
#define pe_err(fmt...)
Definition: internal.h:49
gboolean pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now, crm_time_t *next_change)
Evaluate any rules contained by given XML element.
Definition: rules.c:39
Cluster status and scheduling.
@ pcmk__str_casei
char * id
Definition: pe_types.h:329
resource_alloc_functions_t * cmds
Definition: pe_types.h:341
GList * refs
Definition: pe_types.h:462
GHashTable * tags
Definition: pe_types.h:187
GHashTable * template_rsc_sets
Definition: pe_types.h:185
xmlNode * input
Definition: pe_types.h:144
GList * resources
Definition: pe_types.h:165
crm_time_t * now
Definition: pe_types.h:145
void(* internal_constraints)(pe_resource_t *rsc)
Wrappers for and extensions to libxml2.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
const xmlChar * pcmkXmlStr
Definition: xml.h:50
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956
xmlDoc * getDocPtr(xmlNode *node)
Definition: xml.c:711
void free_xml(xmlNode *child)
Definition: xml.c:885
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:891
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:2145