pacemaker 3.0.1-16e74fc4da
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>
21#include <crm/common/xml.h>
23#include <crm/common/iso8601.h>
24#include <crm/pengine/status.h>
26#include <pacemaker-internal.h>
28
38void
40{
41 xmlNode *xml_constraints = pcmk_find_cib_element(scheduler->input,
43
44 for (xmlNode *xml_obj = pcmk__xe_first_child(xml_constraints, NULL, NULL,
45 NULL);
46 xml_obj != NULL; xml_obj = pcmk__xe_next(xml_obj, NULL)) {
47
48 const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
49 const char *tag = (const char *) xml_obj->name;
50
51 if (id == NULL) {
52 pcmk__config_err("Ignoring <%s> constraint without "
53 PCMK_XA_ID, tag);
54 continue;
55 }
56
57 crm_trace("Unpacking %s constraint '%s'", tag, id);
58
59 if (pcmk__str_eq(PCMK_XE_RSC_ORDER, tag, pcmk__str_none)) {
61
62 } else if (pcmk__str_eq(PCMK_XE_RSC_COLOCATION, tag, pcmk__str_none)) {
64
65 } else if (pcmk__str_eq(PCMK_XE_RSC_LOCATION, tag, pcmk__str_none)) {
67
68 } else if (pcmk__str_eq(PCMK_XE_RSC_TICKET, tag, pcmk__str_none)) {
70
71 } else {
72 pcmk__config_err("Unsupported constraint type: %s", tag);
73 }
74 }
75}
76
78pcmk__find_constraint_resource(GList *rsc_list, const char *id)
79{
80 if (id == NULL) {
81 return NULL;
82 }
83 for (GList *iter = rsc_list; iter != NULL; iter = iter->next) {
84 pcmk_resource_t *parent = iter->data;
85 pcmk_resource_t *match = NULL;
86
87 match = parent->priv->fns->find_rsc(parent, id, NULL,
89 if (match != NULL) {
90 if (!pcmk__str_eq(match->id, id, pcmk__str_none)) {
91 /* We found an instance of a clone instead */
92 match = uber_parent(match);
93 crm_debug("Found %s for %s", match->id, id);
94 }
95 return match;
96 }
97 }
98 crm_trace("No match for %s", id);
99 return NULL;
100}
101
113static bool
114find_constraint_tag(const pcmk_scheduler_t *scheduler, const char *id,
115 pcmk__idref_t **tag)
116{
117 *tag = NULL;
118
119 // Check whether id refers to a resource set template
120 if (g_hash_table_lookup_extended(scheduler->priv->templates, id,
121 NULL, (gpointer *) tag)) {
122 if (*tag == NULL) {
123 crm_notice("No resource is derived from template '%s'", id);
124 return false;
125 }
126 return true;
127 }
128
129 // If not, check whether id refers to a tag
130 if (g_hash_table_lookup_extended(scheduler->priv->tags, id,
131 NULL, (gpointer *) tag)) {
132 if (*tag == NULL) {
133 crm_notice("No resource is tagged with '%s'", id);
134 return false;
135 }
136 return true;
137 }
138
139 pcmk__config_warn("No resource, template, or tag named '%s'", id);
140 return false;
141}
142
157int
158pcmk__parse_constraint_role(const char *id, const char *role_spec,
159 enum rsc_role_e *role)
160{
161 *role = pcmk_parse_role(role_spec);
162 switch (*role) {
164 if (role_spec != NULL) {
165 pcmk__config_err("Ignoring constraint %s: Invalid role '%s'",
166 id, role_spec);
168 }
169 break;
170
172 *role = pcmk_role_unknown;
173 break;
174
175 default:
176 break;
177 }
178 return pcmk_rc_ok;
179}
180
194bool
196 pcmk_resource_t **rsc, pcmk__idref_t **tag)
197{
198 if (rsc != NULL) {
200 if (*rsc != NULL) {
201 return true;
202 }
203 }
204
205 if ((tag != NULL) && find_constraint_tag(scheduler, id, tag)) {
206 return true;
207 }
208
209 return false;
210}
211
229xmlNode *
231{
232 xmlNode *new_xml = NULL;
233 bool any_refs = false;
234
235 // Short-circuit if there are no sets
237 NULL) == NULL) {
238 return NULL;
239 }
240
241 new_xml = pcmk__xml_copy(NULL, xml_obj);
242
243 for (xmlNode *set = pcmk__xe_first_child(new_xml, PCMK_XE_RESOURCE_SET,
244 NULL, NULL);
245 set != NULL; set = pcmk__xe_next(set, PCMK_XE_RESOURCE_SET)) {
246
247 GList *tag_refs = NULL;
248 GList *iter = NULL;
249
250 for (xmlNode *xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF,
251 NULL, NULL);
252 xml_rsc != NULL;
253 xml_rsc = pcmk__xe_next(xml_rsc, PCMK_XE_RESOURCE_REF)) {
254
255 pcmk_resource_t *rsc = NULL;
256 pcmk__idref_t *tag = NULL;
257
258 if (!pcmk__valid_resource_or_tag(scheduler, pcmk__xe_id(xml_rsc),
259 &rsc, &tag)) {
260 pcmk__config_err("Ignoring resource sets for constraint '%s' "
261 "because '%s' is not a valid resource or tag",
262 pcmk__xe_id(xml_obj), pcmk__xe_id(xml_rsc));
263 pcmk__xml_free(new_xml);
264 return NULL;
265
266 } else if (rsc) {
267 continue;
268
269 } else if (tag) {
270 /* PCMK_XE_RESOURCE_REF under PCMK_XE_RESOURCE_SET references
271 * template or tag
272 */
273 xmlNode *last_ref = xml_rsc;
274
275 /* For example, given the original XML:
276 *
277 * <resource_set id="tag1-colocation-0" sequential="true">
278 * <resource_ref id="rsc1"/>
279 * <resource_ref id="tag1"/>
280 * <resource_ref id="rsc4"/>
281 * </resource_set>
282 *
283 * If rsc2 and rsc3 are tagged with tag1, we add them after it:
284 *
285 * <resource_set id="tag1-colocation-0" sequential="true">
286 * <resource_ref id="rsc1"/>
287 * <resource_ref id="tag1"/>
288 * <resource_ref id="rsc2"/>
289 * <resource_ref id="rsc3"/>
290 * <resource_ref id="rsc4"/>
291 * </resource_set>
292 */
293
294 for (iter = tag->refs; iter != NULL; iter = iter->next) {
295 const char *ref_id = iter->data;
296 xmlNode *new_ref = pcmk__xe_create(set,
298
299 crm_xml_add(new_ref, PCMK_XA_ID, ref_id);
300 xmlAddNextSibling(last_ref, new_ref);
301
302 last_ref = new_ref;
303 }
304
305 any_refs = true;
306
307 /* Freeing the resource_ref now would break the XML child
308 * iteration, so just remember it for freeing later.
309 */
310 tag_refs = g_list_append(tag_refs, xml_rsc);
311 }
312 }
313
314 /* Now free '<resource_ref id="tag1"/>', and finally get:
315
316 <resource_set id="tag1-colocation-0" sequential="true">
317 <resource_ref id="rsc1"/>
318 <resource_ref id="rsc2"/>
319 <resource_ref id="rsc3"/>
320 <resource_ref id="rsc4"/>
321 </resource_set>
322
323 */
324 for (iter = tag_refs; iter != NULL; iter = iter->next) {
325 xmlNode *tag_ref = iter->data;
326
327 pcmk__xml_free(tag_ref);
328 }
329 g_list_free(tag_refs);
330 }
331
332 if (!any_refs) {
333 pcmk__xml_free(new_xml);
334 new_xml = NULL;
335 }
336 return new_xml;
337}
338
350bool
351pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr,
352 bool convert_rsc, const pcmk_scheduler_t *scheduler)
353{
354 const char *cons_id = NULL;
355 const char *id = NULL;
356
357 pcmk_resource_t *rsc = NULL;
358 pcmk__idref_t *tag = NULL;
359
360 *rsc_set = NULL;
361
362 CRM_CHECK((xml_obj != NULL) && (attr != NULL), return false);
363
364 cons_id = pcmk__xe_id(xml_obj);
365 if (cons_id == NULL) {
366 pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
367 xml_obj->name);
368 return false;
369 }
370
371 id = crm_element_value(xml_obj, attr);
372 if (id == NULL) {
373 return true;
374 }
375
376 if (!pcmk__valid_resource_or_tag(scheduler, id, &rsc, &tag)) {
377 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
378 "valid resource or tag", cons_id, id);
379 return false;
380
381 } else if (tag) {
382 /* The "attr" attribute (for a resource in a constraint) specifies a
383 * template or tag. Add the corresponding PCMK_XE_RESOURCE_SET
384 * containing the resources derived from or tagged with it.
385 */
386 *rsc_set = pcmk__xe_create(xml_obj, PCMK_XE_RESOURCE_SET);
387 crm_xml_add(*rsc_set, PCMK_XA_ID, id);
388
389 for (GList *iter = tag->refs; iter != NULL; iter = iter->next) {
390 const char *obj_ref = iter->data;
391 xmlNode *rsc_ref = NULL;
392
393 rsc_ref = pcmk__xe_create(*rsc_set, PCMK_XE_RESOURCE_REF);
394 crm_xml_add(rsc_ref, PCMK_XA_ID, obj_ref);
395 }
396
397 // Set PCMK_XA_SEQUENTIAL=PCMK_VALUE_FALSE for the PCMK_XE_RESOURCE_SET
399
400 } else if ((rsc != NULL) && convert_rsc) {
401 /* Even if a regular resource is referenced by "attr", convert it into a
402 * PCMK_XE_RESOURCE_SET, because the other resource reference in the
403 * constraint could be a template or tag.
404 */
405 xmlNode *rsc_ref = NULL;
406
407 *rsc_set = pcmk__xe_create(xml_obj, PCMK_XE_RESOURCE_SET);
408 crm_xml_add(*rsc_set, PCMK_XA_ID, id);
409
410 rsc_ref = pcmk__xe_create(*rsc_set, PCMK_XE_RESOURCE_REF);
411 crm_xml_add(rsc_ref, PCMK_XA_ID, id);
412
413 } else {
414 return true;
415 }
416
417 /* Remove the "attr" attribute referencing the template/tag */
418 if (*rsc_set != NULL) {
419 pcmk__xe_remove_attr(xml_obj, attr);
420 }
421
422 return true;
423}
424
431void
433{
434 crm_trace("Create internal constraints");
435 for (GList *iter = scheduler->priv->resources;
436 iter != NULL; iter = iter->next) {
437
438 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
439
440 rsc->priv->cmds->internal_constraints(rsc);
441 }
442}
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
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition complex.c:999
A dumping ground.
ISO_8601 Date handling.
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_notice(fmt, args...)
Definition logging.h:363
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define crm_debug(fmt, args...)
Definition logging.h:368
#define crm_trace(fmt, args...)
Definition logging.h:370
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
pcmk_scheduler_t * scheduler
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__idref_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)
int pcmk__parse_constraint_role(const char *id, const char *role_spec, enum rsc_role_e *role)
@ pcmk_rsc_match_history
Also match clone instance ID from resource history.
Definition resources.h:34
@ pcmk_rc_ok
Definition results.h:159
@ pcmk_rc_unpack_error
Definition results.h:122
enum rsc_role_e pcmk_parse_role(const char *role)
Parse a resource role from a string role specification.
Definition roles.c:51
rsc_role_e
Definition roles.h:34
@ pcmk_role_started
Started.
Definition roles.h:37
@ pcmk_role_unknown
Resource role is unknown.
Definition roles.h:35
Scheduler API.
Cluster status and scheduling.
@ pcmk__str_none
void(* internal_constraints)(pcmk_resource_t *rsc)
const pcmk__assignment_methods_t * cmds
const pcmk__rsc_methods_t * fns
pcmk__resource_private_t * priv
Definition resources.h:61
pcmk_resource_t *(* find_rsc)(pcmk_resource_t *rsc, const char *search, const pcmk_node_t *node, uint32_t flags)
pcmk__scheduler_private_t * priv
Definition scheduler.h:99
xmlNode * input
Definition scheduler.h:81
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:832
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
#define PCMK_XE_CONSTRAINTS
Definition xml_names.h:89
#define PCMK_XE_RSC_TICKET
Definition xml_names.h:190
#define PCMK_XE_RESOURCE_REF
Definition xml_names.h:177
#define PCMK_XE_RSC_ORDER
Definition xml_names.h:189
#define PCMK_XA_ID
Definition xml_names.h:301
#define PCMK_XE_RSC_COLOCATION
Definition xml_names.h:185
#define PCMK_XE_RESOURCE_SET
Definition xml_names.h:178
#define PCMK_XE_RSC_LOCATION
Definition xml_names.h:188
#define PCMK_XA_SEQUENTIAL
Definition xml_names.h:398