pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
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>
25 #include <crm/pengine/internal.h>
26 #include <crm/pengine/rules.h>
27 #include <pacemaker-internal.h>
28 #include "libpacemaker_private.h"
29 
30 static bool
31 evaluate_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 
55 void
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 descendants 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 
106 pcmk__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 
139 static bool
140 find_constraint_tag(const pe_working_set_t *data_set, const char *id,
141  pe_tag_t **tag)
142 {
143  *tag = NULL;
144 
145  // Check whether id refers to a resource set template
146  if (g_hash_table_lookup_extended(data_set->template_rsc_sets, id,
147  NULL, (gpointer *) tag)) {
148  if (*tag == NULL) {
149  crm_warn("No resource is derived from template '%s'", id);
150  return false;
151  }
152  return true;
153  }
154 
155  // If not, check whether id refers to a tag
156  if (g_hash_table_lookup_extended(data_set->tags, id,
157  NULL, (gpointer *) tag)) {
158  if (*tag == NULL) {
159  crm_warn("No resource is tagged with '%s'", id);
160  return false;
161  }
162  return true;
163  }
164 
165  crm_warn("No template or tag named '%s'", id);
166  return false;
167 }
168 
182 bool
184  pe_resource_t **rsc, pe_tag_t **tag)
185 {
186  if (rsc != NULL) {
188  if (*rsc != NULL) {
189  return true;
190  }
191  }
192 
193  if ((tag != NULL) && find_constraint_tag(data_set, id, tag)) {
194  return true;
195  }
196 
197  return false;
198 }
199 
214 xmlNode *
216 {
217  xmlNode *new_xml = NULL;
218  bool any_refs = false;
219 
220  // Short-circuit if there are no sets
221  if (first_named_child(xml_obj, XML_CONS_TAG_RSC_SET) == NULL) {
222  return NULL;
223  }
224 
225  new_xml = copy_xml(xml_obj);
226 
227  for (xmlNode *set = first_named_child(new_xml, XML_CONS_TAG_RSC_SET);
228  set != NULL; set = crm_next_same_xml(set)) {
229 
230  GList *tag_refs = NULL;
231  GList *gIter = NULL;
232 
233  for (xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
234  xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
235 
236  pe_resource_t *rsc = NULL;
237  pe_tag_t *tag = NULL;
238 
239  if (!pcmk__valid_resource_or_tag(data_set, ID(xml_rsc), &rsc,
240  &tag)) {
241  pcmk__config_err("Ignoring resource sets for constraint '%s' "
242  "because '%s' is not a valid resource or tag",
243  ID(xml_obj), ID(xml_rsc));
244  free_xml(new_xml);
245  return NULL;
246 
247  } else if (rsc) {
248  continue;
249 
250  } else if (tag) {
251  /* The resource_ref under the resource_set references a template/tag */
252  xmlNode *last_ref = xml_rsc;
253 
254  /* A sample:
255 
256  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  Now we are appending rsc2 and rsc3 which are tagged with tag1 right 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 
276  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
277  const char *obj_ref = (const char *) gIter->data;
278  xmlNode *new_rsc_ref = NULL;
279 
280  new_rsc_ref = xmlNewDocRawNode(getDocPtr(set), NULL,
282  crm_xml_add(new_rsc_ref, XML_ATTR_ID, obj_ref);
283  xmlAddNextSibling(last_ref, new_rsc_ref);
284 
285  last_ref = new_rsc_ref;
286  }
287 
288  any_refs = true;
289 
290  /* Freeing the resource_ref now would break the XML child
291  * iteration, so just remember it for freeing later.
292  */
293  tag_refs = g_list_append(tag_refs, xml_rsc);
294  }
295  }
296 
297  /* Now free '<resource_ref id="tag1"/>', and finally get:
298 
299  <resource_set id="tag1-colocation-0" sequential="true">
300  <resource_ref id="rsc1"/>
301  <resource_ref id="rsc2"/>
302  <resource_ref id="rsc3"/>
303  <resource_ref id="rsc4"/>
304  </resource_set>
305 
306  */
307  for (gIter = tag_refs; gIter != NULL; gIter = gIter->next) {
308  xmlNode *tag_ref = gIter->data;
309 
310  free_xml(tag_ref);
311  }
312  g_list_free(tag_refs);
313  }
314 
315  if (!any_refs) {
316  free_xml(new_xml);
317  new_xml = NULL;
318  }
319  return new_xml;
320 }
321 
332 bool
333 pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr,
334  bool convert_rsc, const pe_working_set_t *data_set)
335 {
336  const char *cons_id = NULL;
337  const char *id = NULL;
338 
339  pe_resource_t *rsc = NULL;
340  pe_tag_t *tag = NULL;
341 
342  *rsc_set = NULL;
343 
344  CRM_CHECK((xml_obj != NULL) && (attr != NULL), return false);
345 
346  cons_id = ID(xml_obj);
347  if (cons_id == NULL) {
348  pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
349  crm_element_name(xml_obj));
350  return false;
351  }
352 
353  id = crm_element_value(xml_obj, attr);
354  if (id == NULL) {
355  return true;
356  }
357 
358  if (!pcmk__valid_resource_or_tag(data_set, id, &rsc, &tag)) {
359  pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
360  "valid resource or tag", cons_id, id);
361  return false;
362 
363  } else if (tag) {
364  GList *gIter = NULL;
365 
366  /* A template/tag is referenced by the "attr" attribute (first, then, rsc or with-rsc).
367  Add the template/tag's corresponding "resource_set" which contains the resources derived
368  from it or tagged with it under the constraint. */
369  *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
370  crm_xml_add(*rsc_set, XML_ATTR_ID, id);
371 
372  for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
373  const char *obj_ref = (const char *) gIter->data;
374  xmlNode *rsc_ref = NULL;
375 
376  rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
377  crm_xml_add(rsc_ref, XML_ATTR_ID, obj_ref);
378  }
379 
380  /* Set sequential="false" for the resource_set */
381  pcmk__xe_set_bool_attr(*rsc_set, "sequential", false);
382 
383  } else if ((rsc != NULL) && convert_rsc) {
384  /* Even a regular resource is referenced by "attr", convert it into a resource_set.
385  Because the other side of the constraint could be a template/tag reference. */
386  xmlNode *rsc_ref = NULL;
387 
388  *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
389  crm_xml_add(*rsc_set, XML_ATTR_ID, id);
390 
391  rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
392  crm_xml_add(rsc_ref, XML_ATTR_ID, id);
393 
394  } else {
395  return true;
396  }
397 
398  /* Remove the "attr" attribute referencing the template/tag */
399  if (*rsc_set != NULL) {
400  xml_remove_prop(xml_obj, attr);
401  }
402 
403  return true;
404 }
405 
412 void
414 {
415  crm_trace("Create internal constraints");
416  for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
417  pe_resource_t *rsc = (pe_resource_t *) iter->data;
418 
419  rsc->cmds->internal_constraints(rsc);
420  }
421 }
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:126
GHashTable * tags
Definition: pe_types.h:203
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
A dumping ground.
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition: iso8601.c:142
void(* internal_constraints)(pe_resource_t *rsc)
struct crm_time_s crm_time_t
Definition: iso8601.h:32
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition: utils.c:715
#define pcmk__config_warn(fmt...)
#define XML_CIB_TAG_CONSTRAINTS
Definition: msg_xml.h:202
resource_alloc_functions_t * cmds
Definition: pe_types.h:359
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2521
#define pcmk__config_err(fmt...)
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
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: nvpair.c:921
#define XML_CONS_TAG_RSC_DEPEND
Definition: msg_xml.h:363
#define XML_CONS_TAG_RSC_TICKET
Definition: msg_xml.h:366
#define XML_CONS_TAG_RSC_SET
Definition: msg_xml.h:367
void pcmk__create_internal_constraints(pe_working_set_t *data_set)
xmlDoc * getDocPtr(xmlNode *node)
Definition: xml.c:647
GList * resources
Definition: pe_types.h:181
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:819
#define crm_warn(fmt, args...)
Definition: logging.h:378
#define crm_debug(fmt, args...)
Definition: logging.h:382
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:922
#define XML_ATTR_ID
Definition: msg_xml.h:147
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
bool pcmk__valid_resource_or_tag(const pe_working_set_t *data_set, const char *id, pe_resource_t **rsc, pe_tag_t **tag)
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:153
#define XML_CONS_TAG_RSC_LOCATION
Definition: msg_xml.h:365
#define crm_trace(fmt, args...)
Definition: logging.h:383
pe_working_set_t * data_set
Wrappers for and extensions to libxml2.
ISO_8601 Date handling.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:677
#define XML_TAG_RESOURCE_REF
Definition: msg_xml.h:229
void pcmk__unpack_constraints(pe_working_set_t *data_set)
void free_xml(xmlNode *child)
Definition: xml.c:813
xmlNode * input
Definition: pe_types.h:160
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition: iso8601.c:359
const xmlChar * pcmkXmlStr
Definition: xml.h:50
GList * refs
Definition: pe_types.h:489
match resource ID or LRM history ID
Definition: pe_types.h:101
xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pe_working_set_t *data_set)
Cluster status and scheduling.
pcmk__action_result_t result
Definition: pcmk_fence.c:35
pe_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
Cluster Configuration.
G_GNUC_INTERNAL void pcmk__unpack_ordering(xmlNode *xml_obj, pe_working_set_t *data_set)
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:1735
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
#define XML_CONS_TAG_RSC_ORDER
Definition: msg_xml.h:364
G_GNUC_INTERNAL void pcmk__unpack_colocation(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)
G_GNUC_INTERNAL void pcmk__unpack_rsc_ticket(xmlNode *xml_obj, pe_working_set_t *data_set)
#define ID(x)
Definition: msg_xml.h:480
#define pe_err(fmt...)
Definition: internal.h:52
const char * parent
Definition: cib.c:25
bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, const pe_working_set_t *data_set)
crm_time_t * now
Definition: pe_types.h:161
#define crm_info(fmt, args...)
Definition: logging.h:380
GHashTable * template_rsc_sets
Definition: pe_types.h:201
char * id
Definition: pe_types.h:347
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2547
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150