pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_constraints.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2023 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, pcmk_scheduler_t *scheduler)
32{
33 bool result = FALSE;
34 crm_time_t *next_change = crm_time_new_undefined();
35
36 result = pe_evaluate_rules(lifetime, NULL, scheduler->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
40 pe__update_recheck_time(recheck, scheduler, "constraint lifetime");
41 }
42 crm_time_free(next_change);
43 return result;
44}
45
55void
57{
58 xmlNode *xml_constraints = pcmk_find_cib_element(scheduler->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 = (const char *) xml_obj->name;
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 descendants of the "
81 "constraint object)", id);
82 }
83
84 if ((lifetime != NULL) && !evaluate_lifetime(lifetime, scheduler)) {
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_none)) {
89
90 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_DEPEND, tag, pcmk__str_none)) {
92
93 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_LOCATION, tag,
96
97 } else if (pcmk__str_eq(XML_CONS_TAG_RSC_TICKET, tag, pcmk__str_none)) {
99
100 } else {
101 pe_err("Unsupported constraint type: %s", tag);
102 }
103 }
104}
105
107pcmk__find_constraint_resource(GList *rsc_list, const char *id)
108{
109 if (id == NULL) {
110 return NULL;
111 }
112 for (GList *iter = rsc_list; iter != NULL; iter = iter->next) {
113 pcmk_resource_t *parent = iter->data;
114 pcmk_resource_t *match = parent->fns->find_rsc(parent, id, NULL,
116
117 if (match != NULL) {
118 if (!pcmk__str_eq(match->id, id, pcmk__str_none)) {
119 /* We found an instance of a clone instead */
120 match = uber_parent(match);
121 crm_debug("Found %s for %s", match->id, id);
122 }
123 return match;
124 }
125 }
126 crm_trace("No match for %s", id);
127 return NULL;
128}
129
141static bool
142find_constraint_tag(const pcmk_scheduler_t *scheduler, const char *id,
143 pcmk_tag_t **tag)
144{
145 *tag = NULL;
146
147 // Check whether id refers to a resource set template
148 if (g_hash_table_lookup_extended(scheduler->template_rsc_sets, id,
149 NULL, (gpointer *) tag)) {
150 if (*tag == NULL) {
151 crm_warn("No resource is derived from template '%s'", id);
152 return false;
153 }
154 return true;
155 }
156
157 // If not, check whether id refers to a tag
158 if (g_hash_table_lookup_extended(scheduler->tags, id,
159 NULL, (gpointer *) tag)) {
160 if (*tag == NULL) {
161 crm_warn("No resource is tagged with '%s'", id);
162 return false;
163 }
164 return true;
165 }
166
167 crm_warn("No template or tag named '%s'", id);
168 return false;
169}
170
184bool
186 pcmk_resource_t **rsc, pcmk_tag_t **tag)
187{
188 if (rsc != NULL) {
190 if (*rsc != NULL) {
191 return true;
192 }
193 }
194
195 if ((tag != NULL) && find_constraint_tag(scheduler, id, tag)) {
196 return true;
197 }
198
199 return false;
200}
201
216xmlNode *
218{
219 xmlNode *new_xml = NULL;
220 bool any_refs = false;
221
222 // Short-circuit if there are no sets
223 if (first_named_child(xml_obj, XML_CONS_TAG_RSC_SET) == NULL) {
224 return NULL;
225 }
226
227 new_xml = copy_xml(xml_obj);
228
229 for (xmlNode *set = first_named_child(new_xml, XML_CONS_TAG_RSC_SET);
230 set != NULL; set = crm_next_same_xml(set)) {
231
232 GList *tag_refs = NULL;
233 GList *iter = NULL;
234
235 for (xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
236 xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
237
238 pcmk_resource_t *rsc = NULL;
239 pcmk_tag_t *tag = NULL;
240
241 if (!pcmk__valid_resource_or_tag(scheduler, ID(xml_rsc), &rsc,
242 &tag)) {
243 pcmk__config_err("Ignoring resource sets for constraint '%s' "
244 "because '%s' is not a valid resource or tag",
245 ID(xml_obj), ID(xml_rsc));
246 free_xml(new_xml);
247 return NULL;
248
249 } else if (rsc) {
250 continue;
251
252 } else if (tag) {
253 // resource_ref under resource_set references template or tag
254 xmlNode *last_ref = xml_rsc;
255
256 /* For example, given the original XML:
257 *
258 * <resource_set id="tag1-colocation-0" sequential="true">
259 * <resource_ref id="rsc1"/>
260 * <resource_ref id="tag1"/>
261 * <resource_ref id="rsc4"/>
262 * </resource_set>
263 *
264 * If rsc2 and rsc3 are tagged with tag1, we add them after it:
265 *
266 * <resource_set id="tag1-colocation-0" sequential="true">
267 * <resource_ref id="rsc1"/>
268 * <resource_ref id="tag1"/>
269 * <resource_ref id="rsc2"/>
270 * <resource_ref id="rsc3"/>
271 * <resource_ref id="rsc4"/>
272 * </resource_set>
273 */
274
275 for (iter = tag->refs; iter != NULL; iter = iter->next) {
276 const char *obj_ref = iter->data;
277 xmlNode *new_rsc_ref = NULL;
278
279 new_rsc_ref = xmlNewDocRawNode(set->doc, NULL,
280 (pcmkXmlStr)
282 NULL);
283 crm_xml_add(new_rsc_ref, XML_ATTR_ID, obj_ref);
284 xmlAddNextSibling(last_ref, new_rsc_ref);
285
286 last_ref = new_rsc_ref;
287 }
288
289 any_refs = true;
290
291 /* Freeing the resource_ref now would break the XML child
292 * iteration, so just remember it for freeing later.
293 */
294 tag_refs = g_list_append(tag_refs, xml_rsc);
295 }
296 }
297
298 /* Now free '<resource_ref id="tag1"/>', and finally get:
299
300 <resource_set id="tag1-colocation-0" sequential="true">
301 <resource_ref id="rsc1"/>
302 <resource_ref id="rsc2"/>
303 <resource_ref id="rsc3"/>
304 <resource_ref id="rsc4"/>
305 </resource_set>
306
307 */
308 for (iter = tag_refs; iter != NULL; iter = iter->next) {
309 xmlNode *tag_ref = iter->data;
310
311 free_xml(tag_ref);
312 }
313 g_list_free(tag_refs);
314 }
315
316 if (!any_refs) {
317 free_xml(new_xml);
318 new_xml = NULL;
319 }
320 return new_xml;
321}
322
334bool
335pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr,
336 bool convert_rsc, const pcmk_scheduler_t *scheduler)
337{
338 const char *cons_id = NULL;
339 const char *id = NULL;
340
341 pcmk_resource_t *rsc = NULL;
342 pcmk_tag_t *tag = NULL;
343
344 *rsc_set = NULL;
345
346 CRM_CHECK((xml_obj != NULL) && (attr != NULL), return false);
347
348 cons_id = ID(xml_obj);
349 if (cons_id == NULL) {
350 pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
351 xml_obj->name);
352 return false;
353 }
354
355 id = crm_element_value(xml_obj, attr);
356 if (id == NULL) {
357 return true;
358 }
359
360 if (!pcmk__valid_resource_or_tag(scheduler, id, &rsc, &tag)) {
361 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
362 "valid resource or tag", cons_id, id);
363 return false;
364
365 } else if (tag) {
366 /* The "attr" attribute (for a resource in a constraint) specifies a
367 * template or tag. Add the corresponding resource_set containing the
368 * resources derived from or tagged with it.
369 */
370 *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
371 crm_xml_add(*rsc_set, XML_ATTR_ID, id);
372
373 for (GList *iter = tag->refs; iter != NULL; iter = iter->next) {
374 const char *obj_ref = iter->data;
375 xmlNode *rsc_ref = NULL;
376
377 rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
378 crm_xml_add(rsc_ref, XML_ATTR_ID, obj_ref);
379 }
380
381 /* Set sequential="false" for the resource_set */
382 pcmk__xe_set_bool_attr(*rsc_set, "sequential", false);
383
384 } else if ((rsc != NULL) && convert_rsc) {
385 /* Even if a regular resource is referenced by "attr", convert it into a
386 * resource_set, because the other resource reference in the constraint
387 * could be a template or tag.
388 */
389 xmlNode *rsc_ref = NULL;
390
391 *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
392 crm_xml_add(*rsc_set, XML_ATTR_ID, id);
393
394 rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
395 crm_xml_add(rsc_ref, XML_ATTR_ID, id);
396
397 } else {
398 return true;
399 }
400
401 /* Remove the "attr" attribute referencing the template/tag */
402 if (*rsc_set != NULL) {
403 xml_remove_prop(xml_obj, attr);
404 }
405
406 return true;
407}
408
415void
417{
418 crm_trace("Create internal constraints");
419 for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
420 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
421
422 rsc->cmds->internal_constraints(rsc);
423 }
424}
const char * parent
Definition cib.c:27
Cluster Configuration.
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition cib.c:172
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition nvpair.c:872
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition complex.c:936
A dumping ground.
ISO_8601 Date handling.
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition iso8601.c:359
void crm_time_free(crm_time_t *dt)
Definition iso8601.c:150
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition iso8601.c:142
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition iso8601.c:126
struct crm_time_s crm_time_t
Definition iso8601.h:32
G_GNUC_INTERNAL void pcmk__unpack_ordering(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL void pcmk__unpack_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL void pcmk__unpack_colocation(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL void pcmk__unpack_rsc_ticket(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
#define crm_info(fmt, args...)
Definition logging.h:382
#define crm_warn(fmt, args...)
Definition logging.h:380
#define CRM_CHECK(expr, failure_action)
Definition logging.h:238
#define crm_debug(fmt, args...)
Definition logging.h:384
#define crm_trace(fmt, args...)
Definition logging.h:385
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
#define XML_TAG_RESOURCE_REF
Definition msg_xml.h:234
#define ID(x)
Definition msg_xml.h:474
#define XML_CONS_TAG_RSC_LOCATION
Definition msg_xml.h:355
#define XML_CONS_TAG_RSC_TICKET
Definition msg_xml.h:356
#define XML_CONS_TAG_RSC_DEPEND
Definition msg_xml.h:353
#define XML_CONS_TAG_RSC_SET
Definition msg_xml.h:357
#define XML_CONS_TAG_RSC_ORDER
Definition msg_xml.h:354
#define XML_ATTR_ID
Definition msg_xml.h:156
#define XML_CIB_TAG_CONSTRAINTS
Definition msg_xml.h:207
pcmk_scheduler_t * scheduler
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:447
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:302
pcmk__action_result_t result
Definition pcmk_fence.c:35
pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
bool pcmk__valid_resource_or_tag(const pcmk_scheduler_t *scheduler, const char *id, pcmk_resource_t **rsc, pcmk_tag_t **tag)
void pcmk__unpack_constraints(pcmk_scheduler_t *scheduler)
void pcmk__create_internal_constraints(pcmk_scheduler_t *scheduler)
bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, const pcmk_scheduler_t *scheduler)
void pe__update_recheck_time(time_t recheck, pcmk_scheduler_t *scheduler, const char *reason)
Definition utils.c:682
#define pe_err(fmt...)
Definition internal.h:39
@ pcmk_rsc_match_history
Also match clone instance ID from resource history.
Definition resources.h:199
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_none
Implementation of pcmk_resource_t.
Definition resources.h:399
pcmk_assignment_methods_t * cmds
Resource assignment methods.
Definition resources.h:417
pcmk_rsc_methods_t * fns
Resource object methods.
Definition resources.h:416
char * id
Resource ID in configuration.
Definition resources.h:400
Configuration tag object.
Definition tags.h:26
GList * refs
XML IDs of objects that reference the tag.
Definition tags.h:28
Implementation of pcmk_scheduler_t.
Definition scheduler.h:172
GHashTable * tags
Configuration tags (ID -> pcmk_tag_t *)
Definition scheduler.h:218
GHashTable * template_rsc_sets
Mappings of template ID to resource ID.
Definition scheduler.h:213
xmlNode * input
CIB XML.
Definition scheduler.h:175
GList * resources
Resources in cluster.
Definition scheduler.h:196
crm_time_t * now
Current time for evaluation purposes.
Definition scheduler.h:176
void(* internal_constraints)(pcmk_resource_t *rsc)
pcmk_resource_t *(* find_rsc)(pcmk_resource_t *rsc, const char *search, const pcmk_node_t *node, int flags)
Search for a resource ID in a resource and its children.
Definition resources.h:287
Wrappers for and extensions to libxml2.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2484
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:2510
void free_xml(xmlNode *child)
Definition xml.c:783
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:789
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:638
void xml_remove_prop(xmlNode *obj, const char *name)
Definition xml.c:1696