pacemaker 2.1.8-2.1.8
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-2024 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/common/xml.h>
22#include <crm/common/iso8601.h>
23#include <crm/pengine/status.h>
25#include <crm/pengine/rules.h>
26#include <pacemaker-internal.h>
28
29static bool
30evaluate_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
59void
61{
62 xmlNode *xml_constraints = pcmk_find_cib_element(scheduler->input,
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)) {
93
94 } else if (pcmk__str_eq(PCMK_XE_RSC_COLOCATION, tag, pcmk__str_none)) {
96
97 } else if (pcmk__str_eq(PCMK_XE_RSC_LOCATION, tag, pcmk__str_none)) {
99
100 } else if (pcmk__str_eq(PCMK_XE_RSC_TICKET, tag, pcmk__str_none)) {
102
103 } else {
104 pcmk__config_err("Unsupported constraint type: %s", tag);
105 }
106 }
107}
108
110pcmk__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,
119
120 if (match != NULL) {
121 if (!pcmk__str_eq(match->id, id, pcmk__str_none)) {
122 /* We found an instance of a clone instead */
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
144static bool
145find_constraint_tag(const pcmk_scheduler_t *scheduler, const char *id,
146 pcmk_tag_t **tag)
147{
148 *tag = NULL;
149
150 // Check whether id refers to a resource set template
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 // If not, check whether id refers to a tag
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
187bool
189 pcmk_resource_t **rsc, pcmk_tag_t **tag)
190{
191 if (rsc != NULL) {
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
221xmlNode *
223{
224 xmlNode *new_xml = NULL;
225 bool any_refs = false;
226
227 // Short-circuit if there are no sets
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 /* PCMK_XE_RESOURCE_REF under PCMK_XE_RESOURCE_SET references
262 * template or tag
263 */
264 xmlNode *last_ref = xml_rsc;
265
266 /* For example, given the original XML:
267 *
268 * <resource_set id="tag1-colocation-0" sequential="true">
269 * <resource_ref id="rsc1"/>
270 * <resource_ref id="tag1"/>
271 * <resource_ref id="rsc4"/>
272 * </resource_set>
273 *
274 * If rsc2 and rsc3 are tagged with tag1, we add them after it:
275 *
276 * <resource_set id="tag1-colocation-0" sequential="true">
277 * <resource_ref id="rsc1"/>
278 * <resource_ref id="tag1"/>
279 * <resource_ref id="rsc2"/>
280 * <resource_ref id="rsc3"/>
281 * <resource_ref id="rsc4"/>
282 * </resource_set>
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)
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 /* Freeing the resource_ref now would break the XML child
302 * iteration, so just remember it for freeing later.
303 */
304 tag_refs = g_list_append(tag_refs, xml_rsc);
305 }
306 }
307
308 /* Now free '<resource_ref id="tag1"/>', and finally get:
309
310 <resource_set id="tag1-colocation-0" sequential="true">
311 <resource_ref id="rsc1"/>
312 <resource_ref id="rsc2"/>
313 <resource_ref id="rsc3"/>
314 <resource_ref id="rsc4"/>
315 </resource_set>
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
344bool
345pcmk__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 /* The "attr" attribute (for a resource in a constraint) specifies a
377 * template or tag. Add the corresponding PCMK_XE_RESOURCE_SET
378 * containing the resources derived from or tagged with it.
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 // Set PCMK_XA_SEQUENTIAL=PCMK_VALUE_FALSE for the PCMK_XE_RESOURCE_SET
393
394 } else if ((rsc != NULL) && convert_rsc) {
395 /* Even if a regular resource is referenced by "attr", convert it into a
396 * PCMK_XE_RESOURCE_SET, because the other resource reference in the
397 * constraint could be a template or tag.
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 /* Remove the "attr" attribute referencing the template/tag */
412 if (*rsc_set != NULL) {
413 pcmk__xe_remove_attr(xml_obj, attr);
414 }
415
416 return true;
417}
418
425void
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}
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:903
int pcmk__evaluate_rules(xmlNode *xml, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
Definition rules.c:1486
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition complex.c:1007
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:129
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:397
#define crm_notice(fmt, args...)
Definition logging.h:395
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_trace(fmt, args...)
Definition logging.h:402
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
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:446
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:301
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:694
@ pcmk_rsc_match_history
Also match clone instance ID from resource history.
Definition resources.h:185
@ pcmk_rc_ok
Definition results.h:162
Cluster status and scheduling.
@ pcmk__str_none
Data used to evaluate a rule (any NULL items are ignored)
Definition rules.h:57
const crm_time_t * now
Current time for rule evaluation purposes.
Definition rules.h:59
pcmk_assignment_methods_t * cmds
Definition resources.h:413
pcmk_rsc_methods_t * fns
Definition resources.h:412
GList * refs
Definition tags.h:31
GHashTable * tags
Definition scheduler.h:253
GHashTable * template_rsc_sets
Definition scheduler.h:248
xmlNode * input
Definition scheduler.h:196
GList * resources
Definition scheduler.h:231
crm_time_t * now
Definition scheduler.h:198
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)
Definition resources.h:276
Wrappers for and extensions to libxml2.
const xmlChar * pcmkXmlStr
Definition xml.h:41
void free_xml(xmlNode *child)
Definition xml.c:867
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
Definition xml.c:652
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:883
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition xml.c:2108
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
#define PCMK_XE_CONSTRAINTS
Definition xml_names.h:89
#define PCMK_XE_RSC_TICKET
Definition xml_names.h:186
#define PCMK_XE_RESOURCE_REF
Definition xml_names.h:173
#define PCMK_XE_RSC_ORDER
Definition xml_names.h:185
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XE_RSC_COLOCATION
Definition xml_names.h:181
#define PCMK_XE_RESOURCE_SET
Definition xml_names.h:174
#define PCMK_XE_RSC_LOCATION
Definition xml_names.h:184
#define PCMK_XA_SEQUENTIAL
Definition xml_names.h:393
#define PCMK__XE_LIFETIME