pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
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) \
73do { \
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
144
147
150
151 // @COMPAT Can we start including text nodes unconditionally?
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
168int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data,
169 int depth, uint32_t options);
170int 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 "']"
205int pcmk__xml2fd(int fd, xmlNode *cur);
206
213
214void pcmk__strip_xml_text(xmlNode *xml);
215const char *pcmk__xe_add_last_written(xmlNode *xe);
216
217xmlNode *pcmk__xe_first_child(const xmlNode *parent, const char *node_name,
218 const char *attr_n, const char *attr_v);
219
220
221void pcmk__xe_remove_attr(xmlNode *element, const char *name);
222bool pcmk__xe_remove_attr_cb(xmlNode *xml, void *user_data);
223void pcmk__xe_remove_matching_attrs(xmlNode *element,
224 bool (*match)(xmlAttrPtr, void *),
225 void *user_data);
226int pcmk__xe_delete_match(xmlNode *xml, xmlNode *search);
227int pcmk__xe_replace_match(xmlNode *xml, xmlNode *replace);
228int pcmk__xe_update_match(xmlNode *xml, xmlNode *update, uint32_t flags);
229
230GString *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
311bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type);
312char *pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type);
313
322char *
324
335 const char *filespec);
336
345static inline const char *
346pcmk__xe_id(const xmlNode *xml)
347{
348 return crm_element_value(xml, PCMK_XA_ID);
349}
350
360static inline bool
361pcmk__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
375static inline xmlNode *
376pcmk__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
394static inline xmlNode *
395pcmk__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
413static inline xmlNode *
414pcmk__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
424xmlNode *pcmk__xe_create(xmlNode *parent, const char *name);
425xmlNode *pcmk__xml_copy(xmlNode *parent, xmlNode *src);
426xmlNode *pcmk__xe_next_same(const xmlNode *node);
427
428void pcmk__xe_set_content(xmlNode *node, const char *format, ...)
429 G_GNUC_PRINTF(2, 3);
430
449
450int pcmk__xe_copy_attrs(xmlNode *target, const xmlNode *src, uint32_t flags);
451
460void
461pcmk__xe_set_propv(xmlNodePtr node, va_list pairs);
462
473void
474pcmk__xe_set_props(xmlNodePtr node, ...)
475G_GNUC_NULL_TERMINATED;
476
485static inline xmlAttr *
486pcmk__xe_first_attr(const xmlNode *xe)
487{
488 return (xe == NULL)? NULL : xe->properties;
489}
490
500char *
501pcmk__xpath_node_id(const char *xpath, const char *node);
502
513void
515 const char *name);
516
517/* internal XML-related utilities */
518
540
541void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag);
542
563int
564pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name,
565 int (*handler)(xmlNode *xml, void *userdata),
566 void *userdata);
567
568bool pcmk__xml_tree_foreach(xmlNode *xml, bool (*fn)(xmlNode *, void *),
569 void *user_data);
570
571static inline const char *
572pcmk__xml_attr_value(const xmlAttr *attr)
573{
574 return ((attr == NULL) || (attr->children == NULL))? NULL
575 : (const char *) attr->children->content;
576}
577
578// @COMPAT Remove when v1 patchsets are removed
579xmlNode *pcmk__diff_v1_xml_object(xmlNode *left, xmlNode *right, bool suppress);
580
581// @COMPAT Drop when PCMK__XE_PROMOTABLE_LEGACY is removed
582static inline const char *
583pcmk__map_element_name(const xmlNode *xml)
584{
585 if (xml == NULL) {
586 return NULL;
587 } else if (pcmk__xe_is(xml, PCMK__XE_PROMOTABLE_LEGACY)) {
588 return PCMK_XE_CLONE;
589 } else {
590 return (const char *) xml->name;
591 }
592}
593
594#endif // PCMK__XML_INTERNAL__H
const char * parent
Definition cib.c:27
const char * name
Definition cib.c:26
uint64_t flags
Definition remote.c:3
enum crm_ais_msg_types type
Definition cpg.c:3
char data[0]
Definition cpg.c:10
A dumping ground.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
Formatted output for pacemaker tools.
const char * target
Definition pcmk_fence.c:29
This structure contains everything that makes up a single output formatter.
pcmk__xml_fmt_options
@ pcmk__xml_fmt_close
Include the closing tag of an XML element.
@ pcmk__xml_fmt_diff_plus
Log a created XML subtree.
@ pcmk__xml_fmt_children
Include the children of an XML element.
@ pcmk__xml_fmt_open
Include the opening tag of an XML element, and include XML comments.
@ pcmk__xml_fmt_diff_minus
Log a removed XML subtree.
@ pcmk__xml_fmt_pretty
Include indentation and newlines.
@ pcmk__xml_fmt_filtered
Exclude certain XML attributes (for calculating digests)
@ pcmk__xml_fmt_text
Include XML text nodes.
@ pcmk__xml_fmt_diff_short
Log a minimal version of an XML diff (only showing the changes)
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
int pcmk__xe_update_match(xmlNode *xml, xmlNode *update, uint32_t flags)
Definition xml.c:2046
void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag)
Definition xml.c:89
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
pcmk__xa_flags
@ pcmk__xaf_none
Flag has no effect.
@ pcmk__xaf_no_overwrite
Don't overwrite existing values.
@ pcmk__xaf_score_update
void pcmk__xe_remove_matching_attrs(xmlNode *element, bool(*match)(xmlAttrPtr, void *), void *user_data)
Definition xml.c:692
char * pcmk__xml_artefact_root(enum pcmk__xml_artefact_ns ns)
Definition xml.c:2184
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition xml.c:1028
int pcmk__xe_copy_attrs(xmlNode *target, const xmlNode *src, uint32_t flags)
Definition xml.c:584
bool pcmk__xe_remove_attr_cb(xmlNode *xml, void *user_data)
Definition xml.c:674
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition xml.c:959
int pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name, int(*handler)(xmlNode *xml, void *userdata), void *userdata)
Definition xml.c:2288
bool pcmk__xml_tree_foreach(xmlNode *xml, bool(*fn)(xmlNode *, void *), void *user_data)
Definition xml.c:42
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
xml_private_flags
@ pcmk__xf_acl_create
@ pcmk__xf_deleted
@ pcmk__xf_acl_enabled
@ pcmk__xf_created
@ pcmk__xf_acl_denied
@ pcmk__xf_dirty
@ pcmk__xf_modified
@ pcmk__xf_acl_deny
@ pcmk__xf_skip
@ pcmk__xf_acl_write
@ pcmk__xf_lazy
@ pcmk__xf_tracking
@ pcmk__xf_none
@ pcmk__xf_processed
@ pcmk__xf_moved
@ pcmk__xf_acl_read
void pcmk__strip_xml_text(xmlNode *xml)
Definition xml.c:923
void pcmk__xe_set_propv(xmlNodePtr node, va_list pairs)
Definition xml.c:2261
int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml)
void pcmk__warn_multiple_name_matches(pcmk__output_t *out, xmlNode *search, const char *name)
Definition xpath.c:332
GString * pcmk__element_xpath(const xmlNode *xml)
Definition xpath.c:256
pcmk__xml_escape_type
@ pcmk__xml_escape_attr_pretty
@ pcmk__xml_escape_attr
@ pcmk__xml_escape_text
int pcmk__xml2fd(int fd, xmlNode *cur)
Definition xml_io.c:713
int pcmk__xe_delete_match(xmlNode *xml, xmlNode *search)
Definition xml.c:1839
int pcmk__xe_replace_match(xmlNode *xml, xmlNode *replace)
Definition xml.c:1952
void pcmk__xe_set_content(xmlNode *node, const char *format,...) G_GNUC_PRINTF(2
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition xml.c:1110
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition xml.c:2279
xmlNode * pcmk__diff_v1_xml_object(xmlNode *left, xmlNode *right, bool suppress)
Definition patchset.c:1447
int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data, int depth, uint32_t options)
pcmk__xml_artefact_ns
@ pcmk__xml_artefact_ns_legacy_xslt
@ pcmk__xml_artefact_ns_legacy_rng
@ pcmk__xml_artefact_ns_base_rng
@ pcmk__xml_artefact_ns_base_xslt
char * pcmk__xpath_node_id(const char *xpath, const char *node)
Definition xpath.c:290
char * pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns, const char *filespec)
Definition xml.c:2241
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XE_CLONE
Definition xml_names.h:80
#define PCMK__XE_PROMOTABLE_LEGACY