pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
xml_internal.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #ifndef PCMK__XML_INTERNAL__H
11 #define PCMK__XML_INTERNAL__H
12 
13 /*
14  * Internal-only wrappers for and extensions to libxml2 (libxslt)
15  */
16 
17 #include <stdlib.h>
18 #include <stdint.h> // uint32_t
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include <crm/crm.h> /* transitively imports qblog.h */
25 #include <crm/common/xml_names_internal.h> // PCMK__XE_PROMOTABLE_LEGACY
26 
27 #include <libxml/relaxng.h>
28 
72 #define PCMK__XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap) \
73 do { \
74  if (!(dechunk) && (prefix) == NULL) { /* quick pass */ \
75  qb_log_from_external_source_va(__func__, __FILE__, (fmt), \
76  (priority), __LINE__, 0, (ap)); \
77  (void) (postemit); \
78  } else { \
79  int CXLB_len = 0; \
80  char *CXLB_buf = NULL; \
81  static int CXLB_buffer_len = 0; \
82  static char *CXLB_buffer = NULL; \
83  static uint8_t CXLB_priority = 0; \
84  \
85  CXLB_len = vasprintf(&CXLB_buf, (fmt), (ap)); \
86  \
87  if (CXLB_len <= 0 || CXLB_buf[CXLB_len - 1] == '\n' || !(dechunk)) { \
88  if (CXLB_len < 0) { \
89  CXLB_buf = (char *) "LOG CORRUPTION HAZARD"; /*we don't modify*/\
90  CXLB_priority = QB_MIN(CXLB_priority, LOG_ERR); \
91  } else if (CXLB_len > 0 /* && (dechunk) */ \
92  && CXLB_buf[CXLB_len - 1] == '\n') { \
93  CXLB_buf[CXLB_len - 1] = '\0'; \
94  } \
95  if (CXLB_buffer) { \
96  qb_log_from_external_source(__func__, __FILE__, "%s%s%s", \
97  CXLB_priority, __LINE__, 0, \
98  (prefix) != NULL ? (prefix) : "", \
99  CXLB_buffer, CXLB_buf); \
100  free(CXLB_buffer); \
101  } else { \
102  qb_log_from_external_source(__func__, __FILE__, "%s%s", \
103  (priority), __LINE__, 0, \
104  (prefix) != NULL ? (prefix) : "", \
105  CXLB_buf); \
106  } \
107  if (CXLB_len < 0) { \
108  CXLB_buf = NULL; /* restore temporary override */ \
109  } \
110  CXLB_buffer = NULL; \
111  CXLB_buffer_len = 0; \
112  (void) (postemit); \
113  \
114  } else if (CXLB_buffer == NULL) { \
115  CXLB_buffer_len = CXLB_len; \
116  CXLB_buffer = CXLB_buf; \
117  CXLB_buf = NULL; \
118  CXLB_priority = (priority); /* remember as a running severest */ \
119  \
120  } else { \
121  CXLB_buffer = realloc(CXLB_buffer, 1 + CXLB_buffer_len + CXLB_len); \
122  memcpy(CXLB_buffer + CXLB_buffer_len, CXLB_buf, CXLB_len); \
123  CXLB_buffer_len += CXLB_len; \
124  CXLB_buffer[CXLB_buffer_len] = '\0'; \
125  CXLB_priority = QB_MIN(CXLB_priority, (priority)); /* severest? */ \
126  } \
127  free(CXLB_buf); \
128  } \
129 } while (0)
130 
131 /*
132  * \enum pcmk__xml_fmt_options
133  * \brief Bit flags to control format in XML logs and dumps
134  */
138 
141 
143  pcmk__xml_fmt_open = (1 << 3),
144 
147 
150 
151  // @COMPAT Can we start including text nodes unconditionally?
153  pcmk__xml_fmt_text = (1 << 6),
154 
155  // @COMPAT Remove when v1 patchsets are removed
158 
159  // @COMPAT Remove when v1 patchsets are removed
162 
163  // @COMPAT Remove when v1 patchsets are removed
166 };
167 
168 int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data,
169  int depth, uint32_t options);
170 int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml);
171 
172 /* XML search strings for guest, remote and pacemaker_remote nodes */
173 
174 /* search string to find CIB resources entries for cluster nodes */
175 #define PCMK__XP_MEMBER_NODE_CONFIG \
176  "//" PCMK_XE_CIB "/" PCMK_XE_CONFIGURATION "/" PCMK_XE_NODES \
177  "/" PCMK_XE_NODE \
178  "[not(@" PCMK_XA_TYPE ") or @" PCMK_XA_TYPE "='" PCMK_VALUE_MEMBER "']"
179 
180 /* search string to find CIB resources entries for guest nodes */
181 #define PCMK__XP_GUEST_NODE_CONFIG \
182  "//" PCMK_XE_CIB "//" PCMK_XE_CONFIGURATION "//" PCMK_XE_PRIMITIVE \
183  "//" PCMK_XE_META_ATTRIBUTES "//" PCMK_XE_NVPAIR \
184  "[@" PCMK_XA_NAME "='" PCMK_META_REMOTE_NODE "']"
185 
186 /* search string to find CIB resources entries for remote nodes */
187 #define PCMK__XP_REMOTE_NODE_CONFIG \
188  "//" PCMK_XE_CIB "//" PCMK_XE_CONFIGURATION "//" PCMK_XE_PRIMITIVE \
189  "[@" PCMK_XA_TYPE "='" PCMK_VALUE_REMOTE "']" \
190  "[@" PCMK_XA_PROVIDER "='pacemaker']"
191 
192 /* search string to find CIB node status entries for pacemaker_remote nodes */
193 #define PCMK__XP_REMOTE_NODE_STATUS \
194  "//" PCMK_XE_CIB "//" PCMK_XE_STATUS "//" PCMK__XE_NODE_STATE \
195  "[@" PCMK_XA_REMOTE_NODE "='" PCMK_VALUE_TRUE "']"
196 
205 int pcmk__xml2fd(int fd, xmlNode *cur);
206 
212 };
213 
214 void pcmk__strip_xml_text(xmlNode *xml);
215 const char *pcmk__xe_add_last_written(xmlNode *xe);
216 
217 xmlNode *pcmk__xe_first_child(const xmlNode *parent, const char *node_name,
218  const char *attr_n, const char *attr_v);
219 
220 
221 void pcmk__xe_remove_attr(xmlNode *element, const char *name);
222 bool pcmk__xe_remove_attr_cb(xmlNode *xml, void *user_data);
223 void pcmk__xe_remove_matching_attrs(xmlNode *element,
224  bool (*match)(xmlAttrPtr, void *),
225  void *user_data);
226 int pcmk__xe_delete_match(xmlNode *xml, xmlNode *search);
227 int pcmk__xe_replace_match(xmlNode *xml, xmlNode *replace);
228 int pcmk__xe_update_match(xmlNode *xml, xmlNode *update, uint32_t flags);
229 
230 GString *pcmk__element_xpath(const xmlNode *xml);
231 
284 
292 
293  /* @COMPAT Drop escaping of at least '\n' and '\t' for
294  * pcmk__xml_escape_attr_pretty when openstack-info, openstack-floating-ip,
295  * and openstack-virtual-ip resource agents no longer depend on it.
296  *
297  * At time of writing, openstack-info may set a multiline value for the
298  * openstack_ports node attribute. The other two agents query the value and
299  * require it to be on one line with no spaces.
300  */
309 };
310 
311 bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type);
312 char *pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type);
313 
322 char *
324 
335  const char *filespec);
336 
345 static inline const char *
346 pcmk__xe_id(const xmlNode *xml)
347 {
348  return crm_element_value(xml, PCMK_XA_ID);
349 }
350 
360 static inline bool
361 pcmk__xe_is(const xmlNode *xml, const char *name)
362 {
363  return (xml != NULL) && (xml->name != NULL) && (name != NULL)
364  && (strcmp((const char *) xml->name, name) == 0);
365 }
366 
375 static inline xmlNode *
376 pcmk__xml_first_child(const xmlNode *parent)
377 {
378  xmlNode *child = (parent? parent->children : NULL);
379 
380  while (child && (child->type == XML_TEXT_NODE)) {
381  child = child->next;
382  }
383  return child;
384 }
385 
394 static inline xmlNode *
395 pcmk__xml_next(const xmlNode *child)
396 {
397  xmlNode *next = (child? child->next : NULL);
398 
399  while (next && (next->type == XML_TEXT_NODE)) {
400  next = next->next;
401  }
402  return next;
403 }
404 
413 static inline xmlNode *
414 pcmk__xe_next(const xmlNode *child)
415 {
416  xmlNode *next = child? child->next : NULL;
417 
418  while (next && (next->type != XML_ELEMENT_NODE)) {
419  next = next->next;
420  }
421  return next;
422 }
423 
424 xmlNode *pcmk__xe_create(xmlNode *parent, const char *name);
425 xmlNode *pcmk__xc_create(xmlDoc *doc, const char *content);
426 void pcmk__xml_free_doc(xmlDoc *doc);
427 xmlNode *pcmk__xml_copy(xmlNode *parent, xmlNode *src);
428 xmlNode *pcmk__xe_next_same(const xmlNode *node);
429 
430 void pcmk__xe_set_content(xmlNode *node, const char *format, ...)
431  G_GNUC_PRINTF(2, 3);
432 
441 
444 
450 };
451 
452 int pcmk__xe_get_score(const xmlNode *xml, const char *name, int *score,
453  int default_score);
454 
455 int pcmk__xe_copy_attrs(xmlNode *target, const xmlNode *src, uint32_t flags);
456 
465 void
466 pcmk__xe_set_propv(xmlNodePtr node, va_list pairs);
467 
478 void
479 pcmk__xe_set_props(xmlNodePtr node, ...)
480 G_GNUC_NULL_TERMINATED;
481 
490 static inline xmlAttr *
491 pcmk__xe_first_attr(const xmlNode *xe)
492 {
493  return (xe == NULL)? NULL : xe->properties;
494 }
495 
505 char *
506 pcmk__xpath_node_id(const char *xpath, const char *node);
507 
518 void
520  const char *name);
521 
522 /* internal XML-related utilities */
523 
525  pcmk__xf_none = 0x0000,
526  pcmk__xf_dirty = 0x0001,
530 
533  pcmk__xf_skip = 0x0040,
534  pcmk__xf_moved = 0x0080,
535 
540 
543  pcmk__xf_lazy = 0x4000,
544 };
545 
546 void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag);
547 
568 int
569 pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name,
570  int (*handler)(xmlNode *xml, void *userdata),
571  void *userdata);
572 
573 bool pcmk__xml_tree_foreach(xmlNode *xml, bool (*fn)(xmlNode *, void *),
574  void *user_data);
575 
576 static inline const char *
577 pcmk__xml_attr_value(const xmlAttr *attr)
578 {
579  return ((attr == NULL) || (attr->children == NULL))? NULL
580  : (const char *) attr->children->content;
581 }
582 
583 // @COMPAT Remove when v1 patchsets are removed
584 xmlNode *pcmk__diff_v1_xml_object(xmlNode *left, xmlNode *right, bool suppress);
585 
586 // @COMPAT Drop when PCMK__XE_PROMOTABLE_LEGACY is removed
587 static inline const char *
588 pcmk__map_element_name(const xmlNode *xml)
589 {
590  if (xml == NULL) {
591  return NULL;
592  } else if (pcmk__xe_is(xml, PCMK__XE_PROMOTABLE_LEGACY)) {
593  return PCMK_XE_CLONE;
594  } else {
595  return (const char *) xml->name;
596  }
597 }
598 
599 #endif // PCMK__XML_INTERNAL__H
char * pcmk__xml_artefact_root(enum pcmk__xml_artefact_ns ns)
Definition: xml.c:2202
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:974
A dumping ground.
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1199
char data[0]
Definition: cpg.c:58
int pcmk__xe_copy_attrs(xmlNode *target, const xmlNode *src, uint32_t flags)
Definition: xml.c:669
const char * name
Definition: cib.c:26
xmlNode * pcmk__diff_v1_xml_object(xmlNode *left, xmlNode *right, bool suppress)
Definition: patchset.c:1435
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition: xml.c:1048
int pcmk__xe_replace_match(xmlNode *xml, xmlNode *replace)
Definition: xml.c:1974
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1117
Exclude certain XML attributes (for calculating digests)
Definition: xml_internal.h:137
Include the opening tag of an XML element, and include XML comments.
Definition: xml_internal.h:143
void pcmk__xe_set_propv(xmlNodePtr node, va_list pairs)
Definition: xml.c:2279
pcmk__xa_flags
Definition: xml_internal.h:438
enum crm_ais_msg_types type
Definition: cpg.c:51
void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag)
Definition: xml.c:94
char * pcmk__xpath_node_id(const char *xpath, const char *node)
Definition: xpath.c:290
Include indentation and newlines.
Definition: xml_internal.h:140
Log a created XML subtree.
Definition: xml_internal.h:157
void pcmk__xe_set_content(xmlNode *node, const char *format,...) G_GNUC_PRINTF(2
int pcmk__xe_delete_match(xmlNode *xml, xmlNode *search)
Definition: xml.c:1859
#define PCMK_XE_CLONE
Definition: xml_names.h:80
Formatted output for pacemaker tools.
void pcmk__strip_xml_text(xmlNode *xml)
Definition: xml.c:1012
xmlNode * pcmk__xc_create(xmlDoc *doc, const char *content)
Definition: xml_comment.c:28
pcmk__xml_escape_type
Definition: xml_internal.h:276
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:458
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:481
Include the children of an XML element.
Definition: xml_internal.h:146
void pcmk__xe_remove_matching_attrs(xmlNode *element, bool(*match)(xmlAttrPtr, void *), void *user_data)
Definition: xml.c:742
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
Definition: xml.c:702
bool pcmk__xe_remove_attr_cb(xmlNode *xml, void *user_data)
Definition: xml.c:724
Flag has no effect.
Definition: xml_internal.h:440
#define PCMK_XA_ID
Definition: xml_names.h:301
int pcmk__xe_update_match(xmlNode *xml, xmlNode *update, uint32_t flags)
Definition: xml.c:2068
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml.c:2297
xml_private_flags
Definition: xml_internal.h:524
const char * target
Definition: pcmk_fence.c:29
pcmk__xml_artefact_ns
Definition: xml_internal.h:207
Log a removed XML subtree.
Definition: xml_internal.h:161
int pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name, int(*handler)(xmlNode *xml, void *userdata), void *userdata)
Definition: xml.c:2306
int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data, int depth, uint32_t options)
Definition: xml_display.c:229
Include the closing tag of an XML element.
Definition: xml_internal.h:149
int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml)
Definition: xml_display.c:370
int pcmk__xe_get_score(const xmlNode *xml, const char *name, int *score, int default_score)
Definition: xml.c:549
This structure contains everything that makes up a single output formatter.
Include XML text nodes.
Definition: xml_internal.h:153
void pcmk__xml_free_doc(xmlDoc *doc)
Definition: xml.c:819
bool pcmk__xml_tree_foreach(xmlNode *xml, bool(*fn)(xmlNode *, void *), void *user_data)
Definition: xml.c:45
Log a minimal version of an XML diff (only showing the changes)
Definition: xml_internal.h:165
GString * pcmk__element_xpath(const xmlNode *xml)
Definition: xpath.c:256
void pcmk__warn_multiple_name_matches(pcmk__output_t *out, xmlNode *search, const char *name)
Definition: xpath.c:332
int pcmk__xml2fd(int fd, xmlNode *cur)
Definition: xml_io.c:715
const char * parent
Definition: cib.c:27
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:770
char * pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns, const char *filespec)
Definition: xml.c:2259
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition: xml.c:2130
#define PCMK__XE_PROMOTABLE_LEGACY
uint64_t flags
Definition: remote.c:215
pcmk__xml_fmt_options
Definition: xml_internal.h:135
Don&#39;t overwrite existing values.
Definition: xml_internal.h:443